Skip to contentSkip to conversation

Support progress reporting

PATCH Superseded Paul Eggleton 3 participants 17 messages Jun 13, 2016 – Jun 28, 2016 Library code

v1 of 2 Superseded Latest is v2 →

lore
Share & tools
lore
#0 lore raw

cover Support progress reporting

Add code to support progress reporting within OpenEmbedded, as well as a couple of related changes to allow reworking the extensible SDK installation process.

The following changes since commit 6d1379c8818400e5cdc442e6142f08a110fd5b95:

lib/bb/main.py: Fix use of BBPOSTCONF and BBPRECONF (2016-06-09 18:00:45 +0100)

are available in the git repository at:

git://git.yoctoproject.org/poky-contrib paule/startup-bb
http://git.yoctoproject.org/cgit.cgi/poky-contrib/log/?h=paule/startup-bb

Paul Eggleton (10):
knotty: provide a symlink to the latest console log
knotty: import latest python-progressbar
lib: implement basic task progress support
lib/bb/progress: add MultiStageProgressReporter
fetch2: implement progress support
knotty: add code to support showing progress for sstate object querying
knotty: show task progress bar
knotty: add quiet output mode
runqueue: add ability to enforce that tasks are setscened
runqueue: report progress for "Preparing RunQueue" step

 lib/bb/build.py                |  34 ++++
 lib/bb/event.py                |  27 +++
 lib/bb/fetch2/__init__.py      |   4 +-
 lib/bb/fetch2/git.py           |  52 +++++-
 lib/bb/fetch2/wget.py          |  26 ++-
 lib/bb/main.py                 |   9 +
 lib/bb/msg.py                  |   5 +-
 lib/bb/progress.py             | 266 ++++++++++++++++++++++++++++
 lib/bb/runqueue.py             | 131 +++++++++++++-
 lib/bb/ui/knotty.py            | 143 ++++++++++++---
 lib/bb/ui/uihelper.py          |   7 +-
 lib/progressbar.py             | 384 ----------------------------------------
 lib/progressbar/LICENSE.txt    |  52 ++++++
 lib/progressbar/__init__.py    |  49 ++++++
 lib/progressbar/compat.py      |  44 +++++
 lib/progressbar/progressbar.py | 315 +++++++++++++++++++++++++++++++++
 lib/progressbar/widgets.py     | 391 +++++++++++++++++++++++++++++++++++++++++
 17 files changed, 1519 insertions(+), 420 deletions(-)
 create mode 100644 lib/bb/progress.py
 delete mode 100644 lib/progressbar.py
 create mode 100644 lib/progressbar/LICENSE.txt
 create mode 100644 lib/progressbar/__init__.py
 create mode 100644 lib/progressbar/compat.py
 create mode 100644 lib/progressbar/progressbar.py
 create mode 100644 lib/progressbar/widgets.py
Signature · 1 line
2.5.5
#1 lore raw

PATCH 1/10 knotty: provide a symlink to the latest console log

If you're looking to find the latest console log repeatedly it can be a bit tedious - let's just create a symlink just as we do with other logs to make it easy to find.

---
 lib/bb/ui/knotty.py | 6 ++++++
 1 file changed, 6 insertions(+)
lib/bb/ui/knotty.py +6 -0
index 9605c8e..ddd36d5 100644
@@ -287,6 +287,12 @@ def main(server, eventHandler, params, tf = TerminalFilter):
         bb.msg.addDefaultlogFilter(consolelog)
         consolelog.setFormatter(conlogformat)
         logger.addHandler(consolelog)
+        loglink = os.path.join(os.path.dirname(consolelogfile), 'console-latest.log')
+        bb.utils.remove(loglink)
+        try:
+           os.symlink(os.path.basename(consolelogfile), loglink)
+        except OSError:
+           pass
 
     llevel, debug_domains = bb.msg.constructLogOptions()
     server.runCommand(["setEventMask", server.getEventHandle(), llevel, debug_domains, _evt_list])
Signature · 1 line
2.5.5
#2 lore raw

PATCH 2/10 knotty: import latest python-progressbar

In reply to Paul Eggleton

Since we're going to make some minor extensions to it, it makes sense to bring in the latest version of python-progressbar. Its structure has changed a little but the API hasn't; however we do need to ensure our overridden _needs_update() function's signature in BBProgress() matches properly.

---
 lib/bb/ui/knotty.py            |   2 +-
 lib/progressbar.py             | 384 -----------------------------------------
 lib/progressbar/LICENSE.txt    |  52 ++++++
 lib/progressbar/__init__.py    |  49 ++++++
 lib/progressbar/compat.py      |  44 +++++
 lib/progressbar/progressbar.py | 307 ++++++++++++++++++++++++++++++++
 lib/progressbar/widgets.py     | 355 +++++++++++++++++++++++++++++++++++++
 7 files changed, 808 insertions(+), 385 deletions(-)
 delete mode 100644 lib/progressbar.py
 create mode 100644 lib/progressbar/LICENSE.txt
 create mode 100644 lib/progressbar/__init__.py
 create mode 100644 lib/progressbar/compat.py
 create mode 100644 lib/progressbar/progressbar.py
 create mode 100644 lib/progressbar/widgets.py
lib/bb/ui/knotty.py +1 -1
index ddd36d5..6a6f688 100644
@@ -51,7 +51,7 @@ class BBProgress(progressbar.ProgressBar):
             self._resize_default = None
         progressbar.ProgressBar.__init__(self, maxval, [self.msg + ": "] + widgets, fd=sys.stdout)
 
-    def _handle_resize(self, signum, frame):
+    def _handle_resize(self, signum=None, frame=None):
         progressbar.ProgressBar._handle_resize(self, signum, frame)
         if self._resize_default:
             self._resize_default(signum, frame)
lib/progressbar.py deleted +0 -384

384 lines not on this page · raw message

lib/progressbar/LICENSE.txt new file +52 -0

52 lines not on this page · raw message

lib/progressbar/__init__.py new file +49 -0

49 lines not on this page · raw message

lib/progressbar/compat.py new file +44 -0

44 lines not on this page · raw message

lib/progressbar/progressbar.py new file +307 -0

307 lines not on this page · raw message

lib/progressbar/widgets.py new file +355 -0

355 lines not on this page · raw message

Signature · 1 line
2.5.5
#3 lore raw

PATCH 3/10 lib: implement basic task progress support

In reply to Paul Eggleton

