1111import sys
1212import logging
1313import os
14+ import entrypoints
1415import getpass
1516import shutil
1617import tempfile
1718import time
1819
19- import docker
20+ from . engine import BuildError , ContainerEngineException , ImageLoadError
2021from urllib .parse import urlparse
21- from docker .utils import kwargs_from_env
22- from docker .errors import DockerException
2322import escapism
2423from pythonjsonlogger import jsonlogger
2524
@@ -382,6 +381,33 @@ def _user_name_default(self):
382381 config = True ,
383382 )
384383
384+ engine = Unicode (
385+ "docker" ,
386+ config = True ,
387+ help = """
388+ Name of the container engine.
389+
390+ Defaults to 'docker'.
391+ """ ,
392+ )
393+
394+ def get_engine (self ):
395+ """Return an instance of the container engine.
396+
397+ Currently no arguments are passed to the engine constructor.
398+ """
399+ engines = entrypoints .get_group_named ("repo2docker.engines" )
400+ try :
401+ entry = engines [self .engine ]
402+ except KeyError :
403+ raise ContainerEngineException (
404+ "Container engine '{}' not found. Available engines: {}" .format (
405+ self .engine , "," .join (engines .keys ())
406+ )
407+ )
408+ engine_class = entry .load ()
409+ return engine_class (parent = self )
410+
385411 def fetch (self , url , ref , checkout_path ):
386412 """Fetch the contents of `url` and place it in `checkout_path`.
387413
@@ -474,13 +500,18 @@ def initialize(self):
474500
475501 def push_image (self ):
476502 """Push docker image to registry"""
477- client = docker . APIClient ( version = "auto" , ** kwargs_from_env () )
503+ client = self . get_engine ( )
478504 # Build a progress setup for each layer, and only emit per-layer
479505 # info every 1.5s
480506 progress_layers = {}
481507 layers = {}
482508 last_emit_time = time .time ()
483- for chunk in client .push (self .output_image_spec , stream = True ):
509+ for chunk in client .push (self .output_image_spec ):
510+ if client .string_output :
511+ self .log .info (chunk , extra = dict (phase = "pushing" ))
512+ continue
513+ # else this is Docker output
514+
484515 # each chunk can be one or more lines of json events
485516 # split lines here in case multiple are delivered at once
486517 for line in chunk .splitlines ():
@@ -492,7 +523,7 @@ def push_image(self):
492523 continue
493524 if "error" in progress :
494525 self .log .error (progress ["error" ], extra = dict (phase = "failed" ))
495- raise docker . errors . ImageLoadError (progress ["error" ])
526+ raise ImageLoadError (progress ["error" ])
496527 if "id" not in progress :
497528 continue
498529 # deprecated truncated-progress data
@@ -528,7 +559,7 @@ def start_container(self):
528559
529560 Returns running container
530561 """
531- client = docker . from_env ( version = "auto" )
562+ client = self . get_engine ( )
532563
533564 docker_host = os .environ .get ("DOCKER_HOST" )
534565 if docker_host :
@@ -565,11 +596,8 @@ def start_container(self):
565596
566597 container_volumes = {}
567598 if self .volumes :
568- api_client = docker .APIClient (
569- version = "auto" , ** docker .utils .kwargs_from_env ()
570- )
571- image = api_client .inspect_image (self .output_image_spec )
572- image_workdir = image ["ContainerConfig" ]["WorkingDir" ]
599+ image = client .inspect_image (self .output_image_spec )
600+ image_workdir = image .config ["WorkingDir" ]
573601
574602 for k , v in self .volumes .items ():
575603 container_volumes [os .path .abspath (k )] = {
@@ -580,15 +608,14 @@ def start_container(self):
580608 run_kwargs = dict (
581609 publish_all_ports = self .all_ports ,
582610 ports = ports ,
583- detach = True ,
584611 command = run_cmd ,
585612 volumes = container_volumes ,
586613 environment = self .environment ,
587614 )
588615
589616 run_kwargs .update (self .extra_run_kwargs )
590617
591- container = client .containers . run (self .output_image_spec , ** run_kwargs )
618+ container = client .run (self .output_image_spec , ** run_kwargs )
592619
593620 while container .status == "created" :
594621 time .sleep (0.5 )
@@ -611,7 +638,7 @@ def wait_for_container(self, container):
611638 if container .status == "running" :
612639 self .log .info ("Stopping container...\n " , extra = dict (phase = "running" ))
613640 container .kill ()
614- exit_code = container .attrs [ "State" ][ "ExitCode" ]
641+ exit_code = container .exitcode
615642
616643 container .wait ()
617644
@@ -645,12 +672,11 @@ def find_image(self):
645672 if self .dry_run :
646673 return False
647674 # check if we already have an image for this content
648- client = docker . APIClient ( version = "auto" , ** kwargs_from_env () )
675+ client = self . get_engine ( )
649676 for image in client .images ():
650- if image ["RepoTags" ] is not None :
651- for tag in image ["RepoTags" ]:
652- if tag == self .output_image_spec + ":latest" :
653- return True
677+ for tag in image .tags :
678+ if tag == self .output_image_spec + ":latest" :
679+ return True
654680 return False
655681
656682 def build (self ):
@@ -660,12 +686,9 @@ def build(self):
660686 # Check if r2d can connect to docker daemon
661687 if not self .dry_run :
662688 try :
663- docker_client = docker .APIClient (version = "auto" , ** kwargs_from_env ())
664- except DockerException as e :
665- self .log .error (
666- "\n Docker client initialization error: %s.\n Check if docker is running on the host.\n " ,
667- e ,
668- )
689+ docker_client = self .get_engine ()
690+ except ContainerEngineException as e :
691+ self .log .error ("\n Container engine initialization error: %s\n " , e )
669692 self .exit (1 )
670693
671694 # If the source to be executed is a directory, continue using the
@@ -751,11 +774,14 @@ def build(self):
751774 self .cache_from ,
752775 self .extra_build_kwargs ,
753776 ):
754- if "stream" in l :
777+ if docker_client .string_output :
778+ self .log .info (l , extra = dict (phase = "building" ))
779+ # else this is Docker output
780+ elif "stream" in l :
755781 self .log .info (l ["stream" ], extra = dict (phase = "building" ))
756782 elif "error" in l :
757783 self .log .info (l ["error" ], extra = dict (phase = "failure" ))
758- raise docker . errors . BuildError (l ["error" ], build_log = "" )
784+ raise BuildError (l ["error" ])
759785 elif "status" in l :
760786 self .log .info (
761787 "Fetching base image...\r " , extra = dict (phase = "building" )
0 commit comments