diff options
| -rw-r--r-- | bitbake/lib/bb/fetch2/__init__.py | 4 | ||||
| -rw-r--r-- | bitbake/lib/bb/fetch2/git.py | 52 | ||||
| -rw-r--r-- | bitbake/lib/bb/fetch2/wget.py | 28 | ||||
| -rw-r--r-- | bitbake/lib/bb/progress.py | 31 |
4 files changed, 107 insertions, 8 deletions
diff --git a/bitbake/lib/bb/fetch2/__init__.py b/bitbake/lib/bb/fetch2/__init__.py index b6fcaaad55..a27512cc87 100644 --- a/bitbake/lib/bb/fetch2/__init__.py +++ b/bitbake/lib/bb/fetch2/__init__.py | |||
| @@ -779,7 +779,7 @@ def localpath(url, d): | |||
| 779 | fetcher = bb.fetch2.Fetch([url], d) | 779 | fetcher = bb.fetch2.Fetch([url], d) |
| 780 | return fetcher.localpath(url) | 780 | return fetcher.localpath(url) |
| 781 | 781 | ||
| 782 | def runfetchcmd(cmd, d, quiet=False, cleanup=None): | 782 | def runfetchcmd(cmd, d, quiet=False, cleanup=None, log=None): |
| 783 | """ | 783 | """ |
| 784 | Run cmd returning the command output | 784 | Run cmd returning the command output |
| 785 | Raise an error if interrupted or cmd fails | 785 | Raise an error if interrupted or cmd fails |
| @@ -821,7 +821,7 @@ def runfetchcmd(cmd, d, quiet=False, cleanup=None): | |||
| 821 | error_message = "" | 821 | error_message = "" |
| 822 | 822 | ||
| 823 | try: | 823 | try: |
| 824 | (output, errors) = bb.process.run(cmd, shell=True, stderr=subprocess.PIPE) | 824 | (output, errors) = bb.process.run(cmd, log=log, shell=True, stderr=subprocess.PIPE) |
| 825 | success = True | 825 | success = True |
| 826 | except bb.process.NotFoundError as e: | 826 | except bb.process.NotFoundError as e: |
| 827 | error_message = "Fetch command %s" % (e.command) | 827 | error_message = "Fetch command %s" % (e.command) |
diff --git a/bitbake/lib/bb/fetch2/git.py b/bitbake/lib/bb/fetch2/git.py index 59827e304f..4e2dcec0d7 100644 --- a/bitbake/lib/bb/fetch2/git.py +++ b/bitbake/lib/bb/fetch2/git.py | |||
| @@ -71,11 +71,53 @@ import os | |||
| 71 | import re | 71 | import re |
| 72 | import bb | 72 | import bb |
| 73 | import errno | 73 | import errno |
| 74 | import bb.progress | ||
| 74 | from bb import data | 75 | from bb import data |
| 75 | from bb.fetch2 import FetchMethod | 76 | from bb.fetch2 import FetchMethod |
| 76 | from bb.fetch2 import runfetchcmd | 77 | from bb.fetch2 import runfetchcmd |
| 77 | from bb.fetch2 import logger | 78 | from bb.fetch2 import logger |
| 78 | 79 | ||
| 80 | |||
| 81 | class GitProgressHandler(bb.progress.LineFilterProgressHandler): | ||
| 82 | """Extract progress information from git output""" | ||
| 83 | def __init__(self, d): | ||
| 84 | self._buffer = '' | ||
| 85 | self._count = 0 | ||
| 86 | super(GitProgressHandler, self).__init__(d) | ||
| 87 | # Send an initial progress event so the bar gets shown | ||
| 88 | self._fire_progress(-1) | ||
| 89 | |||
| 90 | def write(self, string): | ||
| 91 | self._buffer += string | ||
| 92 | stages = ['Counting objects', 'Compressing objects', 'Receiving objects', 'Resolving deltas'] | ||
| 93 | stage_weights = [0.2, 0.05, 0.5, 0.25] | ||
| 94 | stagenum = 0 | ||
| 95 | for i, stage in reversed(list(enumerate(stages))): | ||
| 96 | if stage in self._buffer: | ||
| 97 | stagenum = i | ||
| 98 | self._buffer = '' | ||
| 99 | break | ||
| 100 | self._status = stages[stagenum] | ||
| 101 | percs = re.findall(r'(\d+)%', string) | ||
| 102 | if percs: | ||
| 103 | progress = int(round((int(percs[-1]) * stage_weights[stagenum]) + (sum(stage_weights[:stagenum]) * 100))) | ||
| 104 | rates = re.findall(r'([\d.]+ [a-zA-Z]*/s+)', string) | ||
| 105 | if rates: | ||
| 106 | rate = rates[-1] | ||
| 107 | else: | ||
| 108 | rate = None | ||
| 109 | self.update(progress, rate) | ||
| 110 | else: | ||
| 111 | if stagenum == 0: | ||
| 112 | percs = re.findall(r': (\d+)', string) | ||
| 113 | if percs: | ||
| 114 | count = int(percs[-1]) | ||
| 115 | if count > self._count: | ||
| 116 | self._count = count | ||
| 117 | self._fire_progress(-count) | ||
| 118 | super(GitProgressHandler, self).write(string) | ||
| 119 | |||
| 120 | |||
| 79 | class Git(FetchMethod): | 121 | class Git(FetchMethod): |
| 80 | """Class to fetch a module or modules from git repositories""" | 122 | """Class to fetch a module or modules from git repositories""" |
| 81 | def init(self, d): | 123 | def init(self, d): |
| @@ -196,10 +238,11 @@ class Git(FetchMethod): | |||
| 196 | # We do this since git will use a "-l" option automatically for local urls where possible | 238 | # We do this since git will use a "-l" option automatically for local urls where possible |
| 197 | if repourl.startswith("file://"): | 239 | if repourl.startswith("file://"): |
| 198 | repourl = repourl[7:] | 240 | repourl = repourl[7:] |
| 199 | clone_cmd = "%s clone --bare --mirror %s %s" % (ud.basecmd, repourl, ud.clonedir) | 241 | clone_cmd = "LANG=C %s clone --bare --mirror %s %s --progress" % (ud.basecmd, repourl, ud.clonedir) |
| 200 | if ud.proto.lower() != 'file': | 242 | if ud.proto.lower() != 'file': |
| 201 | bb.fetch2.check_network_access(d, clone_cmd) | 243 | bb.fetch2.check_network_access(d, clone_cmd) |
| 202 | runfetchcmd(clone_cmd, d) | 244 | progresshandler = GitProgressHandler(d) |
| 245 | runfetchcmd(clone_cmd, d, log=progresshandler) | ||
| 203 | 246 | ||
| 204 | os.chdir(ud.clonedir) | 247 | os.chdir(ud.clonedir) |
| 205 | # Update the checkout if needed | 248 | # Update the checkout if needed |
| @@ -214,10 +257,11 @@ class Git(FetchMethod): | |||
| 214 | logger.debug(1, "No Origin") | 257 | logger.debug(1, "No Origin") |
| 215 | 258 | ||
| 216 | runfetchcmd("%s remote add --mirror=fetch origin %s" % (ud.basecmd, repourl), d) | 259 | runfetchcmd("%s remote add --mirror=fetch origin %s" % (ud.basecmd, repourl), d) |
| 217 | fetch_cmd = "%s fetch -f --prune %s refs/*:refs/*" % (ud.basecmd, repourl) | 260 | fetch_cmd = "LANG=C %s fetch -f --prune --progress %s refs/*:refs/*" % (ud.basecmd, repourl) |
| 218 | if ud.proto.lower() != 'file': | 261 | if ud.proto.lower() != 'file': |
| 219 | bb.fetch2.check_network_access(d, fetch_cmd, ud.url) | 262 | bb.fetch2.check_network_access(d, fetch_cmd, ud.url) |
| 220 | runfetchcmd(fetch_cmd, d) | 263 | progresshandler = GitProgressHandler(d) |
| 264 | runfetchcmd(fetch_cmd, d, log=progresshandler) | ||
| 221 | runfetchcmd("%s prune-packed" % ud.basecmd, d) | 265 | runfetchcmd("%s prune-packed" % ud.basecmd, d) |
| 222 | runfetchcmd("%s pack-redundant --all | xargs -r rm" % ud.basecmd, d) | 266 | runfetchcmd("%s pack-redundant --all | xargs -r rm" % ud.basecmd, d) |
| 223 | try: | 267 | try: |
diff --git a/bitbake/lib/bb/fetch2/wget.py b/bitbake/lib/bb/fetch2/wget.py index 6cb22aeee9..6b60d9b16b 100644 --- a/bitbake/lib/bb/fetch2/wget.py +++ b/bitbake/lib/bb/fetch2/wget.py | |||
| @@ -31,6 +31,7 @@ import subprocess | |||
| 31 | import os | 31 | import os |
| 32 | import logging | 32 | import logging |
| 33 | import bb | 33 | import bb |
| 34 | import bb.progress | ||
| 34 | import urllib.request, urllib.parse, urllib.error | 35 | import urllib.request, urllib.parse, urllib.error |
| 35 | from bb import data | 36 | from bb import data |
| 36 | from bb.fetch2 import FetchMethod | 37 | from bb.fetch2 import FetchMethod |
| @@ -41,6 +42,27 @@ from bb.utils import export_proxies | |||
| 41 | from bs4 import BeautifulSoup | 42 | from bs4 import BeautifulSoup |
| 42 | from bs4 import SoupStrainer | 43 | from bs4 import SoupStrainer |
| 43 | 44 | ||
| 45 | class WgetProgressHandler(bb.progress.LineFilterProgressHandler): | ||
| 46 | """ | ||
| 47 | Extract progress information from wget output. | ||
| 48 | Note: relies on --progress=dot (with -v or without -q/-nv) being | ||
| 49 | specified on the wget command line. | ||
| 50 | """ | ||
| 51 | def __init__(self, d): | ||
| 52 | super(WgetProgressHandler, self).__init__(d) | ||
| 53 | # Send an initial progress event so the bar gets shown | ||
| 54 | self._fire_progress(0) | ||
| 55 | |||
| 56 | def writeline(self, line): | ||
| 57 | percs = re.findall(r'(\d+)%\s+([\d.]+[A-Z])', line) | ||
| 58 | if percs: | ||
| 59 | progress = int(percs[-1][0]) | ||
| 60 | rate = percs[-1][1] + '/s' | ||
| 61 | self.update(progress, rate) | ||
| 62 | return False | ||
| 63 | return True | ||
| 64 | |||
| 65 | |||
| 44 | class Wget(FetchMethod): | 66 | class Wget(FetchMethod): |
| 45 | """Class to fetch urls via 'wget'""" | 67 | """Class to fetch urls via 'wget'""" |
| 46 | def supports(self, ud, d): | 68 | def supports(self, ud, d): |
| @@ -66,13 +88,15 @@ class Wget(FetchMethod): | |||
| 66 | if not ud.localfile: | 88 | if not ud.localfile: |
| 67 | ud.localfile = data.expand(urllib.parse.unquote(ud.host + ud.path).replace("/", "."), d) | 89 | ud.localfile = data.expand(urllib.parse.unquote(ud.host + ud.path).replace("/", "."), d) |
| 68 | 90 | ||
| 69 | self.basecmd = d.getVar("FETCHCMD_wget", True) or "/usr/bin/env wget -t 2 -T 30 -nv --passive-ftp --no-check-certificate" | 91 | self.basecmd = d.getVar("FETCHCMD_wget", True) or "/usr/bin/env wget -t 2 -T 30 --passive-ftp --no-check-certificate" |
| 70 | 92 | ||
| 71 | def _runwget(self, ud, d, command, quiet): | 93 | def _runwget(self, ud, d, command, quiet): |
| 72 | 94 | ||
| 95 | progresshandler = WgetProgressHandler(d) | ||
| 96 | |||
| 73 | logger.debug(2, "Fetching %s using command '%s'" % (ud.url, command)) | 97 | logger.debug(2, "Fetching %s using command '%s'" % (ud.url, command)) |
| 74 | bb.fetch2.check_network_access(d, command) | 98 | bb.fetch2.check_network_access(d, command) |
| 75 | runfetchcmd(command, d, quiet) | 99 | runfetchcmd(command + ' --progress=dot -v', d, quiet, log=progresshandler) |
| 76 | 100 | ||
| 77 | def download(self, ud, d): | 101 | def download(self, ud, d): |
| 78 | """Fetch urls""" | 102 | """Fetch urls""" |
diff --git a/bitbake/lib/bb/progress.py b/bitbake/lib/bb/progress.py index ee6b9536b8..343b18f8c4 100644 --- a/bitbake/lib/bb/progress.py +++ b/bitbake/lib/bb/progress.py | |||
| @@ -58,6 +58,37 @@ class ProgressHandler(object): | |||
| 58 | self._lastevent = ts | 58 | self._lastevent = ts |
| 59 | self._progress = progress | 59 | self._progress = progress |
| 60 | 60 | ||
| 61 | class LineFilterProgressHandler(ProgressHandler): | ||
| 62 | """ | ||
| 63 | A ProgressHandler variant that provides the ability to filter out | ||
| 64 | the lines if they contain progress information. Additionally, it | ||
| 65 | filters out anything before the last line feed on a line. This can | ||
| 66 | be used to keep the logs clean of output that we've only enabled for | ||
| 67 | getting progress, assuming that that can be done on a per-line | ||
| 68 | basis. | ||
| 69 | """ | ||
| 70 | def __init__(self, d, outfile=None): | ||
| 71 | self._linebuffer = '' | ||
| 72 | super(LineFilterProgressHandler, self).__init__(d, outfile) | ||
| 73 | |||
| 74 | def write(self, string): | ||
| 75 | self._linebuffer += string | ||
| 76 | while True: | ||
| 77 | breakpos = self._linebuffer.find('\n') + 1 | ||
| 78 | if breakpos == 0: | ||
| 79 | break | ||
| 80 | line = self._linebuffer[:breakpos] | ||
| 81 | self._linebuffer = self._linebuffer[breakpos:] | ||
| 82 | # Drop any line feeds and anything that precedes them | ||
| 83 | lbreakpos = line.rfind('\r') + 1 | ||
| 84 | if lbreakpos: | ||
| 85 | line = line[lbreakpos:] | ||
| 86 | if self.writeline(line): | ||
| 87 | super(LineFilterProgressHandler, self).write(line) | ||
| 88 | |||
| 89 | def writeline(self, line): | ||
| 90 | return True | ||
| 91 | |||
| 61 | class BasicProgressHandler(ProgressHandler): | 92 | class BasicProgressHandler(ProgressHandler): |
| 62 | def __init__(self, d, regex=r'(\d+)%', outfile=None): | 93 | def __init__(self, d, regex=r'(\d+)%', outfile=None): |
| 63 | super(BasicProgressHandler, self).__init__(d, outfile) | 94 | super(BasicProgressHandler, self).__init__(d, outfile) |
