Skip to content

Commit

Permalink
Add progress_bar option to image pull
Browse files Browse the repository at this point in the history
Add a new arg option called progress_bar that when set to
true will display a progress bar with the image pull progress.
This uses the compat endpoint as that is the data we are able
to parse to displat the progress bar.

Signed-off-by: Urvashi Mohnani <[email protected]>
  • Loading branch information
umohnani8 committed Nov 9, 2023
1 parent 392ceaa commit 85d0130
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 1 deletion.
17 changes: 17 additions & 0 deletions Pipfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"

[packages]
pyxdg = ">=0.26"
requests = ">=2.24"
sphinx = "*"
tomli = ">=1.2.3"
urllib3 = "<2.0.3,>=1.26.5"
rich = ">=13.6.0"

[dev-packages]

[requires]
python_version = "3.11"
50 changes: 49 additions & 1 deletion podman/domain/images_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
import logging
import urllib.parse
from typing import Any, Dict, Generator, Iterator, List, Mapping, Optional, Union

import requests
from rich.progress import Progress

from podman import api
from podman.api import Literal
Expand Down Expand Up @@ -259,6 +259,8 @@ def pull(
config for this request. auth_config should contain the username and password
keys to be valid.
platform (str) – Platform in the format os[/arch[/variant]]
progress_bar (bool) - Display a progress bar with the image pull progress (uses
the compat endpoint). Default: False
tls_verify (bool) - Require TLS verification. Default: True.
stream (bool) - When True, the pull progress will be published as received.
Default: False.
Expand Down Expand Up @@ -307,9 +309,26 @@ def pull(
params["Variant"] = tokens[2]

stream = kwargs.get("stream", False)
# if the user wants a progress bar, we need to use the compat endpoint
# so set that to true as well as stream so we can parse that output for the
# progress bar
progress_bar = kwargs.get("progress_bar", False)
if progress_bar:
params["compatMode"] = True
stream = True

response = self.client.post("/images/pull", params=params, stream=stream, headers=headers)
response.raise_for_status(not_found=ImageNotFound)

if progress_bar:
tasks = {}
print("Pulling", params["reference"])
with Progress() as progress:
for line in response.iter_lines():
decoded_line = json.loads(line.decode('utf-8'))
self.__show_progress_bar(decoded_line, progress, tasks)
return None

if stream:
return response.iter_lines()

Expand All @@ -325,6 +344,35 @@ def pull(
return self.get(obj["id"])
return self.resource()

def __show_progress_bar(self, line, progress, tasks):
completed = False
if line['status'] == 'Download complete':
description = f'[green][Download complete {line["id"]}]'
completed = True
elif line['status'] == 'Downloading':
description = f'[red][Download {line["id"]}]'
else:
# skip other statuses
return

task_id = line["id"]
if task_id not in tasks.keys():
if completed:
# some layers are really small that they download immediately without showing
# anything as Downloading in the stream.
# For that case, show a completed progress bar
tasks[task_id] = progress.add_task(description, total=100, completed=100)
else:
tasks[task_id] = progress.add_task(description, total=line['progressDetail']['total']) # pylint: disable=line-too-long
else:
if completed:
# due to the stream, the Download complete output can happen before the Downloading
# bar outputs the 100%. So when we detect that the download is in fact complete,
# update the progress bar to show 100%
progress.update(tasks[task_id], description=description, total=100, completed=100)
else:
progress.update(tasks[task_id], completed=line['progressDetail']['current'])

def remove(
self,
image: Union[Image, str],
Expand Down

0 comments on commit 85d0130

Please sign in to comment.