[PATCH 1/3] virtinstall: Improve the progress bar output by meter.end()

Toshiki Sonoda sonoda.toshiki at fujitsu.com
Wed Nov 9 09:33:55 UTC 2022


When virt-install transfers the vmlinuz and initrd.img from an iso disk,
virt-install prints the file size as 0B to the progress bar.

Therefore, we fix the meter to force update if meter.end()
is called earlier than self.update_period.

Signed-off-by: Toshiki Sonoda <sonoda.toshiki at fujitsu.com>
Signed-off-by: Haruka Ohata <ohata.haruka at fujitsu.com>
---
 tests/data/meter/meter7.txt      |  2 ++
 tests/data/meter/meter8.txt      |  6 ++++++
 tests/test_misc.py               | 35 ++++++++++++++++++++++++++------
 virtManager/object/domain.py     |  2 +-
 virtinst/_progresspriv.py        |  4 ++--
 virtinst/diskbackend.py          |  3 ++-
 virtinst/install/urlfetcher.py   |  6 ++++--
 virtinst/install/volumeupload.py |  3 ++-
 virtinst/progress.py             |  4 ++--
 virtinst/storage.py              |  2 +-
 10 files changed, 51 insertions(+), 16 deletions(-)
 create mode 100644 tests/data/meter/meter7.txt
 create mode 100644 tests/data/meter/meter8.txt

diff --git a/tests/data/meter/meter7.txt b/tests/data/meter/meter7.txt
new file mode 100644
index 00000000..ef467dcd
--- /dev/null
+++ b/tests/data/meter/meter7.txt
@@ -0,0 +1,2 @@
+
+Meter text test                                             |    0 B  00:00 ... 
diff --git a/tests/data/meter/meter8.txt b/tests/data/meter/meter8.txt
new file mode 100644
index 00000000..7e17ebf7
--- /dev/null
+++ b/tests/data/meter/meter8.txt
@@ -0,0 +1,6 @@
+
+Meter text test            40% [======-          ]    0 B/s | 3.9 kB  --:-- ETA 
+
+Meter text test            80% [=============-   ]  20 kB/s | 7.8 kB  00:00 ETA 
+
+Meter text test                                             | 7.8 kB  00:00 ... 
diff --git a/tests/test_misc.py b/tests/test_misc.py
index aa610f4d..486d3d1e 100644
--- a/tests/test_misc.py
+++ b/tests/test_misc.py
@@ -167,20 +167,30 @@ def test_misc_meter():
         with unittest.mock.patch("time.time", return_value=1.0):
             m.start(text, startval)
         with unittest.mock.patch("time.time", return_value=1.1):
-            m.update(0)
+            m.update(0, False)
         with unittest.mock.patch("time.time", return_value=1.5):
-            m.update(0)
+            m.update(0, False)
         with unittest.mock.patch("time.time", return_value=2.0):
-            m.update(100)
+            m.update(100, False)
         with unittest.mock.patch("time.time", return_value=3.0):
-            m.update(200)
+            m.update(200, False)
         with unittest.mock.patch("time.time", return_value=4.0):
-            m.update(2000)
+            m.update(2000, False)
         with unittest.mock.patch("time.time", return_value=5.0):
-            m.update(4000)
+            m.update(4000, False)
         with unittest.mock.patch("time.time", return_value=6.0):
             m.end()
 
+    def _test_meter_end(m, force=False, startval=10000, text="Meter text test"):
+        with unittest.mock.patch("time.time", return_value=1.0):
+            m.start(text, startval)
+        with unittest.mock.patch("time.time", return_value=1.1):
+            m.update(4000, force)
+        with unittest.mock.patch("time.time", return_value=1.2):
+            m.update(8000, force)
+        with unittest.mock.patch("time.time", return_value=1.3):
+            m.end()
+
     # Basic output testing
     meter = _progresspriv.TextMeter(output=io.StringIO())
     _test_meter_values(meter)
@@ -222,6 +232,19 @@ def test_misc_meter():
     out = meter.output.getvalue().replace("\r", "\n")
     utils.diff_compare(out, os.path.join(utils.DATADIR, "meter", "meter6.txt"))
 
+    # end() is called before meter is updated.
+    # In this case, we needs to call the update(num, True) before end() is called.
+    meter = _progresspriv.TextMeter(output=io.StringIO())
+    _test_meter_end(meter, False)
+    out = meter.output.getvalue().replace("\r", "\n")
+    utils.diff_compare(out, os.path.join(utils.DATADIR, "meter", "meter7.txt"))
+
+    # end() is called after meter is updated.
+    meter = _progresspriv.TextMeter(output=io.StringIO())
+    _test_meter_end(meter, True)
+    out = meter.output.getvalue().replace("\r", "\n")
+    utils.diff_compare(out, os.path.join(utils.DATADIR, "meter", "meter8.txt"))
+
     # BaseMeter coverage
     meter = _progresspriv.BaseMeter()
     _test_meter_values(meter)
