From 2ae8ce898f89d384b37229ed163ba8920b7b4f6a Mon Sep 17 00:00:00 2001
From: Sergio Oliveira <sergio@tracy.com.br>
Date: Thu, 22 Oct 2015 14:42:02 -0200
Subject: [PATCH] Display progress bar if python-progress is available

---
 cli/copr_cli/main.py         | 18 ++++++++++++++++-
 cli/copr_cli/util.py         | 48 ++++++++++++++++++++++++++++++++++++++++++++
 python/copr/client/client.py | 16 +++++++++++----
 3 files changed, 77 insertions(+), 5 deletions(-)
 create mode 100644 cli/copr_cli/util.py

diff --git a/cli/copr_cli/main.py b/cli/copr_cli/main.py
index ba24054..8f25650 100644
--- a/cli/copr_cli/main.py
+++ b/cli/copr_cli/main.py
@@ -29,6 +29,8 @@ log.addHandler(NullHandler())
 from copr import CoprClient
 import copr.client.exceptions as copr_exceptions
 
+from .util import ProgressBar
+
 
 no_config_warning = """
 |================ WARNING: =======================|
@@ -159,10 +161,24 @@ class Commands(object):
             copr = m.group(2)
         else:
             username = None
+
+        if os.path.exists(args.pkgs[0]):
+            bar = ProgressBar(max=os.path.getsize(args.pkgs[0]))
+
+            def progress_callback(monitor):
+                bar.next(n=8192)
+
+            print('Uploading package {}'.format(args.pkgs[0]))
+        else:
+            progress_callback = None
+
         result = self.client.create_new_build(
             projectname=copr, chroots=args.chroots, pkgs=args.pkgs,
             memory=args.memory, timeout=args.timeout,
-            username=username)
+            username=username, progress_callback=progress_callback)
+
+        bar.finish()
+
         if result.output != "ok":
             print(result.error)
             return
diff --git a/cli/copr_cli/util.py b/cli/copr_cli/util.py
new file mode 100644
index 0000000..bb73415
--- /dev/null
+++ b/cli/copr_cli/util.py
@@ -0,0 +1,48 @@
+# coding: utf-8
+
+try:
+    from progress.bar import Bar
+except ImportError:
+    progress = False
+else:
+    progress = True
+
+
+def format_size(bytes):
+    if bytes > 1000 * 1000:
+        return '%.1fMB' % (bytes / 1000.0 / 1000)
+    elif bytes > 10 * 1000:
+        return '%ikB' % (bytes / 1000)
+    elif bytes > 1000:
+        return '%.1fkB' % (bytes / 1000.0)
+    else:
+        return '%ibytes' % bytes
+
+
+class ProgressMixin(object):
+
+    @property
+    def download_speed(self):
+        if self.avg == 0.0:
+            return "..."
+        return format_size(1 / self.avg) + "/s"
+
+    @property
+    def downloaded(self):
+        return format_size(self.index)
+
+
+class DummyBar(object):
+    def __init__(self, max=None):
+        pass
+
+    def next(self, n=None):
+        pass
+
+
+if progress:
+    class ProgressBar(Bar, ProgressMixin):
+        message = "%(percent)d%%"
+        suffix = "%(downloaded)s %(download_speed)s eta %(eta_td)s"
+else:
+    ProgressBar = DummyBar
diff --git a/python/copr/client/client.py b/python/copr/client/client.py
index 40071f7..f7f6c7a 100644
--- a/python/copr/client/client.py
+++ b/python/copr/client/client.py
@@ -14,7 +14,8 @@ import requests
 import six
 
 from six.moves import configparser
-from requests_toolbelt.multipart.encoder import MultipartEncoder
+from requests_toolbelt.multipart.encoder import (MultipartEncoder,
+                                                 MultipartEncoderMonitor)
 
 # urlparse from six is not available on el7
 # because it requires at least python-six-1.4.1
@@ -301,7 +302,8 @@ class CoprClient(UnicodeMixin):
         return response
 
     def create_new_build(self, projectname, pkgs, username=None,
-                         timeout=None, memory=None, chroots=None):
+                         timeout=None, memory=None, chroots=None,
+                         progress_callback=None):
         """ Creates new build
 
             :param projectname: name of Copr project (without user namespace)
@@ -310,6 +312,8 @@ class CoprClient(UnicodeMixin):
             :param timeout: [optional] build timeout
             :param memory: [optional] amount of required memory for build process
             :param chroots: [optional] build only with given chroots
+            :param progress_callback: [optional] a function that received a
+            MultipartEncoderMonitor instance for each chunck of uploaded data
 
             :return: :py:class:`~.responses.CoprResponse` with additional fields:
 
@@ -321,7 +325,6 @@ class CoprClient(UnicodeMixin):
             "memory_reqs": memory,
             "timeout": timeout
         }
-        headers = None
 
         if urlparse(pkgs[0]).scheme != "":
             api_endpoint = "new_build"
@@ -342,7 +345,12 @@ class CoprClient(UnicodeMixin):
             data[chroot] = "y"
 
         m = MultipartEncoder(data)
-        data = self._fetch(url, m, method="post", headers={'Content-Type': m.content_type})
+
+        callback = progress_callback or (lambda x: x)
+
+        monit = MultipartEncoderMonitor(m, callback)
+        data = self._fetch(url, monit, method="post",
+                           headers={'Content-Type': monit.content_type})
 
         response = CoprResponse(
             client=self,
-- 
2.6.0

