diff --git a/bin/euscan b/bin/euscan index dfdedca..907902a 100755 --- a/bin/euscan +++ b/bin/euscan @@ -19,6 +19,7 @@ __description__ = "A tool to detect new upstream releases." # Imports import sys +import os import getopt import errno import httplib @@ -32,6 +33,7 @@ from gentoolkit.errors import GentoolkitException from euscan import CONFIG, output from euscan.scan import scan_upstream +from euscan.out import progress_bar # Globals @@ -233,13 +235,21 @@ def main(): if CONFIG['verbose'] > 2: httplib.HTTPConnection.debuglevel = 1 + isatty = os.environ.get('TERM') != 'dumb' and sys.stdout.isatty() + for query in queries: + on_progress = None + if (CONFIG['format'] or CONFIG['quiet']) and isatty: + print("%s:" % query, file=sys.stderr) + on_progress_gen = progress_bar() + on_progress = on_progress_gen.next() + ret = [] output.set_query(query) try: - ret = scan_upstream(query) + ret = scan_upstream(query, on_progress) except AmbiguousPackageName as e: pkgs = e.args[0] output.eerror("\n".join(pkgs)) @@ -264,10 +274,18 @@ def main(): if not CONFIG['quiet'] and not CONFIG['format']: print() + if (CONFIG['format'] or CONFIG['quiet']) and isatty: + on_progress_gen.next() + print("\n", file=sys.stderr) + if ret is not None: if len(ret) > 0: for cp, url, version, handler, confidence in ret: output.result(cp, version, url, handler, confidence) + + if (CONFIG['format'] or CONFIG['quiet']) and isatty: + print("\n", file=sys.stderr) + elif not CONFIG['quiet']: output.ewarn( "Didn't find any new version, check package's homepage " + diff --git a/pym/euscan/out.py b/pym/euscan/out.py index a6f5147..c569a89 100644 --- a/pym/euscan/out.py +++ b/pym/euscan/out.py @@ -1,9 +1,55 @@ from io import StringIO from collections import defaultdict import json +import signal +import time from gentoolkit import pprinter as pp -from portage.output import EOutput +import portage +from portage.output import EOutput, TermProgressBar + + +class ProgressHandler(object): + def __init__(self): + self.curval = 0 + self.maxval = 0 + self.last_update = 0 + self.min_display_latency = 0.2 + + def on_progress(self, maxval, curval): + self.maxval = maxval + self.curval = curval + cur_time = time.time() + if cur_time - self.last_update >= self.min_display_latency: + self.last_update = cur_time + self.display() + + def display(self): + raise NotImplementedError(self) + + +def progress_bar(): + on_progress = None + progress_bar = TermProgressBar() + + progress_handler = ProgressHandler() + on_progress = progress_handler.on_progress + + def display(): + progress_bar.set(progress_handler.curval, progress_handler.maxval) + progress_handler.display = display + + def sigwinch_handler(signum, frame): + lines, progress_bar.term_columns = portage.output.get_term_size() + signal.signal(signal.SIGWINCH, sigwinch_handler) + + yield on_progress + + # make sure the final progress is displayed + progress_handler.display() + signal.signal(signal.SIGWINCH, signal.SIG_DFL) + + yield None class EOutputMem(EOutput): @@ -87,5 +133,8 @@ class EuscanOutput(object): print "%s: %s" % (key.capitalize(), value) def __getattr__(self, key): - output = self.queries[self.current_query]["output"] - return getattr(output, key) + if not self.config["quiet"]: + output = self.queries[self.current_query]["output"] + return getattr(output, key) + else: + return lambda *x: None diff --git a/pym/euscan/scan.py b/pym/euscan/scan.py index a73bf76..0b8f4ad 100644 --- a/pym/euscan/scan.py +++ b/pym/euscan/scan.py @@ -13,7 +13,6 @@ from euscan import CONFIG, BLACKLIST_PACKAGES from euscan import handlers, helpers, output from euscan.ebuild import package_from_ebuild -import euscan def filter_versions(cp, versions): filtered = {} @@ -41,10 +40,17 @@ def filter_versions(cp, versions): ] -def scan_upstream_urls(cpv, urls): +def scan_upstream_urls(cpv, urls, on_progress): versions = [] + maxval = len(urls) + 5 + curval = 1 + for filename in urls: + curval += 1 + if on_progress: + on_progress(maxval, curval) + for url in urls[filename]: if not CONFIG['quiet'] and not CONFIG['format']: pp.uprint() @@ -69,7 +75,19 @@ def scan_upstream_urls(cpv, urls): break cp, ver, rev = portage.pkgsplit(cpv) - return filter_versions(cp, versions) + + curval += 1 + if on_progress: + on_progress(maxval, curval) + + result = filter_versions(cp, versions) + + curval += 1 + if on_progress: + on_progress(maxval, curval) + + return result + # gentoolkit stores PORTDB, so even if we modify it to add an overlay # it will still use the old dbapi @@ -83,7 +101,15 @@ def reload_gentoolkit(): if hasattr(gentoolkit.query, 'PORTDB'): gentoolkit.query.PORTDB = PORTDB -def scan_upstream(query): + +def scan_upstream(query, on_progress=None): + """ + Scans the upstream searching new versions for the given query + """ + + maxval = 3 + curval = 0 + matches = [] if query.endswith(".ebuild"): @@ -122,6 +148,10 @@ def scan_upstream(query): output.metadata("cp", pkg.cp, show=False) output.metadata("cpv", pkg.cpv, show=False) + curval += 1 + if on_progress: + on_progress(maxval, curval) + if pkg.cp in BLACKLIST_PACKAGES: output.ewarn( pp.warn("Package '%s' is blacklisted" % pp.pkgquery(pkg.cp)) @@ -172,4 +202,14 @@ def scan_upstream(query): scan_time = (datetime.now() - start_time).total_seconds() output.metadata("scan_time", scan_time, show=False) - return scan_upstream_urls(pkg.cpv, urls) + curval += 1 + if on_progress: + on_progress(maxval, curval) + + result = scan_upstream_urls(pkg.cpv, urls, on_progress) + + curval += 1 + if on_progress: + on_progress(maxval, curval) + + return result