26
26
27
27
# python package version
28
28
# should match r"^__version__ = '(?P<version>[^']+)'$" for setup.py
29
- __version__ = '0.5.14 '
29
+ __version__ = '0.5.15 '
30
30
31
31
32
32
log = logging .getLogger (__name__ )
@@ -300,17 +300,24 @@ def init(self, box_name=None, box_url=None):
300
300
self ._call_vagrant_command (['init' , box_name , box_url ])
301
301
302
302
def up (self , no_provision = False , provider = None , vm_name = None ,
303
- provision = None , provision_with = None ):
303
+ provision = None , provision_with = None , stream_output = False ):
304
304
'''
305
- Launch the Vagrant box.
305
+ Invoke `vagrant up` to start a box or boxes, possibly streaming the
306
+ command output.
306
307
vm_name=None: name of VM.
307
308
provision_with: optional list of provisioners to enable.
308
309
provider: Back the machine with a specific provider
309
310
no_provision: if True, disable provisioning. Same as 'provision=False'.
310
311
provision: optional boolean. Enable or disable provisioning. Default
311
312
behavior is to use the underlying vagrant default.
313
+ stream_output: if True, return a generator that yields each line of the
314
+ output of running the command. Consume the generator or the
315
+ subprocess might hang. if False, None is returned and the command
316
+ is run to completion without streaming the output. Defaults to
317
+ False.
312
318
Note: If provision and no_provision are not None, no_provision will be
313
319
ignored.
320
+ returns: None or a generator yielding lines of output.
314
321
'''
315
322
provider_arg = '--provider=%s' % provider if provider else None
316
323
prov_with_arg = None if provision_with is None else '--provision-with'
@@ -323,15 +330,14 @@ def up(self, no_provision=False, provider=None, vm_name=None,
323
330
no_provision_arg = '--no-provision' if no_provision else None
324
331
provision_arg = None if provision is None else '--provision' if provision else '--no-provision'
325
332
326
- self ._call_vagrant_command (['up' , vm_name , no_provision_arg ,
327
- provision_arg , provider_arg ,
328
- prov_with_arg , providers_arg ])
329
- try :
330
- self .conf (vm_name = vm_name ) # cache configuration
331
- except subprocess .CalledProcessError :
332
- # in multi-VM environments, up() can be used to start all VMs,
333
- # however vm_name is required for conf() or ssh_config().
334
- pass
333
+ args = ['up' , vm_name , no_provision_arg , provision_arg , provider_arg , prov_with_arg , providers_arg ]
334
+ if stream_output :
335
+ generator = self ._stream_vagrant_command (args )
336
+ else :
337
+ self ._call_vagrant_command (args )
338
+
339
+ self ._cached_conf [vm_name ] = None # remove cached configuration
340
+ return generator if stream_output else None
335
341
336
342
def provision (self , vm_name = None , provision_with = None ):
337
343
'''
@@ -345,25 +351,40 @@ def provision(self, vm_name=None, provision_with=None):
345
351
self ._call_vagrant_command (['provision' , vm_name , prov_with_arg ,
346
352
providers_arg ])
347
353
348
- def reload (self , vm_name = None , provision = None , provision_with = None ):
354
+ def reload (self , vm_name = None , provision = None , provision_with = None ,
355
+ stream_output = False ):
349
356
'''
350
357
Quoting from Vagrant docs:
351
358
> The equivalent of running a halt followed by an up.
352
-
353
- > This command is usually required for changes made in the Vagrantfile to take effect. After making any modifications to the Vagrantfile, a reload should be called.
354
-
355
- > The configured provisioners will not run again, by default. You can force the provisioners to re-run by specifying the --provision flag.
359
+ > This command is usually required for changes made in the Vagrantfile
360
+ to take effect. After making any modifications to the Vagrantfile, a
361
+ reload should be called.
362
+ > The configured provisioners will not run again, by default. You can
363
+ force the provisioners to re-run by specifying the --provision flag.
356
364
357
365
provision: optional boolean. Enable or disable provisioning. Default
358
366
behavior is to use the underlying vagrant default.
359
367
provision_with: optional list of provisioners to enable.
360
368
e.g. ['shell', 'chef_solo']
369
+ stream_output: if True, return a generator that yields each line of the
370
+ output of running the command. Consume the generator or the
371
+ subprocess might hang. if False, None is returned and the command
372
+ is run to completion without streaming the output. Defaults to
373
+ False.
374
+ returns: None or a generator yielding lines of output.
361
375
'''
362
376
prov_with_arg = None if provision_with is None else '--provision-with'
363
377
providers_arg = None if provision_with is None else ',' .join (provision_with )
364
378
provision_arg = None if provision is None else '--provision' if provision else '--no-provision'
365
- self ._call_vagrant_command (['reload' , vm_name , provision_arg ,
366
- prov_with_arg , providers_arg ])
379
+
380
+ args = ['reload' , vm_name , provision_arg , prov_with_arg , providers_arg ]
381
+ if stream_output :
382
+ generator = self ._stream_vagrant_command (args )
383
+ else :
384
+ self ._call_vagrant_command (args )
385
+
386
+ self ._cached_conf [vm_name ] = None # remove cached configuration
387
+ return generator if stream_output else None
367
388
368
389
def suspend (self , vm_name = None ):
369
390
'''
@@ -954,6 +975,35 @@ def _run_vagrant_command(self, args):
954
975
return compat .decode (subprocess .check_output (command , cwd = self .root ,
955
976
env = self .env , stderr = err_fh ))
956
977
978
+ def _stream_vagrant_command (self , args ):
979
+ """
980
+ Execute a vagrant command, returning a generator of the output lines.
981
+ Caller should consume the entire generator to avoid the hanging the
982
+ subprocess.
983
+
984
+ :param args: Arguments for the Vagrant command.
985
+ :return: generator that yields each line of the command stdout.
986
+ :rtype: generator iterator
987
+ """
988
+ py3 = sys .version_info > (3 , 0 )
989
+
990
+ # Make subprocess command
991
+ command = self ._make_vagrant_command (args )
992
+ with self .err_cm () as err_fh :
993
+ sp_args = dict (args = command , cwd = self .root , env = self .env ,
994
+ stdout = subprocess .PIPE , stderr = err_fh , bufsize = 1 )
995
+
996
+ # Iterate over output lines.
997
+ # See http://stackoverflow.com/questions/2715847/python-read-streaming-input-from-subprocess-communicate#17698359
998
+ p = subprocess .Popen (** sp_args )
999
+ with p .stdout :
1000
+ for line in iter (p .stdout .readline , b'' ):
1001
+ yield compat .decode (line ) # if PY3 decode bytestrings
1002
+ p .wait ()
1003
+ # Raise CalledProcessError for consistency with _call_vagrant_command
1004
+ if p .returncode != 0 :
1005
+ raise subprocess .CalledProcessError (p .returncode , command )
1006
+
957
1007
958
1008
class SandboxVagrant (Vagrant ):
959
1009
'''
0 commit comments