Repository: osrf/rocker

Issue:
extract pull functionality into library
it's currently only available in the cli interface. It could easily be a free function for easier reuse.

Comments:

Patch:
diff --git a/src/rocker/cli.py b/src/rocker/cli.py
index f422ef0..5b59ed7 100755
--- a/src/rocker/cli.py
+++ b/src/rocker/cli.py
@@ -18,11 +18,10 @@ import argparse
 import os
 import sys
 
-
-import docker
-
 from .core import DockerImageGenerator
 from .core import list_plugins
+from .core import pull_image
+
 
 def main():
 
@@ -51,18 +50,8 @@ def main():
     base_image = args.image
 
     if args.pull:
-        try:
-            docker_client = docker.APIClient()
-        except AttributeError:
-            # docker-py pre 2.0
-            docker_client = docker.Client()
-        try:
-            print("Pulling image %s" % base_image)
-            for line in docker_client.pull(base_image, stream=True):
-                print(line)
-        except docker.errors.APIError as ex:
-            print('Pull of %s failed: %s' % (base_image, ex))
-            pass
+        pull_image(base_image)
+
     dig = DockerImageGenerator(active_extensions, args_dict, base_image)
     exit_code = dig.build(**vars(args))
     if exit_code != 0:
diff --git a/src/rocker/core.py b/src/rocker/core.py
index 895c6ed..06e836e 100755
--- a/src/rocker/core.py
+++ b/src/rocker/core.py
@@ -29,6 +29,15 @@ import docker
 import pexpect
 
 
+def get_docker_client():
+    """Simple helper function for pre 2.0 imports"""
+    try:
+        docker_client = docker.APIClient()
+    except AttributeError:
+        # docker-py pre 2.0
+        docker_client = docker.Client()
+    return docker_client
+
 class DockerImageGenerator(object):
     def __init__(self, active_extensions, cliargs, base_image):
         self.built = False
@@ -59,11 +68,7 @@ class DockerImageGenerator(object):
             arguments['tag'] = self.image_name
             print("Building docker file with arguments: ", arguments)
             try:
-                try:
-                    docker_client = docker.APIClient()
-                except AttributeError:
-                    # docker-py pre 2.0
-                    docker_client = docker.Client()
+                docker_client = get_docker_client()
                 success_detected = False
                 for line in docker_client.build(**arguments):
                     output = line.get('stream', '').rstrip()
@@ -159,3 +164,15 @@ def list_plugins(extension_point='rocker.extensions'):
     plugin_names = list(unordered_plugins.keys())
     plugin_names.sort()
     return OrderedDict([(k, unordered_plugins[k]) for k in plugin_names])
+
+
+def pull_image(image_name):
+    docker_client = get_docker_client()
+    try:
+        print("Pulling image %s" % image_name)
+        for line in docker_client.pull(image_name, stream=True):
+            print(line)
+        return True
+    except docker.errors.APIError as ex:
+        print('Pull of %s failed: %s' % (image_name, ex))
+        return False


Test patch:
diff --git a/test/test_core.py b/test/test_core.py
index 9c7a5b7..0fdfe8c 100644
--- a/test/test_core.py
+++ b/test/test_core.py
@@ -15,10 +15,14 @@
 # specific language governing permissions and limitations
 # under the License.
 
+import docker
 import unittest
 
+from itertools import chain
 
 from rocker.cli import DockerImageGenerator, list_plugins
+from rocker.core import pull_image
+from rocker.core import get_docker_client
 
 class RockerCoreTest(unittest.TestCase):
     
@@ -29,3 +33,18 @@ class RockerCoreTest(unittest.TestCase):
         self.assertTrue('pulse' in plugin_names )
         self.assertTrue('user' in plugin_names )
         self.assertTrue('home' in plugin_names )
+
+    def test_pull_image(self):
+        TEST_IMAGE='alpine:latest'
+        docker_client = get_docker_client()
+
+        l = docker_client.images()
+        tags = set(chain.from_iterable([i['RepoTags'] for i in l if i['RepoTags']]))
+        print(tags)
+        if TEST_IMAGE in tags:
+            docker_client.remove_image(TEST_IMAGE)
+            print('removed image %s' % TEST_IMAGE)
+        self.assertTrue(pull_image(TEST_IMAGE))
+
+    def test_failed_pull_image(self):
+        self.assertFalse(pull_image("osrf/ros:does_not_exist"))