44import bugzoo .errors
55import bugzoo .version
66
7- from typing import List
7+ from typing import List , Optional , Dict
88from operator import itemgetter
99from bugzoo .manager import BugZoo
10+ from bugzoo .tool import Tool
1011
1112
1213def error (msg : str ) -> None :
@@ -213,16 +214,13 @@ def list_tools(rbox: 'BugZoo', show_installed=None) -> None:
213214# [container] group
214215###############################################################################
215216
216- def launch (rbox : 'BugZoo' ,
217- name : str ,
218- tools : List [str ] = None ,
219- volumes : List [str ] = None
220- ) -> None :
221- if not tools :
222- tools = []
223-
217+ def __prepare_volumes (volumes : List [str ] = None ) -> Dict [str , Dict [str , str ]]:
218+ """
219+ Produces a volume-mapping dictionary, ready for use with Docker's Python
220+ API, from a list of volume commands.
221+ """
224222 if not volumes :
225- volumes = []
223+ return {}
226224
227225 # transform the list of volumes into a dictionary
228226 volume_map = {}
@@ -237,17 +235,47 @@ def launch(rbox: 'BugZoo',
237235 'mode' : mode
238236 }
239237
240- bug = rbox .bugs [name ]
238+ return volume_map
239+
240+
241+ def __prepare_tools (bz : 'BugZoo' , tools : List [str ] = None ) -> List [Tool ]:
242+ """
243+ Fetches the corresponding tool objects for a list of tools given by
244+ their names.
245+ """
246+ if not tools :
247+ return []
248+ return [bz .tools [t ] for t in tools ]
249+
250+
251+ def launch (bz : 'BugZoo' ,
252+ name : str ,
253+ interactive : bool ,
254+ tools : Optional [List [str ]] = None ,
255+ volumes : Optional [List [str ]] = None ,
256+ command : Optional [str ] = None ,
257+ ) -> None :
258+ volumes = __prepare_volumes (volumes )
259+ tools = __prepare_tools (bz , tools )
260+ bug = bz .bugs [name ]
241261 bug .install ()
242- tools = [ rbox . tools [ t ] for t in tools ]
262+
243263 try :
244264 c = None
245265 c = bug .provision (tty = True ,
246266 tools = tools ,
247- volumes = volume_map )
248- c .interact ()
267+ volumes = volumes )
268+ if command is not None :
269+ stream = c .command (command , stderr = True , stdout = True , block = False )
270+ for s in stream .output :
271+ print (s .decode ('utf8' ).strip ())
272+
273+ if interactive :
274+ c .interact ()
275+
276+ # ensure that the container is always destroyed
249277 finally :
250- if c : # ensure the container is destroyed
278+ if c :
251279 c .destroy ()
252280
253281
@@ -306,28 +334,28 @@ def build_parser():
306334 action = 'store_true' )
307335 cmd .set_defaults (func = lambda args : install_tool (rbox , args .tool , args .update ))
308336
309- # [tool uninstall (--force) :tool]
337+ # [tool uninstall (-f|- -force) :tool]
310338 cmd = g_subparsers .add_parser ('uninstall' )
311339 cmd .add_argument ('tool' )
312340 cmd .add_argument ('-f' , '--force' ,
313341 action = 'store_true' )
314342 cmd .set_defaults (func = lambda args : uninstall_tool (rbox , args .tool , force = args .force ))
315343
316- # [tool build (--update ) :bug ]
344+ # [tool build (-f|--force ) :tool ]
317345 cmd = g_subparsers .add_parser ('build' )
318346 cmd .add_argument ('tool' )
319347 cmd .add_argument ('-f' , '--force' ,
320348 action = 'store_true' )
321349 cmd .set_defaults (func = lambda args : build_tool (rbox , args .tool , args .force ))
322350
323- # [tool download (-- force) :bug ]
351+ # [tool download (-f|-- force) :tool ]
324352 cmd = g_subparsers .add_parser ('download' )
325353 cmd .add_argument ('tool' )
326354 cmd .add_argument ('-f' , '--force' ,
327355 action = 'store_true' )
328356 cmd .set_defaults (func = lambda args : download_tool (rbox , args .tool , args .force ))
329357
330- # [tool upload :bug ]
358+ # [tool upload :tool ]
331359 cmd = g_subparsers .add_parser ('upload' )
332360 cmd .add_argument ('tool' )
333361 cmd .set_defaults (func = lambda args : upload_tool (rbox , args .tool ))
@@ -350,7 +378,7 @@ def build_parser():
350378 g_dataset = subparsers .add_parser ('dataset' )
351379 g_subparsers = g_dataset .add_subparsers ()
352380
353- # [datasetlaunch :bug ]
381+ # [dataset list ]
354382 cmd = g_subparsers .add_parser ('list' )
355383 cmd .set_defaults (func = lambda args : list_datasets (rbox ))
356384
@@ -374,9 +402,32 @@ def build_parser():
374402 dest = 'volumes' ,
375403 action = 'append' ,
376404 default = [])
377- cmd .set_defaults (func = lambda args : launch (rbox , args .bug , args .tools , args .volumes ))
378-
379- # [container run :bug]
405+ cmd .set_defaults (func = lambda args : launch (rbox ,
406+ args .bug ,
407+ interactive = True ,
408+ tools = args .tools ,
409+ volumes = args .volumes ))
410+
411+ # [container run :bug :command]
412+ cmd = g_subparsers .add_parser ('run' )
413+ cmd .add_argument ('bug' )
414+ cmd .add_argument ('--with' ,
415+ help = 'name of a tool' ,
416+ dest = 'tools' ,
417+ action = 'append' ,
418+ default = [])
419+ cmd .add_argument ('-v' , '--volume' ,
420+ help = 'a host-container volume mapping' ,
421+ dest = 'volumes' ,
422+ action = 'append' ,
423+ default = [])
424+ cmd .add_argument ('command' )
425+ cmd .set_defaults (func = lambda args : launch (rbox ,
426+ args .bug ,
427+ interactive = False ,
428+ command = args .command ,
429+ tools = args .tools ,
430+ volumes = args .volumes ))
380431
381432 # [container connect :bug]
382433
0 commit comments