Repository: google/docker-explorer

Issue:
Have DE auto complete partial docker ID
ie use `0ddf71064` for 
`0ddf710643b47e581dbce3e17677c9a557b82943bacee2dfbc19f178a99ad374`

Discussion:

Patch:
diff --git a/docker_explorer/de.py b/docker_explorer/de.py
index 4817867..c42b89c 100644
--- a/docker_explorer/de.py
+++ b/docker_explorer/de.py
@@ -41,7 +41,7 @@ class DockerExplorer(object):
     self._argument_parser = None
     self.container_config_filename = 'config.v2.json'
     self.containers_directory = None
-    self.docker_directory = None
+    self.docker_directory = '/var/lib/docker'
     self.docker_version = 2
 
   def _SetDockerDirectory(self, docker_path):
@@ -136,15 +136,49 @@ class DockerExplorer(object):
     """Parses the command line options."""
     self.docker_directory = os.path.abspath(options.docker_directory)
 
-  def GetContainer(self, container_id):
-    """Returns a Container object given a container_id.
+  def _GetFullContainerID(self, short_id):
+    """Searches for a container ID from its first characters.
 
     Args:
-      container_id (str): the ID of the container.
+      short_id (str): the first few characters of a container ID.
+    Returns:
+      str: the full container ID
+    Raises:
+      errors.DockerExplorerError: when we couldn't map the short version to
+        exactly one full container ID.
+    """
+    if len(short_id) == 64:
+      return short_id
+
+    containers_dir = os.path.join(self.docker_directory, 'containers')
+    possible_cids = []
+    for container_dirs in sorted(os.listdir(containers_dir)):
+      possible_cid = os.path.basename(container_dirs)
+      if possible_cid.startswith(short_id):
+        possible_cids.append(possible_cid)
+
+    possible_cids_len = len(possible_cids)
+    if possible_cids_len == 0:
+      raise errors.DockerExplorerError(
+          'Could not find any container ID starting with "{0}"'.format(
+              short_id))
+    if possible_cids_len > 1:
+      raise errors.DockerExplorerError(
+          'Too many container IDs starting with "{0}": {1}'.format(
+              short_id, ', '.join(possible_cids)))
+
+    return possible_cids[0]
+
+  def GetContainer(self, container_id_part):
+    """Returns a Container object given the first characters of a container_id.
+
+    Args:
+      container_id_part (str): the first characters of a container ID.
 
     Returns:
       container.Container: the container object.
     """
+    container_id = self._GetFullContainerID(container_id_part)
     return container.Container(
         self.docker_directory, container_id, docker_version=self.docker_version)
 


Test patch:
diff --git a/tests.py b/tests.py
index c3689d9..6d73370 100644
--- a/tests.py
+++ b/tests.py
@@ -250,6 +250,31 @@ class TestAufsStorage(DockerTestCase):
         'with command : /bin/sh -c #(nop)  CMD ["sh"]')
     self.assertEqual(expected_string, container_obj.GetHistory())
 
+  def testGetFullContainerID(self):
+    """Tests the DockerExplorer._GetFullContainerID function on AuFS."""
+    self.assertEqual(
+        '2cc4b0d9c1dfdf71099c5e9a109e6a0fe286152a5396bd1850689478e8f70625',
+        self.de_object._GetFullContainerID('2cc4b0d'))
+
+    with self.assertRaises(Exception) as err:
+      self.de_object._GetFullContainerID('')
+    self.assertEqual(
+        'Too many container IDs starting with "": '
+        '1171e9631158156ba2b984d335b2bf31838403700df3882c51aed70beebb604f, '
+        '2cc4b0d9c1dfdf71099c5e9a109e6a0fe286152a5396bd1850689478e8f70625, '
+        '7b02fb3e8a665a63e32b909af5babb7d6ba0b64e10003b2d9534c7d5f2af8966, '
+        '986c6e682f30550512bc2f7243f5a57c91b025e543ef703c426d732585209945, '
+        'b6f881bfc566ed604da1dc9bc8782a3540380c094154d703a77113b1ecfca660, '
+        'c8a38b6c29b0c901c37c2bb17bfcd73942c44bb71cc528505385c62f3c6fff35, '
+        'dd39804186d4f649f1e9cec89df1583e7a12a48193223a16cc40958f7e76b858',
+        err.exception.message)
+
+    with self.assertRaises(Exception) as err:
+      self.de_object._GetFullContainerID('xx')
+    self.assertEqual(
+        'Could not find any container ID starting with "xx"',
+        err.exception.message)
+
 
 class TestOverlayStorage(DockerTestCase):
   """Tests methods in the OverlayStorage object."""
@@ -378,6 +403,26 @@ class TestOverlayStorage(DockerTestCase):
         'with command : /bin/sh -c #(nop)  CMD ["sh"]')
     self.assertEqual(expected_string, container_obj.GetHistory())
 
+  def testGetFullContainerID(self):
+    """Tests the DockerExplorer._GetFullContainerID function on Overlay."""
+    self.assertEqual(
+        '5dc287aa80b460652a5584e80a5c8c1233b0c0691972d75424cf5250b917600a',
+        self.de_object._GetFullContainerID('5dc287aa80'))
+
+    with self.assertRaises(Exception) as err:
+      self.de_object._GetFullContainerID('4')
+    self.assertEqual(
+        'Too many container IDs starting with "4": '
+        '42e8679f78d6ea623391cdbcb928740ed804f928bd94f94e1d98687f34c48311, '
+        '4ad09bee61dcc675bf41085dbf38c31426a7ed6666fdd47521bfb8f5e67a7e6d',
+        err.exception.message)
+
+    with self.assertRaises(Exception) as err:
+      self.de_object._GetFullContainerID('xx')
+    self.assertEqual(
+        'Could not find any container ID starting with "xx"',
+        err.exception.message)
+
 
 class TestOverlay2Storage(DockerTestCase):
   """Tests methods in the Overlay2Storage object."""
@@ -516,6 +561,30 @@ class TestOverlay2Storage(DockerTestCase):
         'with command : /bin/sh -c #(nop)  CMD ["sh"]')
     self.assertEqual(expected_string, container_obj.GetHistory(container_obj))
 
+  def testGetFullContainerID(self):
+    """Tests the DockerExplorer._GetFullContainerID function on Overlay2."""
+    self.assertEqual(
+        '61ba4e6c012c782186c649466157e05adfd7caa5b551432de51043893cae5353',
+        self.de_object._GetFullContainerID('61ba4e6c012c782'))
+
+    with self.assertRaises(Exception) as err:
+      self.de_object._GetFullContainerID('')
+    self.assertEqual(
+        'Too many container IDs starting with "": '
+        '10acac0b3466813c9e1f85e2aa7d06298e51fbfe86bbcb6b7a19dd33d3798f6a, '
+        '61ba4e6c012c782186c649466157e05adfd7caa5b551432de51043893cae5353, '
+        '8e8b7f23eb7cbd4dfe7e91646ddd0e0f524218e25d50113559f078dfb2690206, '
+        '9949fa153b778e39d6cab0a4e0ba60fa34a13fedb1f256d613a2f88c0c98408a, '
+        'f83f963c67cbd36055f690fc988c1e42be06c1253e80113d1d516778c06b2841',
+        err.exception.message)
+
+    with self.assertRaises(Exception) as err:
+      self.de_object._GetFullContainerID('xx')
+    self.assertEqual(
+        'Could not find any container ID starting with "xx"',
+        err.exception.message)
+
+
 del DockerTestCase
 
 if __name__ == '__main__':