diff --git a/virtManager/object/domain.py b/virtManager/object/domain.py
index 2d6f5bca..e7d2afcc 100644
--- a/virtManager/object/domain.py
+++ b/virtManager/object/domain.py
@@ -50,7 +50,7 @@ def start_job_progress_thread(vm, meter, progtext):
                     meter.start(progtext, data_total)
 
                 progress = data_total - data_remaining
-                meter.update(progress)
+                meter.update(progress, False)
             except Exception:  # pragma: no cover
                 log.exception("Error calling jobinfo")
                 return
diff --git a/virtinst/_progresspriv.py b/virtinst/_progresspriv.py
index 5a31a18c..119c4d2c 100644
--- a/virtinst/_progresspriv.py
+++ b/virtinst/_progresspriv.py
@@ -106,13 +106,13 @@ class BaseMeter:
         self.last_amount_read = 0
         self.last_update_time = now
 
-    def update(self, amount_read):
+    def update(self, amount_read, force):
         # for a real gui, you probably want to override and put a call
         # to your mainloop iteration function here
         assert type(amount_read) is int
 
         now = time.time()
-        if (not self.last_update_time or
+        if (force or not self.last_update_time or
                 (now >= self.last_update_time + self.update_period)):
             self.re.update(amount_read, now)
             self.last_amount_read = amount_read
diff --git a/virtinst/diskbackend.py b/virtinst/diskbackend.py
index 5f80c437..373797f1 100644
--- a/virtinst/diskbackend.py
+++ b/virtinst/diskbackend.py
@@ -617,6 +617,7 @@ class CloneStorageCreator(_StorageCreator):
                     l = os.read(src_fd, clone_block_size)
                     s = len(l)
                     if s == 0:
+                        meter.update(i, True)
                         meter.end()
                         break
                     # check sequence of zeros
@@ -629,7 +630,7 @@ class CloneStorageCreator(_StorageCreator):
                             break
                     i += s
                     if i < size_bytes:
-                        meter.update(i)
+                        meter.update(i, False)
             except OSError as e:  # pragma: no cover
                 log.debug("Error while cloning", exc_info=True)
                 msg = (_("Error cloning diskimage "
diff --git a/virtinst/install/urlfetcher.py b/virtinst/install/urlfetcher.py
index 4bd89c50..936d629a 100644
--- a/virtinst/install/urlfetcher.py
+++ b/virtinst/install/urlfetcher.py
@@ -118,10 +118,11 @@ class _URLFetcher(object):
         while 1:
             buff = urlobj.read(self._block_size)
             if not buff:
+                self.meter.update(total, True)
                 break
             fileobj.write(buff)
             total += len(buff)
-            self.meter.update(total)
+            self.meter.update(total, False)
         fileobj.flush()
         return total
 
@@ -253,7 +254,8 @@ class _HTTPURLFetcher(_URLFetcher):
         for data in urlobj.iter_content(chunk_size=self._block_size):
             fileobj.write(data)
             total += len(data)
-            self.meter.update(total)
+            self.meter.update(total, False)
+        self.meter.update(total, True)
         fileobj.flush()
         return total
 
diff --git a/virtinst/install/volumeupload.py b/virtinst/install/volumeupload.py
index 7046f294..21fa9f0a 100644
--- a/virtinst/install/volumeupload.py
+++ b/virtinst/install/volumeupload.py
@@ -112,11 +112,12 @@ def _upload_file(conn, meter, destpool, src):
             blocksize = 1024 * 1024  # 1 MiB
             data = fileobj.read(blocksize)
             if not data:
+                meter.update(total, True)
                 break
 
             safe_send(data)
             total += len(data)
-            meter.update(total)
+            meter.update(total, False)
 
         # Cleanup
         stream.finish()
diff --git a/virtinst/progress.py b/virtinst/progress.py
index b195b281..fe6f9933 100644
--- a/virtinst/progress.py
+++ b/virtinst/progress.py
@@ -34,9 +34,9 @@ class Meter:
         self._total_read = 0
         self._meter.start(text, size)
 
-    def update(self, new_total):
+    def update(self, new_total, force):
         self._total_read = new_total
-        self._meter.update(new_total)
+        self._meter.update(new_total, force)
 
     def end(self):
         self._meter.end()
diff --git a/virtinst/storage.py b/virtinst/storage.py
index 509f5cb0..ee58c5f6 100644
--- a/virtinst/storage.py
+++ b/virtinst/storage.py
@@ -440,7 +440,7 @@ def _progress_thread(volname, pool, meter, event):
 
     while True:  # pragma: no cover
         dummy1, dummy2, alloc = vol.info()
-        meter.update(alloc)
+        meter.update(alloc, False)
         if event.wait(1):
             break
 
-- 
2.38.1



More information about the virt-tools-list mailing list