BASIS  r3148
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