For long-running tasks where we have some output from the task that gives us some idea of the progress of the task (such as a percentage complete), provide the means to scrape the output for that progress information and show it to the user in the default knotty terminal output in the form of a progress bar. This is implemented using a new TaskProgress event as well as some code we can insert to do output scanning/filtering.

Any task can fire TaskProgress events; however, if you have a shell task whose output you wish to scan for progress information, you just need to set the "progress" varflag on the task. This can be set to:
* "percent" to just look for a number followed by a % sign
* "percent:<regex>" to specify your own regex matching a percentage value (must have a single group which matches the percentage number)
* "outof:<regex>" to look for the specified regex matching x out of y items completed (must have two groups - first group needs to be x, second y).
We can potentially extend this in future but this should be a good start.

Part of the implementation for [YOCTO #5383].

---
 lib/bb/build.py                | 34 +++++++++++++++++
 lib/bb/progress.py             | 86 ++++++++++++++++++++++++++++++++++++++++++
 lib/bb/ui/knotty.py            | 74 +++++++++++++++++++++++++++++++-----
 lib/bb/ui/uihelper.py          |  7 +++-
 lib/progressbar/progressbar.py | 16 ++++++--
 lib/progressbar/widgets.py     | 36 ++++++++++++++++++
 6 files changed, 239 insertions(+), 14 deletions(-)
 create mode 100644 lib/bb/progress.py
lib/bb/build.py +34 -0
index e016ae3..04bd580 100644
@@ -35,6 +35,7 @@ import stat
 import bb
 import bb.msg
 import bb.process
+import bb.progress
 from bb import data, event, utils
 
 bblogger = logging.getLogger('BitBake')
@@ -137,6 +138,25 @@ class TaskInvalid(TaskBase):
         super(TaskInvalid, self).__init__(task, None, metadata)
         self._message = "No such task '%s'" % task
 
+class TaskProgress(event.Event):
+    """
+    Task made some progress that could be reported to the user, usually in
+    the form of a progress bar or similar.
+    NOTE: this class does not inherit from TaskBase since it doesn't need
+    to - it's fired within the task context itself, so we don't have any of
+    the context information that you do in the case of the other events.
+    The event PID can be used to determine which task it came from.
+    The progress value is normally 0-100, but can also be negative
+    indicating that progress has been made but we aren't able to determine
+    how much.
+    The rate is optional, this is simply an extra string to display to the
+    user if specified.
+    """
+    def __init__(self, progress, rate=None):
+        self.progress = progress
+        self.rate = rate
+        event.Event.__init__(self)
+
 
 class LogTee(object):
     def __init__(self, logger, outfile):
@@ -340,6 +360,20 @@ exit $ret
     else:
         logfile = sys.stdout
 
+    progress = d.getVarFlag(func, 'progress', True)
+    if progress:
+        if progress == 'percent':
+            # Use default regex
+            logfile = bb.progress.BasicProgressHandler(d, outfile=logfile)
+        elif progress.startswith('percent:'):
+            # Use specified regex
+            logfile = bb.progress.BasicProgressHandler(d, regex=progress.split(':', 1)[1], outfile=logfile)
+        elif progress.startswith('outof:'):
+            # Use specified regex
+            logfile = bb.progress.OutOfProgressHandler(d, regex=progress.split(':', 1)[1], outfile=logfile)
+        else:
+            bb.warn('%s: invalid task progress varflag value "%s", ignoring' % (func, progress))
+
     def readfifo(data):
         lines = data.split(b'\0')
         for line in lines:
lib/bb/progress.py new file +86 -0

86 lines not on this page · raw message

lib/bb/ui/knotty.py +65 -9

123 lines not on this page · raw message

lib/bb/ui/uihelper.py +6 -1
index db70b76..1915e47 100644
@@ -18,6 +18,7 @@
 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 
 import bb.build
+import time
 
 class BBUIHelper:
     def __init__(self):
@@ -31,7 +32,7 @@ class BBUIHelper:
 
     def eventHandler(self, event):
         if isinstance(event, bb.build.TaskStarted):
-            self.running_tasks[event.pid] = { 'title' : "%s %s" % (event._package, event._task) }
+            self.running_tasks[event.pid] = { 'title' : "%s %s" % (event._package, event._task), 'starttime' : time.time() }
             self.running_pids.append(event.pid)
             self.needUpdate = True
         if isinstance(event, bb.build.TaskSucceeded):
@@ -52,6 +53,10 @@ class BBUIHelper:
             self.tasknumber_current = event.stats.completed + event.stats.active + event.stats.failed + 1
             self.tasknumber_total = event.stats.total
             self.needUpdate = True
+        if isinstance(event, bb.build.TaskProgress):
+            self.running_tasks[event.pid]['progress'] = event.progress
+            self.running_tasks[event.pid]['rate'] = event.rate
+            self.needUpdate = True
 
     def getTasks(self):
         self.needUpdate = False
lib/progressbar/progressbar.py +12 -4
index 0b9dcf7..2873ad6 100644
@@ -3,6 +3,8 @@
 # progressbar  - Text progress bar library for Python.
 # Copyright (c) 2005 Nilton Volpato
 #
+# (With some small changes after importing into BitBake)
+#
 # This library is free software; you can redistribute it and/or
 # modify it under the terms of the GNU Lesser General Public
 # License as published by the Free Software Foundation; either
@@ -261,12 +263,14 @@ class ProgressBar(object):
         now = time.time()
         self.seconds_elapsed = now - self.start_time
         self.next_update = self.currval + self.update_interval
-        self.fd.write(self._format_line() + '\r')
+        output = self._format_line()
+        self.fd.write(output + '\r')
         self.fd.flush()
         self.last_update_time = now
+        return output
 
 
-    def start(self):
+    def start(self, update=True):
         """Starts measuring time, and prints the bar at 0%.
 
         It returns self so you can use it like this:
@@ -289,8 +293,12 @@ class ProgressBar(object):
             self.update_interval = self.maxval / self.num_intervals
 
 
-        self.start_time = self.last_update_time = time.time()
-        self.update(0)
+        self.start_time = time.time()
+        if update:
+            self.last_update_time = self.start_time
+            self.update(0)
+        else:
+            self.last_update_time = 0
 
         return self
 
lib/progressbar/widgets.py +36 -0
index 6434ad5..77285ca 100644
@@ -353,3 +353,39 @@ class BouncingBar(Bar):
         if not self.fill_left: rpad, lpad = lpad, rpad
 
         return '%s%s%s%s%s' % (left, lpad, marker, rpad, right)
+
+
+class BouncingSlider(Bar):
+    """
+    A slider that bounces back and forth in response to update() calls
+    without reference to the actual value. Based on a combination of
+    BouncingBar from a newer version of this module and RotatingMarker.
+    """
+    def __init__(self, marker='<=>'):
+        self.curmark = -1
+        self.forward = True
+        Bar.__init__(self, marker=marker)
+    def update(self, pbar, width):
+        left, marker, right = (format_updatable(i, pbar) for i in
+                               (self.left, self.marker, self.right))
+
+        width -= len(left) + len(right)
+        if width < 0:
+            return ''
+
+        if pbar.finished: return '%s%s%s' % (left, width * '=', right)
+
+        self.curmark = self.curmark + 1
+        position = int(self.curmark % (width * 2 - 1))
+        if position + len(marker) > width:
+            self.forward = not self.forward
+            self.curmark = 1
+            position = 1
+        lpad = ' ' * (position - 1)
+        rpad = ' ' * (width - len(marker) - len(lpad))
+
+        if not self.forward:
+            temp = lpad
+            lpad = rpad
+            rpad = temp
+        return '%s%s%s%s%s' % (left, lpad, marker, rpad, right)
Signature · 1 line
2.5.5
#4 lore raw

PATCH 4/10 lib/bb/progress: add MultiStageProgressReporter

In reply to Paul Eggleton

Add a class to help report progress in a task that consists of multiple stages, some of which may have internal progress (do_rootfs within OpenEmbedded is one example). Each stage is weighted to try to give a reasonable representation of progress over time.

Part of the implementation for [YOCTO #5383].

---
 lib/bb/progress.py | 107 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 107 insertions(+)
lib/bb/progress.py +107 -0
index bab8e94..7ee9f04 100644
@@ -20,6 +20,7 @@ BitBake progress handling code
 import sys
 import re
 import time
+import inspect
 import bb.event
 import bb.build
 
@@ -84,3 +85,109 @@ class OutOfProgressHandler(ProgressHandler):
             progress = (float(nums[-1][0]) / float(nums[-1][1])) * 100
             self.update(progress)
         super(OutOfProgressHandler, self).write(string)
+
+class MultiStageProgressReporter(object):
+    """
+    Class which allows reporting progress without the caller
+    having to know where they are in the overall sequence. Useful
+    for tasks made up of python code spread across multiple
+    classes / functions - the progress reporter object can
+    be passed around or stored at the object level and calls
+    to next_stage() and update() made whereever needed.
+    """
+    def __init__(self, d, stage_weights, debug=False):
+        """
+        Initialise the progress reporter.
+
+        Parameters:
+        * d: the datastore (needed for firing the events)
+        * stage_weights: a list of weight values, one for each stage.
+          The value is scaled internally so you only need to specify
+          values relative to other values in the list, so if there
+          are two stages and the first takes 2s and the second takes
+          10s you would specify [2, 10] (or [1, 5], it doesn't matter).
+        * debug: specify True (and ensure you call finish() at the end)
+          in order to show a printout of the calculated stage weights
+          based on timing each stage. Use this to determine what the
+          weights should be when you're not sure.
+        """
+        self._data = d
+        total = sum(stage_weights)
+        self._stage_weights = [float(x)/total for x in stage_weights]
+        self._stage = -1
+        self._base_progress = 0
+        # Send an initial progress event so the bar gets shown
+        self._fire_progress(0)
+        self._debug = debug
+        if self._debug:
+            self._last_time = time.time()
+            self._stage_times = []
+            self._stage_total = None
+            self._callers = []
+
+    def _fire_progress(self, taskprogress):
+        bb.event.fire(bb.build.TaskProgress(taskprogress), self._data)
+
+    def next_stage(self, stage_total=None):
+        """
+        Move to the next stage.
+        Parameters:
+        * stage_total: optional total for progress within the stage,
+          see update() for details
+        NOTE: you need to call this before the first stage.
+        """
+        self._stage += 1
+        self._stage_total = stage_total
+        if self._stage == 0:
+            # First stage
+            if self._debug:
+                self._last_time = time.time()
+        else:
+            if self._stage < len(self._stage_weights):
+                self._base_progress = sum(self._stage_weights[:self._stage]) * 100
+                if self._debug:
+                    currtime = time.time()
+                    self._stage_times.append(currtime - self._last_time)
+                    self._last_time = currtime
+                    self._callers.append(inspect.getouterframes(inspect.currentframe())[1])
+            elif not self._debug:
+                bb.warn('ProgressReporter: current stage beyond declared number of stages')
+                self._base_progress = 100
+            self._fire_progress(self._base_progress)
+
+    def update(self, stage_progress):
+        """
+        Update progress within the current stage.
+        Parameters:
+        * stage_progress: progress value within the stage. If stage_total
+          was specified when next_stage() was last called, then this
+          value is considered to be out of stage_total, otherwise it should
+          be a percentage value from 0 to 100.
+        """
+        if self._stage_total:
+            stage_progress = (float(stage_progress) / self._stage_total) * 100
+        if self._stage < 0:
+            bb.warn('ProgressReporter: update called before first call to next_stage()')
+        elif self._stage < len(self._stage_weights):
+            progress = self._base_progress + (stage_progress * self._stage_weights[self._stage])
+        else:
+            progress = self._base_progress
+        if progress > 100:
+            progress = 100
+        self._fire_progress(progress)
+
+    def finish(self):
+        if self._debug:
+            import math
+            self._stage_times.append(time.time() - self._last_time)
+            mintime = max(min(self._stage_times), 0.01)
+            self._callers.append(None)
+            stage_weights = [int(math.ceil(x / mintime)) for x in self._stage_times]
+            bb.warn('Stage weights: %s' % stage_weights)
+            out = []
+            for stage_weight, caller in zip(stage_weights, self._callers):
+                if caller:
+                    out.append('Up to %s:%d: %d' % (caller[1], caller[2], stage_weight))
+                else:
+                    out.append('Up to finish: %d' % stage_weight)
+            bb.warn('Stage times:\n  %s' % '\n  '.join(out))
Signature · 1 line
2.5.5
#5 lore raw

PATCH 5/10 fetch2: implement progress support

In reply to Paul Eggleton

Implement progress reporting support specifically for the fetchers. For fetch tasks we don't necessarily know which fetcher will be used (we might initially be fetching a git:// URI, but if we instead download a mirror tarball we may fetch that over http using wget). These programs also have different abilities as far as reporting progress goes (e.g. wget gives us percentage complete and rate, git gives this some of the time depending on what stage it's at). Additionally we filter out the progress output before it makes it to the logs, in order to prevent the logs filling up with junk.

At the moment this is only implemented for the wget and git fetchers since they are the most commonly used (and svn doesn't seem to support any kind of progress output, at least not without doing a relatively expensive remote file listing first).

Line changes such as the ones you get in git's output as it progresses don't make it to the log files, you only get the final state of the line so the logs aren't filled with progress information that's useless after the fact.

Part of the implementation for [YOCTO #5383].

---
 lib/bb/fetch2/__init__.py |  4 ++--
 lib/bb/fetch2/git.py      | 52 +++++++++++++++++++++++++++++++++++++++++++----
 lib/bb/fetch2/wget.py     | 26 +++++++++++++++++++++++-
 lib/bb/progress.py        | 31 ++++++++++++++++++++++++++++
 4 files changed, 106 insertions(+), 7 deletions(-)
lib/bb/fetch2/__init__.py +2 -2
index f612318..8ba00e0 100644
@@ -779,7 +779,7 @@ def localpath(url, d):
     fetcher = bb.fetch2.Fetch([url], d)
     return fetcher.localpath(url)
 
-def runfetchcmd(cmd, d, quiet=False, cleanup=None):
+def runfetchcmd(cmd, d, quiet=False, cleanup=None, log=None):
     """
     Run cmd returning the command output
     Raise an error if interrupted or cmd fails
@@ -820,7 +820,7 @@ def runfetchcmd(cmd, d, quiet=False, cleanup=None):
     error_message = ""
 
     try:
-        (output, errors) = bb.process.run(cmd, shell=True, stderr=subprocess.PIPE)
+        (output, errors) = bb.process.run(cmd, log=log, shell=True, stderr=subprocess.PIPE)
         success = True
     except bb.process.NotFoundError as e:
         error_message = "Fetch command %s" % (e.command)
lib/bb/fetch2/git.py +48 -4

79 lines not on this page · raw message

lib/bb/fetch2/wget.py +25 -1
index d688fd9..3a381b7 100644
@@ -31,6 +31,7 @@ import subprocess
 import os
 import logging
 import bb
+import bb.progress
 import urllib.request, urllib.parse, urllib.error
 from   bb import data
 from   bb.fetch2 import FetchMethod
@@ -41,6 +42,27 @@ from   bb.utils import export_proxies
 from   bs4 import BeautifulSoup
 from   bs4 import SoupStrainer
 
+class WgetProgressHandler(bb.progress.LineFilterProgressHandler):
+    """
+    Extract progress information from wget output.
+    Note: relies on --progress=dot --show-progress being specified on the
+    wget command line.
+    """
+    def __init__(self, d):
+        super(WgetProgressHandler, self).__init__(d)
+        # Send an initial progress event so the bar gets shown
+        self._fire_progress(0)
+
+    def writeline(self, line):
+        percs = re.findall(r'(\d+)%\s+([\d.]+[A-Z])', line)
+        if percs:
+            progress = int(percs[-1][0])
+            rate = percs[-1][1] + '/s'
+            self.update(progress, rate)
+            return False
+        return True
+
+
 class Wget(FetchMethod):
     """Class to fetch urls via 'wget'"""
     def supports(self, ud, d):
@@ -70,9 +92,11 @@ class Wget(FetchMethod):
 
     def _runwget(self, ud, d, command, quiet):
 
+        progresshandler = WgetProgressHandler(d)
+
         logger.debug(2, "Fetching %s using command '%s'" % (ud.url, command))
         bb.fetch2.check_network_access(d, command)
-        runfetchcmd(command, d, quiet)
+        runfetchcmd(command + ' --progress=dot --show-progress', d, quiet, log=progresshandler)
 
     def download(self, ud, d):
         """Fetch urls"""
lib/bb/progress.py +31 -0
index 7ee9f04..73e3f05 100644
@@ -58,6 +58,37 @@ class ProgressHandler(object):
             self._lastevent = ts
             self._progress = progress
 
+class LineFilterProgressHandler(ProgressHandler):
+    """
+    A ProgressHandler variant that provides the ability to filter out
+    the lines if they contain progress information. Additionally, it
+    filters out anything before the last line feed on a line. This can
+    be used to keep the logs clean of output that we've only enabled for
+    getting progress, assuming that that can be done on a per-line
+    basis.
+    """
+    def __init__(self, d, outfile=None):
+        self._linebuffer = ''
+        super(LineFilterProgressHandler, self).__init__(d, outfile)
+
+    def write(self, string):
+        self._linebuffer += string
+        while True:
+            breakpos = self._linebuffer.find('\n') + 1
+            if breakpos == 0:
+                break
+            line = self._linebuffer[:breakpos]
+            self._linebuffer = self._linebuffer[breakpos:]
+            # Drop any line feeds and anything that precedes them
+            lbreakpos = line.rfind('\r') + 1
+            if lbreakpos:
+                line = line[lbreakpos:]
+            if self.writeline(line):
+                super(LineFilterProgressHandler, self).write(line)
+
+    def writeline(self, line):
+        return True
+
 class BasicProgressHandler(ProgressHandler):
     def __init__(self, d, regex=r'(\d+)%', outfile=None):
         super(BasicProgressHandler, self).__init__(d, outfile)
Signature · 1 line
2.5.5
#8 lore raw

PATCH 6/10 knotty: add code to support showing progress for sstate object querying

In reply to Paul Eggleton

Add support code on the BitBake side to allow sstate.bbclass in OpenEmbedded to report progress when it is checking for availability of artifacts from shared state mirrors.

Part of the implementation for [YOCTO #5853].

---
 lib/bb/event.py     | 27 +++++++++++++++++++++++++++
 lib/bb/ui/knotty.py | 15 +++++++++++++--
 2 files changed, 40 insertions(+), 2 deletions(-)
lib/bb/event.py +27 -0
index 6fb3712..3485d73 100644
@@ -640,6 +640,33 @@ class MetadataEvent(Event):
         self.type = eventtype
         self._localdata = eventdata
 
+class ProcessStarted(Event):
+    """
+    Generic process started event (usually part of the initial startup)
+    where further progress events will be delivered
+    """
+    def __init__(self, processname, total):
+        Event.__init__(self)
+        self.processname = processname
+        self.total = total
+
+class ProcessProgress(Event):
+    """
+    Generic process progress event (usually part of the initial startup)
+    """
+    def __init__(self, processname, progress):
+        Event.__init__(self)
+        self.processname = processname
+        self.progress = progress
+
+class ProcessFinished(Event):
+    """
+    Generic process finished event (usually part of the initial startup)
+    """
+    def __init__(self, processname):
+        Event.__init__(self)
+        self.processname = processname
+
 class SanityCheck(Event):
     """
     Event to run sanity checks, either raise errors or generate events as return status.
lib/bb/ui/knotty.py +13 -2
index 2513501..6fdaafe 100644
@@ -90,7 +90,7 @@ class NonInteractiveProgress(object):
         self.msg = msg
         self.maxval = maxval
 
-    def start(self):
+    def start(self, update=True):
         self.fobj.write("%s..." % self.msg)
         self.fobj.flush()
         return self
@@ -304,7 +304,7 @@ _evt_list = [ "bb.runqueue.runQueueExitWait", "bb.event.LogExecTTY", "logging.Lo
               "bb.event.MultipleProviders", "bb.event.NoProvider", "bb.runqueue.sceneQueueTaskStarted",
               "bb.runqueue.runQueueTaskStarted", "bb.runqueue.runQueueTaskFailed", "bb.runqueue.sceneQueueTaskFailed",
               "bb.event.BuildBase", "bb.build.TaskStarted", "bb.build.TaskSucceeded", "bb.build.TaskFailedSilent",
-              "bb.build.TaskProgress"]
+              "bb.build.TaskProgress", "bb.event.ProcessStarted", "bb.event.ProcessProgress", "bb.event.ProcessFinished"]
 
 def main(server, eventHandler, params, tf = TerminalFilter):
 
@@ -579,6 +579,17 @@ def main(server, eventHandler, params, tf = TerminalFilter):
             if isinstance(event, bb.event.DepTreeGenerated):
                 continue
 
+            if isinstance(event, bb.event.ProcessStarted):
+                parseprogress = new_progress(event.processname, event.total)
+                parseprogress.start(False)
+                continue
+            if isinstance(event, bb.event.ProcessProgress):
+                parseprogress.update(event.progress)
+                continue
+            if isinstance(event, bb.event.ProcessFinished):
+                parseprogress.finish()
+                continue
+
             # ignore
             if isinstance(event, (bb.event.BuildBase,
                                   bb.event.MetadataEvent,
Signature · 1 line
2.5.5
#9 lore raw

PATCH 7/10 knotty: show task progress bar

In reply to Paul Eggleton

In addition to the "currently running n tasks (x of y)" message, show a progress bar for another view on how much of the build is left. We have to take care to reset it when moving from the scenequeue to the runqueue, and explicitly don't include an ETA since not all tasks take equal time and thus it isn't possible to estimate the time remaining with the information available.

---
 lib/bb/ui/knotty.py | 23 +++++++++++++++++++----
 1 file changed, 19 insertions(+), 4 deletions(-)
lib/bb/ui/knotty.py +19 -4
index 6fdaafe..c245c22 100644
@@ -89,6 +89,7 @@ class NonInteractiveProgress(object):
     def __init__(self, msg, maxval):
         self.msg = msg
         self.maxval = maxval
+        self.finished = False
 
     def start(self, update=True):
         self.fobj.write("%s..." % self.msg)
@@ -99,8 +100,11 @@ class NonInteractiveProgress(object):
         pass
 
     def finish(self):
+        if self.finished:
+            return
         self.fobj.write("done.\n")
         self.fobj.flush()
+        self.finished = True
 
 def new_progress(msg, maxval):
     if interactive:
@@ -204,6 +208,8 @@ class TerminalFilter(object):
         console.addFilter(InteractConsoleLogFilter(self, format))
         errconsole.addFilter(InteractConsoleLogFilter(self, format))
 
+        self.main_progress = None
+
     def clearFooter(self):
         if self.footer_present:
             lines = self.footer_present
@@ -246,11 +252,20 @@ class TerminalFilter(object):
 
         if self.main.shutdown:
             content = "Waiting for %s running tasks to finish:" % len(activetasks)
-        elif not len(activetasks):
-            content = "No currently running tasks (%s of %s)" % (self.helper.tasknumber_current, self.helper.tasknumber_total)
+            print(content)
         else:
-            content = "Currently %s running tasks (%s of %s):" % (len(activetasks), self.helper.tasknumber_current, self.helper.tasknumber_total)
-        print(content)
+            if not len(activetasks):
+                content = "No currently running tasks (%s of %s)" % (self.helper.tasknumber_current, self.helper.tasknumber_total)
+            else:
+                content = "Currently %2s running tasks (%s of %s)" % (len(activetasks), self.helper.tasknumber_current, self.helper.tasknumber_total)
+            maxtask = self.helper.tasknumber_total + 1
+            if not self.main_progress or self.main_progress.maxval != maxtask:
+                widgets = [' ', progressbar.Percentage(), ' ', progressbar.Bar()]
+                self.main_progress = BBProgress("Running tasks", maxtask, widgets=widgets)
+                self.main_progress.start(False)
+            self.main_progress.setmessage(content)
+            self.main_progress.update(self.helper.tasknumber_current)
+            print('')
         lines = 1 + int(len(content) / (self.columns + 1))
         for tasknum, task in enumerate(tasks[:(self.rows - 2)]):
             if isinstance(task, tuple):
Signature · 1 line
2.5.5
#10 lore raw

PATCH 8/10 knotty: add quiet output mode

In reply to Paul Eggleton

Quiet output mode disables printing most messages (below warnings) to the console; however these messages still go to the console log file. This is primarily for cases where bitbake is being launched interactively from some other process, but where full console output is not needed.

Because of the need to keep logging all normal events to the console log, this functionality was implemented within the knotty UI rather than in bb.msg (where verbose mode is implemented). We don't currently have a means of registering command line options from the UI end, thus the option actually has to be registered in main.py regardless of the UI, however I didn't feel like it was worth setting up such a mechanism just for this option.

---
 lib/bb/main.py      |  9 +++++++++
 lib/bb/msg.py       |  5 ++++-
 lib/bb/ui/knotty.py | 57 ++++++++++++++++++++++++++++++-----------------------
 3 files changed, 45 insertions(+), 26 deletions(-)
lib/bb/main.py +9 -0
index 283f29b..3fc3ff5 100755
@@ -179,6 +179,9 @@ class BitBakeConfigParameters(cookerdata.ConfigParameters):
         parser.add_option("-D", "--debug", action="count", dest="debug", default=0,
                           help="Increase the debug level. You can specify this more than once.")
 
+        parser.add_option("-q", "--quiet", action="store_true", dest="quiet", default=False,
+                          help="Output less log message data to the terminal.")
+
         parser.add_option("-n", "--dry-run", action="store_true", dest="dry_run", default=False,
                           help="Don't execute, just go through the motions.")
 
@@ -279,6 +282,12 @@ class BitBakeConfigParameters(cookerdata.ConfigParameters):
 
         options, targets = parser.parse_args(argv)
 
+        if options.quiet and options.verbose:
+            parser.error("options --quiet and --verbose are mutually exclusive")
+
+        if options.quiet and options.debug:
+            parser.error("options --quiet and --debug are mutually exclusive")
+
         # use configuration files from environment variables
         if "BBPRECONF" in os.environ:
             options.prefile.append(os.environ["BBPRECONF"])
lib/bb/msg.py +4 -1
index 8c3ab47..b7c39fa 100644
@@ -182,9 +182,12 @@ def constructLogOptions():
         debug_domains["BitBake.%s" % domainarg] = logging.DEBUG - dlevel + 1
     return level, debug_domains
 
-def addDefaultlogFilter(handler, cls = BBLogFilter):
+def addDefaultlogFilter(handler, cls = BBLogFilter, forcelevel=None):
     level, debug_domains = constructLogOptions()
 
+    if forcelevel is not None:
+        level = forcelevel
+
     cls(handler, level, debug_domains)
 
 #
lib/bb/ui/knotty.py +32 -25

106 lines not on this page · raw message

Signature · 1 line
2.5.5
#11 lore raw

PATCH 9/10 runqueue: add ability to enforce that tasks are setscened

In reply to Paul Eggleton

Add the ability to enter a mode where only a specified whitelist of tasks can be executed outright; everything else must be successfully provided in the form of a setscene task (or covered by a setscene task). Any setscene failure outside of the whitelist will cause the build to fail immediately instead of running the real task, and any real tasks that would execute outside of the whitelist cause an immediate build failure when it comes to executing the runqueue as well.

The mode is enabled by setting BB_SETSCENE_ENFORCE="1", and the whitelist is specified through BB_SETSCENE_ENFORCE_WHITELIST, consisting of pn:taskname pairs. A single % character can be substituted for the pn value to match any target explicitly specified on the bitbake command line. Wildcards * and ? can also be used as per standard unix file name matching for both pn and taskname.

Part of the implementation of [YOCTO #9367].

---
 lib/bb/runqueue.py | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 65 insertions(+), 1 deletion(-)
lib/bb/runqueue.py +65 -1
index 376c9f5..c68a3fe 100644
@@ -224,6 +224,7 @@ class RunQueueData:
 
         self.stampwhitelist = cfgData.getVar("BB_STAMP_WHITELIST", True) or ""
         self.multi_provider_whitelist = (cfgData.getVar("MULTI_PROVIDER_WHITELIST", True) or "").split()
+        self.setscenewhitelist = get_setscene_enforce_whitelist(cfgData)
 
         self.reset()
 
@@ -1629,8 +1630,35 @@ class RunQueueExecuteTasks(RunQueueExecute):
         Run the tasks in a queue prepared by rqdata.prepare()
         """
 
+        if self.rqdata.setscenewhitelist:
+            # Check tasks that are going to run against the whitelist
+            unexpected = False
+            for taskid in range(len(self.rqdata.runq_fnid)):
+                fn = self.rqdata.taskData.fn_index[self.rqdata.runq_fnid[taskid]]
+                taskname = self.rqdata.runq_task[taskid]
+                # Ignore covered tasks
+                if taskid in self.rq.scenequeue_covered:
+                    continue
+                # Ignore stamped tasks
+                if self.rq.check_stamp_task(taskid, taskname, cache=self.stampcache):
+                    continue
+                # Ignore noexec tasks
+                taskdep = self.rqdata.dataCache.task_deps[fn]
+                if 'noexec' in taskdep and taskname in taskdep['noexec']:
+                    continue
+
+                pn = self.rqdata.dataCache.pkg_fn[fn]
+                if not check_setscene_enforce_whitelist(pn, taskname, self.rqdata.setscenewhitelist):
+                    unexpected = True
+                    if taskid in self.rqdata.runq_setscene:
+                        logger.error('Task %s.%s attempted to execute unexpectedly and should have been setscened' % (pn, taskname))
+                    else:
+                        logger.error('Task %s.%s attempted to execute unexpectedly' % (pn, taskname))
+            if unexpected:
+                self.rq.state = runQueueCleanUp
+                return True
+
         self.rq.read_workers()
-        
 
         if self.stats.total == 0:
             # nothing to do
@@ -1982,6 +2010,16 @@ class RunQueueExecuteScenequeue(RunQueueExecute):
         self.scenequeue_covered.add(task)
         self.scenequeue_updatecounters(task)
 
+    def check_taskfail(self, task):
+        if self.rqdata.setscenewhitelist:
+            realtask = self.rqdata.runq_setscene[task]
+            fn = self.rqdata.taskData.fn_index[self.rqdata.runq_fnid[realtask]]
+            pn = self.rqdata.dataCache.pkg_fn[fn]
+            taskname = self.rqdata.runq_task[realtask]
+            if not check_setscene_enforce_whitelist(pn, taskname, self.rqdata.setscenewhitelist):
+                logger.error('Task %s.%s failed' % (pn, taskname + "_setscene"))
+                self.rq.state = runQueueCleanUp
+
     def task_complete(self, task):
         self.stats.taskCompleted()
         bb.event.fire(sceneQueueTaskCompleted(task, self.stats, self.rq), self.cfgData)
@@ -1992,6 +2030,7 @@ class RunQueueExecuteScenequeue(RunQueueExecute):
         bb.event.fire(sceneQueueTaskFailed(task, self.stats, result, self), self.cfgData)
         self.scenequeue_notcovered.add(task)
         self.scenequeue_updatecounters(task, True)
+        self.check_taskfail(task)
 
     def task_failoutright(self, task):
         self.runq_running[task] = 1
@@ -2001,6 +2040,7 @@ class RunQueueExecuteScenequeue(RunQueueExecute):
         index = self.rqdata.runq_setscene[task]
         self.scenequeue_notcovered.add(task)
         self.scenequeue_updatecounters(task, True)
+        self.check_taskfail(task)
 
     def task_skip(self, task):
         self.runq_running[task] = 1
@@ -2282,3 +2322,27 @@ class runQueuePipe():
         if len(self.queue) > 0:
             print("Warning, worker left partial message: %s" % self.queue)
         self.input.close()
+
+def get_setscene_enforce_whitelist(d):
+    if d.getVar('BB_SETSCENE_ENFORCE', True) != '1':
+        return None
+    whitelist = (d.getVar("BB_SETSCENE_ENFORCE_WHITELIST", True) or "").split()
+    outlist = []
+    for item in whitelist[:]:
+        if item.startswith('%:'):
+            for target in sys.argv[1:]:
+                if not target.startswith('-'):
+                    outlist.append(target.split(':')[0] + ':' + item.split(':')[1])
+        else:
+            outlist.append(item)
+    return outlist
+
+def check_setscene_enforce_whitelist(pn, taskname, whitelist):
+    import fnmatch
+    if whitelist:
+        item = '%s:%s' % (pn, taskname)
+        for whitelist_item in whitelist:
+            if fnmatch.fnmatch(item, whitelist_item):
+                return True
+        return False
+    return True
Signature · 1 line
2.5.5
#12 lore raw

PATCH 10/10 runqueue: report progress for "Preparing RunQueue" step

In reply to Paul Eggleton

When "Preparing RunQueue" shows up you can expect to wait up to 30 seconds while it works - which is a bit long to leave the user waiting without any kind of output. Since the work being carried out during this time is divided into stages such that it's practical to determine internally how it's progressing, replace the message with a progress bar.

Actually what happens during this time is two major steps rather than just one - the runqueue preparation itself, followed by the initialisation prior to running setscene tasks. I elected to have the progress bar cover both as one (there doesn't appear to be much point in doing otherwise from a user perspective). I did however describe it as "initialising tasks".

---
 lib/bb/progress.py | 42 +++++++++++++++++++++++++++++++++++
 lib/bb/runqueue.py | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 105 insertions(+), 2 deletions(-)
lib/bb/progress.py +42 -0
index 73e3f05..46574dd 100644
@@ -222,3 +222,45 @@ class MultiStageProgressReporter(object):
                 else:
                     out.append('Up to finish: %d' % stage_weight)
             bb.warn('Stage times:\n  %s' % '\n  '.join(out))
+
+class MultiStageProcessProgressReporter(MultiStageProgressReporter):
+    """
+    Version of MultiStageProgressReporter intended for use with
+    standalone processes (such as preparing the runqueue)
+    """
+    def __init__(self, d, processname, stage_weights, debug=False):
+        self._processname = processname
+        MultiStageProgressReporter.__init__(self, d, stage_weights, debug)
+
+    def start(self):
+        bb.event.fire(bb.event.ProcessStarted(self._processname, 100), self._data)
+
+    def _fire_progress(self, taskprogress):
+        bb.event.fire(bb.event.ProcessProgress(self._processname, taskprogress), self._data)
+
+    def finish(self):
+        MultiStageProgressReporter.finish(self)
+        bb.event.fire(bb.event.ProcessFinished(self._processname), self._data)
+
+class DummyMultiStageProcessProgressReporter(MultiStageProgressReporter):
+    """
+    MultiStageProcessProgressReporter that takes the calls and does nothing
+    with them (to avoid a bunch of "if progress_reporter:" checks)
+    """
+    def __init__(self):
+        MultiStageProcessProgressReporter.__init__(self, "", None, [])
+
+    def _fire_progress(self, taskprogress, rate=None):
+        pass
+
+    def start(self):
+        pass
+
+    def next_stage(self, stage_total=None):
+        pass
+
+    def update(self, stage_progress):
+        pass
+
+    def finish(self):
+        pass
lib/bb/runqueue.py +63 -2

256 lines not on this page · raw message

Signature · 1 line
2.5.5
#13 lore raw

Re: [PATCH 10/10] runqueue: report progress for "Preparing RunQueue" step

lib/bb/runqueue.py class RunQueue: · line 1161

Quoted 13 lines · Paul Eggleton
lib/bb/runqueue.py +4 -0
@@ -1119,14 +1150,19 @@ class RunQueue:
 
         if self.state is runQueuePrepare:
             self.rqexe = RunQueueExecuteDummy(self)
+            self.rqdata.init_progress_reporter = bb.progress.MultiStageProcessProgressReporter(self.cooker.data,
+                                                            "Initialising tasks",
+                                                            [27, 870, 3, 33, 1, 3, 3, 2, 3, 6, 1, 13, 1, 1, 132, 32, 1, 61, 1, 13, 2, 243, 151, 299, 81, 1, 15, 72])
             if self.rqdata.prepare() == 0:
                 self.state = runQueueComplete
             else:
                 self.state = runQueueSceneInit
+                self.rqdata.init_progress_reporter.next_stage()
 

I appreciate the difficulty in figuring some of this out and the changes look quite neat on the most part. I am however very worried by the above from a code maintenance standpoint.

If for example I add or remove a step in runqueue, how do I know where in this array to make a change? How do I calculate what the new weighting should be?

I did wonder if next_stage() should pass the number instead, that way at least the call site would be clearer. It doesn't solve the problem of knowing how many steps there are, or what these weights mean or how to recalculate them in the future.

Any thoughts on that?

Cheers,

Richard

#14 lore raw

Re: [PATCH 10/10] runqueue: report progress for "Preparing RunQueue" step

Quoted 23 lines · On Mon, 13 Jun 2016 12:09:33 Richard Purdie wrote:
Quoted 13 lines · Paul Eggleton
lib/bb/runqueue.py +1 -0
@@ -1119,14 +1150,19 @@ class RunQueue:
         if self.state is runQueuePrepare:
             self.rqexe = RunQueueExecuteDummy(self)
 
+            self.rqdata.init_progress_reporter =

bb.progress.MultiStageProcessProgressReporter(self.cooker.data, +
"Initialising tasks",
+ [27, 870, 3,
33, 1, 3, 3, 2, 3, 6, 1, 13, 1, 1, 132, 32, 1, 61, 1, 13, 2, 243, 151, 299, 81, 1, 15, 72])>
if self.rqdata.prepare() == 0:
self.state = runQueueComplete

Quoted 4 lines

else:
self.state = runQueueSceneInit

+ self.rqdata.init_progress_reporter.next_stage()

I appreciate the difficulty in figuring some of this out and the changes look quite neat on the most part. I am however very worried by the above from a code maintenance standpoint.

Quoted 3 lines

If for example I add or remove a step in runqueue, how do I know where in this array to make a change? How do I calculate what the new weighting should be?

Actually with the current patchset it's pretty easy. Just temporarily specify debug=True to the reporter when constructing and it will print out the list of weightings (based on timing each stage) when finish() is called, along with a map of the weightings to the lines where next_stage() was called. (Perhaps if we'd want a comment to that effect for anyone editing this code.)

Quoted 4 lines

I did wonder if next_stage() should pass the number instead, that way at least the call site would be clearer. It doesn't solve the problem of knowing how many steps there are, or what these weights mean or how to recalculate them in the future.

I guess you could do it that way; in the way I'd structured the code earlier it wouldn't have been practical but now that next_stage() must be called before every stage, it could be done. The trouble though is that then if you want to set them all at once (as you often would, since they are relative) you will have to go to each line and update it instead of just changing the list passed to the constructor, so I'm not convinced that's an improvement.

Cheers,
Paul

Signature · 2 lines
Paul Eggleton
Intel Open Source Technology Centre
#15 lore raw

Re: [PATCH 10/10] runqueue: report progress for "Preparing RunQueue" step

Quoted 34 lines · Paul Eggleton
Quoted 28 lines · On Mon, 13 Jun 2016 12:09:33 Richard Purdie wrote:
Quoted 17 lines · Paul Eggleton
lib/bb/runqueue.py +1 -0
@@ -1119,14 +1150,19 @@ class RunQueue:
         if self.state is runQueuePrepare:
             self.rqexe = RunQueueExecuteDummy(self)
 
+            self.rqdata.init_progress_reporter =

bb.progress.MultiStageProcessProgressReporter(self.cooker.data, +

"Initialising
tasks",
+ [27,
870, 3,
33, 1, 3, 3, 2, 3, 6, 1, 13, 1, 1, 132, 32, 1, 61, 1, 13, 2, 243, 151,
299, 81, 1, 15, 72])>
if self.rqdata.prepare() == 0:
self.state = runQueueComplete

Quoted 4 lines

else:
self.state = runQueueSceneInit

+ self.rqdata.init_progress_reporter.next_stage()

I appreciate the difficulty in figuring some of this out and the changes look quite neat on the most part. I am however very worried by
the above from a code maintenance standpoint.

Quoted 4 lines

If for example I add or remove a step in runqueue, how do I know where
in this array to make a change? How do I calculate what the new weighting should be?

Quoted 9 lines

Actually with the current patchset it's pretty easy. Just temporarily specify
debug=True to the reporter when constructing and it will print out the list of
weightings (based on timing each stage) when finish() is called, along with a
map of the weightings to the lines where next_stage() was called. (Perhaps if
we'd want a comment to that effect for anyone editing this code.)

I think a comment in there about this would be helpful as it isn't clear how to handle this. What does it do in the case you have a next() call without a weight? Will that give a warning?

Cheers,

Richard

#16 lore raw

Re: [PATCH 10/10] runqueue: report progress for "Preparing RunQueue" step

Quoted 47 lines · On Wed, 15 Jun 2016 22:46:41 Richard Purdie wrote:
Quoted 36 lines · Paul Eggleton
Quoted 30 lines · On Mon, 13 Jun 2016 12:09:33 Richard Purdie wrote:
Quoted 16 lines · Paul Eggleton
lib/bb/runqueue.py +1 -0
@@ -1119,14 +1150,19 @@ class RunQueue:
         if self.state is runQueuePrepare:
             self.rqexe = RunQueueExecuteDummy(self)
 
+            self.rqdata.init_progress_reporter =

bb.progress.MultiStageProcessProgressReporter(self.cooker.data, +

"Initialising

tasks",
+ [27,
870, 3,
33, 1, 3, 3, 2, 3, 6, 1, 13, 1, 1, 132, 32, 1, 61, 1, 13, 2, 243, 151,
299, 81, 1, 15, 72])>

Quoted 7 lines

if self.rqdata.prepare() == 0:
self.state = runQueueComplete

else:
self.state = runQueueSceneInit

+ self.rqdata.init_progress_reporter.next_stage()

I appreciate the difficulty in figuring some of this out and the changes look quite neat on the most part. I am however very worried by
the above from a code maintenance standpoint.

Quoted 4 lines

If for example I add or remove a step in runqueue, how do I know where
in this array to make a change? How do I calculate what the new weighting should be?

Quoted 9 lines

Actually with the current patchset it's pretty easy. Just temporarily specify
debug=True to the reporter when constructing and it will print out the list of
weightings (based on timing each stage) when finish() is called, along with a
map of the weightings to the lines where next_stage() was called. (Perhaps if
we'd want a comment to that effect for anyone editing this code.)

Quoted 2 lines

I think a comment in there about this would be helpful as it isn't clear how to handle this.

OK, I'll add one - I need to rebase this patchset anyway.

Quoted 2 lines

What does it do in the case you have a next()
call without a weight? Will that give a warning?

It will yes.

Cheers,
Paul

Signature · 2 lines
Paul Eggleton
Intel Open Source Technology Centre
#6 lore raw

Re: [PATCH 05/10] fetch2: implement progress support

In reply to Paul Eggleton
Quoted 3 lines · Paul Eggleton

+ runfetchcmd(command + ' --progress=dot --show-progress', d,
quiet, log=progresshandler)

wget: unrecognized option '--show-progress'

Turns out wget on Ubuntu 14.04 (wget 1.15) doesn't support this option.

Ross

#7 lore raw

Re: [PATCH 05/10] fetch2: implement progress support

Quoted 9 lines · Ross

On 13 June 2016 at 03:52, Paul Eggleton <[email protected]>

Quoted 2 lines · wrote:

+ runfetchcmd(command + ' --progress=dot --show-progress', d,
quiet, log=progresshandler)

wget: unrecognized option '--show-progress'

Turns out wget on Ubuntu 14.04 (wget 1.15) doesn't support this option.

Turns out it was introduced in 1.16. Sigh...

I will try to figure out what we can do with this. Worst case I suppose we could run wget once to determine the version and just disable progress reporting if it's too old.

Cheers,
Paul

Signature · 2 lines
Paul Eggleton
Intel Open Source Technology Centre