Skip to content

Commit 14e0e84

Browse files
authored
Merge pull request #593 from screamerbg/feature_progress
UX: Add progress bar for both Git and Mercurial when using non-verbose mode
2 parents b5d264c + 2ef6c31 commit 14e0e84

File tree

1 file changed

+57
-4
lines changed

1 file changed

+57
-4
lines changed

mbed/mbed.py

Lines changed: 57 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,15 @@ def progress():
177177
sys.stdout.flush()
178178
sys.stdout.write('\b')
179179

180+
def show_progress(title, percent, max_width=80):
181+
percent = round(float(percent), 2)
182+
show_percent = '%.2f' % percent
183+
bwidth = max_width - len(str(title)) - len(show_percent) - 6 # 6 equals the spaces and paddings between title, progress bar and percentage
184+
sys.stdout.write('%s |%s%s| %s%%\r' % (str(title), '#' * int(percent * bwidth // 100), '-' * (bwidth - int(percent * bwidth // 100)), show_percent))
185+
sys.stdout.flush()
186+
187+
def hide_progress(max_width=80):
188+
sys.stdout.write("\r%s\r" % (' ' * max_width))
180189

181190
# Process execution
182191
class ProcessException(Exception):
@@ -198,11 +207,11 @@ def popen(command, stdin=None, **kwargs):
198207
if proc.wait() != 0:
199208
raise ProcessException(proc.returncode, command[0], ' '.join(command), getcwd())
200209

201-
def pquery(command, stdin=None, **kwargs):
210+
def pquery(command, output_callback=None, stdin=None, **kwargs):
202211
if very_verbose:
203212
info('Query "'+' '.join(command)+'" in '+getcwd())
204213
try:
205-
proc = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, **kwargs)
214+
proc = subprocess.Popen(command, bufsize=0, stdout=subprocess.PIPE, stderr=subprocess.PIPE, **kwargs)
206215
except OSError as e:
207216
if e[0] == errno.ENOENT:
208217
error(
@@ -211,6 +220,20 @@ def pquery(command, stdin=None, **kwargs):
211220
else:
212221
raise e
213222

223+
if output_callback:
224+
line = ""
225+
while 1:
226+
s = str(proc.stderr.read(1))
227+
line += s
228+
if s == '\r' or s == '\n':
229+
output_callback(line, s)
230+
line = ""
231+
232+
if proc.returncode is None:
233+
code = proc.poll()
234+
else:
235+
break
236+
214237
stdout, _ = proc.communicate(stdin)
215238

216239
if very_verbose:
@@ -413,7 +436,11 @@ def cleanup():
413436
return True
414437

415438
def clone(url, name=None, depth=None, protocol=None):
416-
popen([hg_cmd, 'clone', formaturl(url, protocol), name] + (['-v'] if very_verbose else ([] if verbose else ['-q'])))
439+
if verbose or very_verbose:
440+
popen([hg_cmd, 'clone', formaturl(url, protocol), name] + (['-v'] if very_verbose else ([] if verbose else ['-q'])))
441+
else:
442+
pquery([hg_cmd, 'clone', '--config', 'progress.assume-tty=true', formaturl(url, protocol), name], output_callback=Hg.action_progress)
443+
hide_progress()
417444

418445
def add(dest):
419446
info("Adding reference \"%s\"" % dest)
@@ -601,6 +628,15 @@ def unignore(dest):
601628
except IOError:
602629
error("Unable to write ignore file in \"%s\"" % os.path.join(getcwd(), Hg.ignore_file), 1)
603630

631+
def action_progress(line, sep):
632+
m = re.match(r'(\w+).+?\s+(\d+)/(\d+)\s+.*?', line)
633+
if m:
634+
if m.group(1) == "manifests":
635+
show_progress('Downloading', (float(m.group(2)) / float(m.group(3))) * 20)
636+
if m.group(1) == "files":
637+
show_progress('Downloading', (float(m.group(2)) / float(m.group(3))) * 100)
638+
639+
604640
# pylint: disable=no-self-argument, no-method-argument, no-member, no-self-use, unused-argument
605641
@scm('git')
606642
@staticclass
@@ -634,7 +670,11 @@ def cleanup():
634670
pquery([git_cmd, 'branch', '-D', branch])
635671

636672
def clone(url, name=None, depth=None, protocol=None):
637-
popen([git_cmd, 'clone', formaturl(url, protocol), name] + (['--depth', depth] if depth else []) + (['-v'] if very_verbose else ([] if verbose else ['-q'])))
673+
if verbose or very_verbose:
674+
popen([git_cmd, 'clone', formaturl(url, protocol), name] + (['--depth', depth] if depth else []) + (['-v'] if very_verbose else ([] if verbose else ['-q'])))
675+
else:
676+
pquery([git_cmd, 'clone', '--progress', formaturl(url, protocol), name] + (['--depth', depth] if depth else []), output_callback=Git.action_progress)
677+
hide_progress()
638678

639679
def add(dest):
640680
info("Adding reference "+dest)
@@ -900,6 +940,19 @@ def unignore(dest):
900940
except IOError:
901941
error("Unable to write ignore file in \"%s\"" % os.path.join(getcwd(), Git.ignore_file), 1)
902942

943+
def action_progress(line, sep):
944+
m = re.match(r'([\w :]+)\:\s*(\d+)% \((\d+)/(\d+)\)', line)
945+
if m:
946+
if m.group(1) == "remote: Compressing objects" and int(m.group(4)) > 100:
947+
show_progress('Preparing', (float(m.group(3)) / float(m.group(4))) * 100)
948+
if m.group(1) == "Receiving objects":
949+
show_progress('Downloading', (float(m.group(3)) / float(m.group(4))) * 80)
950+
if m.group(1) == "Resolving deltas":
951+
show_progress('Downloading', (float(m.group(3)) / float(m.group(4))) * 10 + 80)
952+
if m.group(1) == "Checking out files":
953+
show_progress('Downloading', (float(m.group(3)) / float(m.group(4))) * 10 + 90)
954+
955+
903956
# Repository object
904957
class Repo(object):
905958
is_local = False

0 commit comments

Comments
 (0)