00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 """
00017 Standard utility functions.
00018
00019 Copyright (c) 2011 University of Pennsylvania. All rights reserved.
00020 See COPYING file or https://www.rad.upenn.edu/sbia/software/license.html.
00021
00022 Contact: SBIA Group <sbia-software at uphs.upenn.edu>
00023
00024 """
00025
00026
00027
00028
00029
00030 import sys
00031 import subprocess
00032 import shlex
00033 import re
00034
00035 from sbia.basis.executabletargetinfo import get_executable_path
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047 def print_version(name, copyright=None, license=None):
00048 """
00049 Print version information including copyright and license notices.
00050
00051 @param [in] name Name of executable. Should not be set programmatically
00052 to the first argument to the __main__ module.
00053 @param [in] copyright The copyright notice. If None, the official default
00054 copyright is used without year, which is not desired.
00055 If an empty string is given, no copyright notice is
00056 printed.
00057 @param [in] license Information regarding licensing. If None, the official
00058 software license of SBIA is used. If an empty string
00059 is given, no license information is printed.
00060
00061 """
00062
00063 sys.stdout.write(name + " (BASIS) version 1.2.3 (revision 2104)\n")
00064
00065 if not copyright:
00066 sys.stdout.write("Copyright (c) University of Pennsylvania. All rights reserved.\n")
00067 elif copyright != "":
00068 sys.stdout.write(copyright)
00069 sys.stdout.write('\n')
00070
00071 if not license:
00072 sys.stdout.write("See https://www.cbica.upenn.edu/sbia/software/license.html or COPYING file.\n")
00073 elif license != "":
00074 sys.stdout.write(license)
00075 sys.stdout.write('\n')
00076
00077
00078 def print_contact(contact=None):
00079 """
00080 Print contact information.
00081
00082 @param [in] contact Name of contact. If None, the default contact of SBIA
00083 is used, which is recommended.
00084
00085 """
00086 sys.stdout.write("Contact:\n ")
00087 if not contact:
00088 sys.stdout.write("SBIA Group <sbia-software at uphs.upenn.edu>")
00089 else:
00090 sys.stdout.write(contact)
00091 sys.stdout.write('\n')
00092
00093
00094
00095
00096
00097
00098 class SubprocessError(Exception):
00099 """Exception thrown when command execution failed."""
00100
00101 def __init__(self, msg):
00102 """Initialize exception, i.e., set message describing failure."""
00103 self._message = msg
00104
00105 def __str__(self):
00106 """Return string representation of exception message."""
00107 return self._message
00108
00109
00110 def execute_process(args, quiet=False, stdout=False, allow_fail=False, verbose=0, simulate=False):
00111 """
00112 Execute command as subprocess.
00113
00114 @param [in] args Command with arguments given either as single quoted
00115 string or array of command name and arguments.
00116 In the latter case, the array elements are converted
00117 to strings using the built-in str() function.
00118 Hence, any type which can be converted to a string
00119 can be used. The first argument must be the name
00120 or path of the executable of the command or the
00121 name of the corresponding build target.
00122 @param [in] quiet Turns off output of stdout of child process to
00123 stdout of parent process.
00124 @param [in] stdout Whether to return the command output.
00125 @param [in] allow_fail If true, does not raise an exception if return
00126 value is non-zero. Otherwise, a SubprocessError is
00127 raised by this function.
00128 @param [in] verbose Verbosity of output messages.
00129 Does not affect verbosity of executed command.
00130 @param [in] simulate Whether to simulate command execution only.
00131
00132 @return Exit code of executed command. If @p stdout is True, a tuple
00133 consisting of the exit code and command output is returned.
00134
00135 @throws SubprocessError If command execution failed. This exception is not
00136 raised if the command executed with non-zero exit
00137 code but @p allow_fail set to True.
00138
00139 """
00140
00141 if type(args) is list:
00142 args = [str(i) for i in args]
00143 elif type(args) is str:
00144 args = shlex.split(args)
00145 else:
00146 raise SubprocessError("execute_process(): Argument args must be either list or string")
00147 if len(args) == 0:
00148 raise SubprocessError("execute_process(): No command specified")
00149
00150 path = get_executable_path(args[0])
00151 if not path:
00152 raise SubprocessError(args[0] + ': Either unknown build target or command not found')
00153 args[0] = path
00154
00155 if verbose > 0:
00156 sys.stdout.write('$')
00157 re_whitespace = re.compile('\s');
00158 for arg in args:
00159 sys.stdout.write(' ')
00160 if re_whitespace.search(arg):
00161 sys.stdout.write('"' + arg + '"')
00162 else:
00163 sys.stdout.write(arg)
00164 if simulate:
00165 sys.stdout.write(" (simulated)")
00166 sys.stdout.write('\n')
00167
00168 status = 0
00169 output = ''
00170 if not simulate:
00171 try:
00172
00173 process = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
00174
00175 for line in process.stdout:
00176 if stdout:
00177 output = output + line
00178 if not quiet:
00179 print line.rstrip()
00180 sys.stdout.flush()
00181
00182 (out, err) = process.communicate()
00183
00184 for line in err: sys.stderr.write(line);
00185
00186 status = process.returncode
00187 except OSError, e:
00188 raise SubprocessError(args[0] + ': ' + str(e))
00189 except Exception, e:
00190 msg = "Exception while executing \"" + args[0] + "\"!\n"
00191 msg += "\tArguments: " + ' '.join(['"' + i + '"' for i in args[1:]]) + '\n'
00192 msg += '\t' + str(e)
00193 raise SubprocessError(msg)
00194
00195 if status != 0 and not allow_fail:
00196 raise SubprocessError("Command " + ' '.join(['"' + i + '"' for i in args[0:]]) + " failed")
00197
00198 if stdout:
00199 return (status, output)
00200 else:
00201 return status
00202
00203
00204
00205