@@ -53,25 +53,34 @@ def __init__(self, value):
53
53
def __str__ (self ):
54
54
return repr (self .value )
55
55
56
- def _lock_files ():
57
- tmpdir = '/tmp'
58
- pattern = '.X*-lock'
59
- names = fnmatch .filter (os .listdir (tmpdir ), pattern )
60
- ls = [os .path .join (tmpdir , child ) for child in names ]
61
- ls = [p for p in ls if os .path .isfile (p )]
62
- return ls
63
-
64
- def _search_for_free_display ():
65
- ls = [int (x .split ('X' )[1 ].split ('-' )[0 ]) for x in _lock_files ()]
66
- min_display_num = 1000
67
- if len (ls ):
68
- display_num = max (min_display_num , max (ls ) + 1 )
69
- else :
70
- display_num = min_display_num
71
- random .seed ()
72
- display_num += random .randint (0 , 100 )
73
- return display_num
74
56
57
+ def _unlock_display (ndisplay ):
58
+ lockf = os .path .join ('/tmp' , '.X%d-lock' % ndisplay )
59
+ try :
60
+ os .remove (lockf )
61
+ except :
62
+ return False
63
+
64
+ return True
65
+
66
+ def _exists_in_path (cmd , environ ):
67
+ '''
68
+ Based on a code snippet from
69
+ http://orip.org/2009/08/python-checking-if-executable-exists-in.html
70
+ '''
71
+
72
+ if 'PATH' in environ :
73
+ input_environ = environ .get ("PATH" )
74
+ else :
75
+ input_environ = os .environ .get ("PATH" , "" )
76
+ extensions = os .environ .get ("PATHEXT" , "" ).split (os .pathsep )
77
+ for directory in input_environ .split (os .pathsep ):
78
+ base = os .path .join (directory , cmd )
79
+ options = [base ] + [(base + ext ) for ext in extensions ]
80
+ for filename in options :
81
+ if os .path .exists (filename ):
82
+ return True , filename
83
+ return False , None
75
84
76
85
def load_template (name ):
77
86
"""Load a template from the script_templates directory
@@ -946,6 +955,36 @@ def _check_version_requirements(self, trait_object, raise_exception=True):
946
955
version , max_ver ))
947
956
return unavailable_traits
948
957
958
+ def _run_wrapper (self , runtime ):
959
+ sysdisplay = os .getenv ('DISPLAY' )
960
+ if self ._redirect_x :
961
+ try :
962
+ from xvfbwrapper import Xvfb
963
+ except ImportError :
964
+ iflogger .error ('Xvfb wrapper could not be imported' )
965
+ raise
966
+
967
+ vdisp = Xvfb (nolisten = 'tcp' )
968
+ vdisp .start ()
969
+ vdisp_num = vdisp .vdisplay_num
970
+
971
+ iflogger .info ('Redirecting X to :%d' % vdisp_num )
972
+ runtime .environ ['DISPLAY' ] = ':%d' % vdisp_num
973
+
974
+ runtime = self ._run_interface (runtime )
975
+
976
+ if self ._redirect_x :
977
+ if sysdisplay is None :
978
+ os .unsetenv ('DISPLAY' )
979
+ else :
980
+ os .environ ['DISPLAY' ] = sysdisplay
981
+
982
+ iflogger .info ('Freeing X :%d' % vdisp_num )
983
+ vdisp .stop ()
984
+ _unlock_display (vdisp_num )
985
+
986
+ return runtime
987
+
949
988
def _run_interface (self , runtime ):
950
989
""" Core function that executes interface
951
990
"""
@@ -982,34 +1021,7 @@ def run(self, **inputs):
982
1021
hostname = getfqdn (),
983
1022
version = self .version )
984
1023
try :
985
- if self ._redirect_x :
986
- exist_val , _ = self ._exists_in_path ('Xvfb' ,
987
- runtime .environ )
988
- if not exist_val :
989
- raise IOError ("Xvfb could not be found on host %s" %
990
- (runtime .hostname ))
991
- else :
992
- vdisplay_num = _search_for_free_display ()
993
- xvfb_cmd = ['Xvfb' , ':%d' % vdisplay_num ]
994
- xvfb_proc = subprocess .Popen (xvfb_cmd ,
995
- stdout = open (os .devnull ),
996
- stderr = open (os .devnull ))
997
- wait_step = 0.2
998
- wait_time = 0
999
- while xvfb_proc .poll () is not None :
1000
- if wait_time > config .get ('execution' , 'xvfb_max_wait' ):
1001
- raise Exception ('Error: Xvfb did not start' )
1002
- time .sleep (wait_step ) # give Xvfb time to start
1003
- wait_time += wait_step
1004
-
1005
- runtime .environ ['DISPLAY' ] = ':%s' % vdisplay_num
1006
-
1007
- runtime = self ._run_interface (runtime )
1008
-
1009
- if self ._redirect_x :
1010
- xvfb_proc .kill ()
1011
- xvfb_proc .wait ()
1012
-
1024
+ runtime = self ._run_wrapper (runtime )
1013
1025
outputs = self .aggregate_outputs (runtime )
1014
1026
runtime .endTime = dt .isoformat (dt .utcnow ())
1015
1027
timediff = parseutc (runtime .endTime ) - parseutc (runtime .startTime )
@@ -1169,32 +1181,39 @@ def _read(self, drain):
1169
1181
self ._lastidx = len (self ._rows )
1170
1182
1171
1183
1172
- def run_command (runtime , output = None , timeout = 0.01 ):
1184
+ def run_command (runtime , output = None , timeout = 0.01 , redirect_x = False ):
1173
1185
"""Run a command, read stdout and stderr, prefix with timestamp.
1174
1186
1175
1187
The returned runtime contains a merged stdout+stderr log with timestamps
1176
1188
"""
1177
1189
PIPE = subprocess .PIPE
1178
1190
1191
+ cmdline = runtime .cmdline
1192
+ if redirect_x :
1193
+ exist_xvfb , _ = _exists_in_path ('xvfb-run' , runtime .environ )
1194
+ if not exist_xvfb :
1195
+ raise RuntimeError ('Xvfb was not found, X redirection aborted' )
1196
+ cmdline = 'xvfb-run -a ' + cmdline
1197
+
1179
1198
if output == 'file' :
1180
1199
errfile = os .path .join (runtime .cwd , 'stderr.nipype' )
1181
1200
outfile = os .path .join (runtime .cwd , 'stdout.nipype' )
1182
1201
stderr = open (errfile , 'wt' )
1183
1202
stdout = open (outfile , 'wt' )
1184
1203
1185
- proc = subprocess .Popen (runtime . cmdline ,
1204
+ proc = subprocess .Popen (cmdline ,
1186
1205
stdout = stdout ,
1187
1206
stderr = stderr ,
1188
1207
shell = True ,
1189
1208
cwd = runtime .cwd ,
1190
1209
env = runtime .environ )
1191
1210
else :
1192
- proc = subprocess .Popen (runtime . cmdline ,
1193
- stdout = PIPE ,
1194
- stderr = PIPE ,
1195
- shell = True ,
1196
- cwd = runtime .cwd ,
1197
- env = runtime .environ )
1211
+ proc = subprocess .Popen (cmdline ,
1212
+ stdout = PIPE ,
1213
+ stderr = PIPE ,
1214
+ shell = True ,
1215
+ cwd = runtime .cwd ,
1216
+ env = runtime .environ )
1198
1217
result = {}
1199
1218
errfile = os .path .join (runtime .cwd , 'stderr.nipype' )
1200
1219
outfile = os .path .join (runtime .cwd , 'stdout.nipype' )
@@ -1412,7 +1431,7 @@ def _get_environ(self):
1412
1431
1413
1432
def version_from_command (self , flag = '-v' ):
1414
1433
cmdname = self .cmd .split ()[0 ]
1415
- if self . _exists_in_path (cmdname ):
1434
+ if _exists_in_path (cmdname ):
1416
1435
env = deepcopy (os .environ .data )
1417
1436
out_environ = self ._get_environ ()
1418
1437
env .update (out_environ )
@@ -1425,6 +1444,10 @@ def version_from_command(self, flag='-v'):
1425
1444
o , e = proc .communicate ()
1426
1445
return o
1427
1446
1447
+ def _run_wrapper (self , runtime ):
1448
+ runtime = self ._run_interface (runtime )
1449
+ return runtime
1450
+
1428
1451
def _run_interface (self , runtime , correct_return_codes = [0 ]):
1429
1452
"""Execute command via subprocess
1430
1453
@@ -1444,40 +1467,22 @@ def _run_interface(self, runtime, correct_return_codes=[0]):
1444
1467
out_environ = self ._get_environ ()
1445
1468
runtime .environ .update (out_environ )
1446
1469
executable_name = self .cmd .split ()[0 ]
1447
- exist_val , cmd_path = self . _exists_in_path (executable_name ,
1448
- runtime .environ )
1470
+ exist_val , cmd_path = _exists_in_path (executable_name ,
1471
+ runtime .environ )
1449
1472
if not exist_val :
1450
1473
raise IOError ("%s could not be found on host %s" %
1451
1474
(self .cmd .split ()[0 ], runtime .hostname ))
1452
1475
setattr (runtime , 'command_path' , cmd_path )
1453
1476
setattr (runtime , 'dependencies' , get_dependencies (executable_name ,
1454
1477
runtime .environ ))
1455
- runtime = run_command (runtime , output = self .inputs .terminal_output )
1478
+ runtime = run_command (runtime , output = self .inputs .terminal_output ,
1479
+ redirect_x = self ._redirect_x )
1456
1480
if runtime .returncode is None or \
1457
1481
runtime .returncode not in correct_return_codes :
1458
1482
self .raise_exception (runtime )
1459
1483
1460
1484
return runtime
1461
1485
1462
- def _exists_in_path (self , cmd , environ ):
1463
- '''
1464
- Based on a code snippet from
1465
- http://orip.org/2009/08/python-checking-if-executable-exists-in.html
1466
- '''
1467
-
1468
- if 'PATH' in environ :
1469
- input_environ = environ .get ("PATH" )
1470
- else :
1471
- input_environ = os .environ .get ("PATH" , "" )
1472
- extensions = os .environ .get ("PATHEXT" , "" ).split (os .pathsep )
1473
- for directory in input_environ .split (os .pathsep ):
1474
- base = os .path .join (directory , cmd )
1475
- options = [base ] + [(base + ext ) for ext in extensions ]
1476
- for filename in options :
1477
- if os .path .exists (filename ):
1478
- return True , filename
1479
- return False , None
1480
-
1481
1486
def _format_arg (self , name , trait_spec , value ):
1482
1487
"""A helper function for _parse_inputs
1483
1488
0 commit comments