utilities.cxx
Go to the documentation of this file.
00001 /** 00002 * @file utilities.cxx 00003 * @brief Main module of project-independent BASIS utilities. 00004 * 00005 * Copyright (c) 2011, 2012 University of Pennsylvania. All rights reserved.<br /> 00006 * See https://www.cbica.upenn.edu/sbia/software/license.html or COPYING file. 00007 * 00008 * Contact: SBIA Group <sbia-software at uphs.upenn.edu> 00009 */ 00010 00011 #include <basis/subprocess.h> 00012 #include <basis/utilities.h> 00013 00014 00015 // acceptable in .cxx file 00016 using namespace std; 00017 00018 00019 namespace basis { namespace util { 00020 00021 00022 // =========================================================================== 00023 // executable information 00024 // =========================================================================== 00025 00026 // --------------------------------------------------------------------------- 00027 void print_contact(const char* contact) 00028 { 00029 cout << "Contact:\n " << contact << endl; 00030 } 00031 00032 // --------------------------------------------------------------------------- 00033 void print_version(const char* name, const char* version, const char* project, 00034 const char* copyright, const char* license) 00035 { 00036 assert(name != NULL); 00037 assert(version != NULL); 00038 cout << name; 00039 if (project && *project) cout << " (" << project << ")"; 00040 cout << " " << version << endl; 00041 if (copyright && *copyright) cout << "Copyright (c) " << copyright << ". All rights reserved." << endl; 00042 if (license && *license) cout << license << endl; 00043 } 00044 00045 // --------------------------------------------------------------------------- 00046 string targetuid(const string& name, const IExecutableTargetInfo* targets) 00047 { 00048 return targets != NULL ? targets->targetuid(name) : ""; 00049 } 00050 00051 // --------------------------------------------------------------------------- 00052 bool istarget(const string& name, const IExecutableTargetInfo* targets) 00053 { 00054 return targets != NULL && targets->istarget(name); 00055 } 00056 00057 // --------------------------------------------------------------------------- 00058 string exepath(const string& name, const IExecutableTargetInfo* targets) 00059 { 00060 // return path of this executable if no name given 00061 if (name.empty()) return os::exepath(); 00062 // get name of executable and check if target name is known 00063 string exec_name = targets != NULL ? targets->basename(name) : ""; 00064 // if target is not known 00065 if (exec_name.empty()) { 00066 // return input argument assuming that it is already the path of 00067 // an executable file 00068 exec_name = name; 00069 // try to get absolute path using the which command if path is relative 00070 // TODO Replace use of external which command by C++ implementation 00071 // of which() even though BASIS includes a Python implementation 00072 // that can also be used on Windows. Still, a native C++ 00073 // implementation is desireable. 00074 if (!os::path::isabs(exec_name) && targets->istarget("basis.which")) { 00075 vector<string> which(2); 00076 which[0] = "basis.which"; 00077 which[1] = name; 00078 ostringstream oss; 00079 // attention: this includes a "recursive" call of this function! 00080 if (execute(which, true, &oss, true, 0, false, targets) == 0) { 00081 exec_name = oss.str(); 00082 const string::size_type end = exec_name.find_last_not_of(" \t\n\r"); 00083 if (end == string::npos) { 00084 exec_name = ""; 00085 } else { 00086 exec_name.erase(end + 1); 00087 } 00088 } 00089 } 00090 return exec_name; 00091 } 00092 return os::path::join(targets->dirname(name), exec_name); 00093 } 00094 00095 // --------------------------------------------------------------------------- 00096 string exename(const std::string& name, const IExecutableTargetInfo* targets) 00097 { 00098 string exec_path = exepath(name, targets); 00099 if (exec_path.empty()) return ""; 00100 #if WINDOWS 00101 string fname, ext; 00102 os::path::splitext(exec_path, fname, ext); 00103 if (ext == ".exe" || ext == ".com") exec_path = fname; 00104 #endif 00105 return os::path::basename(exec_path); 00106 } 00107 00108 // --------------------------------------------------------------------------- 00109 string exedir(const std::string& name, const IExecutableTargetInfo* targets) 00110 { 00111 string exec_path = exepath(name, targets); 00112 return exec_path.empty() ? "" : os::path::dirname(exec_path); 00113 } 00114 00115 // =========================================================================== 00116 // command execution 00117 // =========================================================================== 00118 00119 // --------------------------------------------------------------------------- 00120 string tostring(const vector<string>& args) 00121 { 00122 return Subprocess::tostring(args); 00123 } 00124 00125 // --------------------------------------------------------------------------- 00126 vector<string> qsplit(const string& args) 00127 { 00128 return Subprocess::split(args); 00129 } 00130 00131 // --------------------------------------------------------------------------- 00132 int execute(const string& cmd, bool quiet, ostream* out, 00133 bool allow_fail, int verbose, bool simulate, 00134 const IExecutableTargetInfo* targets) 00135 { 00136 vector<string> args = Subprocess::split(cmd); 00137 return execute(args, quiet, out, allow_fail, verbose, simulate, targets); 00138 } 00139 00140 // --------------------------------------------------------------------------- 00141 int execute(vector<string> args, bool quiet, ostream* out, 00142 bool allow_fail, int verbose, bool simulate, 00143 const IExecutableTargetInfo* targets) 00144 { 00145 if (args.empty() || args[0].empty()) { 00146 BASIS_THROW(SubprocessError, "execute_process(): No command specified"); 00147 } 00148 // map build target name to executable file path 00149 string exec_path = exepath(args[0], targets); 00150 // prepend absolute path of found executable 00151 if (!exec_path.empty()) args[0] = exec_path; 00152 // some verbose output 00153 if (verbose > 0 || simulate) { 00154 cout << "$ " << Subprocess::tostring(args); 00155 if (simulate) cout << " (simulated)"; 00156 cout << endl; 00157 } 00158 // execute command 00159 char buf[1024]; 00160 int n; 00161 int status = 0; 00162 Subprocess p; 00163 if (!p.popen(args, Subprocess::RM_NONE, Subprocess::RM_PIPE, Subprocess::RM_PIPE)) { 00164 BASIS_THROW(SubprocessError, "execute_process(): Failed to create subprocess"); 00165 } 00166 // read child's stdout (blocking) 00167 if (!quiet || out != NULL) { 00168 while ((n = p.read(buf, 1023)) > 0) { 00169 buf[n] = '\0'; 00170 if (!quiet) { 00171 cout << buf; 00172 cout.flush(); 00173 } 00174 if (out) *out << buf; 00175 } 00176 } 00177 // wait for child process 00178 if (!p.wait()) { 00179 BASIS_THROW(SubprocessError, "execute_process(): Failed to wait for subprocess"); 00180 } 00181 // write error messages to stderr of parent process 00182 while ((n = p.read(buf, 1023, true)) > 0) { 00183 buf[n] = '\0'; 00184 cerr << buf; 00185 } 00186 // get exit code 00187 status = p.returncode(); 00188 // if command failed, throw an exception 00189 if (status != 0 && !allow_fail) { 00190 BASIS_THROW(SubprocessError, "Command " << Subprocess::tostring(args) << " failed"); 00191 } 00192 return status; 00193 } 00194 00195 00196 } } // end of namespaces