@@ -61,6 +61,17 @@ def _lock_files():
6161 ls = [p for p in ls if os .path .isfile (p )]
6262 return ls
6363
64+ def _unlock_display (ndisplay ):
65+ lockf = os .path .join ('/tmp' , '.X%d-lock' % ndisplay )
66+ try :
67+ os .remove (lockf )
68+ except :
69+ return False
70+
71+ return True
72+
73+
74+
6475def _search_for_free_display ():
6576 ls = [int (x .split ('X' )[1 ].split ('-' )[0 ]) for x in _lock_files ()]
6677 min_display_num = 1000
@@ -946,6 +957,36 @@ def _check_version_requirements(self, trait_object, raise_exception=True):
946957 version , max_ver ))
947958 return unavailable_traits
948959
960+ def _run_wrapper (self , runtime ):
961+ sysdisplay = os .getenv ('DISPLAY' )
962+ if self ._redirect_x :
963+ try :
964+ from xvfbwrapper import Xvfb
965+ except ImportError :
966+ iflogger .error ('Xvfb wrapper could not be imported' )
967+ raise
968+
969+ vdisp = Xvfb (nolisten = 'tcp' )
970+ vdisp .start ()
971+ vdisp_num = vdisp .vdisplay_num
972+
973+ iflogger .info ('Redirecting X to :%d' % vdisp_num )
974+ runtime .environ ['DISPLAY' ] = ':%d' % vdisp_num
975+
976+ runtime = self ._run_interface (runtime )
977+
978+ if self ._redirect_x :
979+ if sysdisplay is None :
980+ os .unsetenv ('DISPLAY' )
981+ else :
982+ os .environ ['DISPLAY' ] = sysdisplay
983+
984+ iflogger .info ('Freeing X :%d' % vdisp_num )
985+ vdisp .stop ()
986+ _unlock_display (vdisp_num )
987+
988+ return runtime
989+
949990 def _run_interface (self , runtime ):
950991 """ Core function that executes interface
951992 """
@@ -982,14 +1023,7 @@ def run(self, **inputs):
9821023 hostname = getfqdn (),
9831024 version = self .version )
9841025 try :
985- if self ._redirect_x :
986- from xvfbwrapper import Xvfb
987- with Xvfb () as xvfb :
988- runtime = self ._run_interface (runtime )
989- else :
990- iflogger .warn ('Error redirecting X, trying without xvfb...' )
991- runtime = self ._run_interface (runtime )
992-
1026+ runtime = self ._run_wrapper (runtime )
9931027 outputs = self .aggregate_outputs (runtime )
9941028 runtime .endTime = dt .isoformat (dt .utcnow ())
9951029 timediff = parseutc (runtime .endTime ) - parseutc (runtime .startTime )
@@ -1097,6 +1131,25 @@ def version(self):
10971131 self .__class__ .__name__ )
10981132 return self ._version
10991133
1134+ def _exists_in_path (self , cmd , environ ):
1135+ '''
1136+ Based on a code snippet from
1137+ http://orip.org/2009/08/python-checking-if-executable-exists-in.html
1138+ '''
1139+
1140+ if 'PATH' in environ :
1141+ input_environ = environ .get ("PATH" )
1142+ else :
1143+ input_environ = os .environ .get ("PATH" , "" )
1144+ extensions = os .environ .get ("PATHEXT" , "" ).split (os .pathsep )
1145+ for directory in input_environ .split (os .pathsep ):
1146+ base = os .path .join (directory , cmd )
1147+ options = [base ] + [(base + ext ) for ext in extensions ]
1148+ for filename in options :
1149+ if os .path .exists (filename ):
1150+ return True , filename
1151+ return False , None
1152+
11001153
11011154class Stream (object ):
11021155 """Function to capture stdout and stderr streams with timestamps
@@ -1149,32 +1202,39 @@ def _read(self, drain):
11491202 self ._lastidx = len (self ._rows )
11501203
11511204
1152- def run_command (runtime , output = None , timeout = 0.01 ):
1205+ def run_command (runtime , output = None , timeout = 0.01 , redirect_x = False ):
11531206 """Run a command, read stdout and stderr, prefix with timestamp.
11541207
11551208 The returned runtime contains a merged stdout+stderr log with timestamps
11561209 """
11571210 PIPE = subprocess .PIPE
11581211
1212+ cmdline = runtime .cmdline
1213+ if redirect_x :
1214+ exist_xvfb , _ = self ._exists_in_path ('xvfb-run' , runtime .environ )
1215+ if not exist_val :
1216+ raise RuntimeError ('Xvfb was not found, X redirection aborted' )
1217+ cmdline = 'xvfb-run -a ' + cmdline
1218+
11591219 if output == 'file' :
11601220 errfile = os .path .join (runtime .cwd , 'stderr.nipype' )
11611221 outfile = os .path .join (runtime .cwd , 'stdout.nipype' )
11621222 stderr = open (errfile , 'wt' )
11631223 stdout = open (outfile , 'wt' )
11641224
1165- proc = subprocess .Popen (runtime . cmdline ,
1225+ proc = subprocess .Popen (cmdline ,
11661226 stdout = stdout ,
11671227 stderr = stderr ,
11681228 shell = True ,
11691229 cwd = runtime .cwd ,
11701230 env = runtime .environ )
11711231 else :
1172- proc = subprocess .Popen (runtime . cmdline ,
1173- stdout = PIPE ,
1174- stderr = PIPE ,
1175- shell = True ,
1176- cwd = runtime .cwd ,
1177- env = runtime .environ )
1232+ proc = subprocess .Popen (cmdline ,
1233+ stdout = PIPE ,
1234+ stderr = PIPE ,
1235+ shell = True ,
1236+ cwd = runtime .cwd ,
1237+ env = runtime .environ )
11781238 result = {}
11791239 errfile = os .path .join (runtime .cwd , 'stderr.nipype' )
11801240 outfile = os .path .join (runtime .cwd , 'stdout.nipype' )
@@ -1405,6 +1465,10 @@ def version_from_command(self, flag='-v'):
14051465 o , e = proc .communicate ()
14061466 return o
14071467
1468+ def _run_wrapper (self , runtime ):
1469+ runtime = self ._run_interface (runtime )
1470+ return runtime
1471+
14081472 def _run_interface (self , runtime , correct_return_codes = [0 ]):
14091473 """Execute command via subprocess
14101474
@@ -1432,32 +1496,14 @@ def _run_interface(self, runtime, correct_return_codes=[0]):
14321496 setattr (runtime , 'command_path' , cmd_path )
14331497 setattr (runtime , 'dependencies' , get_dependencies (executable_name ,
14341498 runtime .environ ))
1435- runtime = run_command (runtime , output = self .inputs .terminal_output )
1499+ runtime = run_command (runtime , output = self .inputs .terminal_output ,
1500+ redirect_x = self ._redirect_x )
14361501 if runtime .returncode is None or \
14371502 runtime .returncode not in correct_return_codes :
14381503 self .raise_exception (runtime )
14391504
14401505 return runtime
14411506
1442- def _exists_in_path (self , cmd , environ ):
1443- '''
1444- Based on a code snippet from
1445- http://orip.org/2009/08/python-checking-if-executable-exists-in.html
1446- '''
1447-
1448- if 'PATH' in environ :
1449- input_environ = environ .get ("PATH" )
1450- else :
1451- input_environ = os .environ .get ("PATH" , "" )
1452- extensions = os .environ .get ("PATHEXT" , "" ).split (os .pathsep )
1453- for directory in input_environ .split (os .pathsep ):
1454- base = os .path .join (directory , cmd )
1455- options = [base ] + [(base + ext ) for ext in extensions ]
1456- for filename in options :
1457- if os .path .exists (filename ):
1458- return True , filename
1459- return False , None
1460-
14611507 def _format_arg (self , name , trait_spec , value ):
14621508 """A helper function for _parse_inputs
14631509
0 commit comments