Skip to content

Commit 5ba31be

Browse files
Reimplemented "container run" command (#124)
* container: removed erroneous decoding command * container: modified 'command' to operate in parent of source directory by default * cli: added 'container run' command * container: fixed 'command' to load environment variables * bumped version to 1.1.1
1 parent 2c96200 commit 5ba31be

File tree

3 files changed

+81
-27
lines changed

3 files changed

+81
-27
lines changed

bugzoo/cli.py

Lines changed: 74 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@
44
import bugzoo.errors
55
import bugzoo.version
66

7-
from typing import List
7+
from typing import List, Optional, Dict
88
from operator import itemgetter
99
from bugzoo.manager import BugZoo
10+
from bugzoo.tool import Tool
1011

1112

1213
def 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

bugzoo/container.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ def copy_from(self, source_fn: str, dest_fn: str) -> None:
218218

219219
def command(self,
220220
cmd: str,
221-
context: str = '/',
221+
context: Optional[str] = None,
222222
stdout: bool = True,
223223
stderr: bool = False,
224224
block: bool = True):
@@ -227,7 +227,11 @@ def command(self,
227227
Returns a tuple containing the exit code, execution duration, and
228228
output, respectively.
229229
"""
230-
cmd = '/bin/bash -c "cd {} && {}"'.format(context, cmd)
230+
# TODO: we need a better long-term alternative
231+
if context is None:
232+
context = os.path.join(self.bug.source_dir, '..')
233+
234+
cmd = '/bin/bash -c "source /.environment && cd {} && {}"'.format(context, cmd)
231235

232236
# based on: https://github.com/roidelapluie/docker-py/commit/ead9ffa34193281967de8cc0d6e1c0dcbf50eda5
233237
client = docker.from_env()
@@ -246,7 +250,6 @@ def command(self,
246250
# non-blocking mode
247251
else:
248252
out = client.api.exec_start(response['Id'], stream=True)
249-
out = out.decode(sys.stdout.encoding)
250253
return PendingExecResponse(response, out)
251254

252255
def coverage(self,

bugzoo/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = '1.0.1'
1+
__version__ = '1.1.1'

0 commit comments

Comments
 (0)