Skip to contentSkip to conversation

Show close matches for invalid task/target

PATCH In review Paul Eggleton 2 participants 5 messages Aug 13, 2013

lore
Share & tools
lore
#0 lore raw

cover Show close matches for invalid task/target

The following changes (against poky, but apply cleanly with -p2 against bitbake master) are available in the git repository at:

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

Paul Eggleton (2):
runqueue: report close matches for an invalid task name
taskdata: report close matches with NoProvider errors

 bitbake/lib/bb/event.py                  |  3 ++-
 bitbake/lib/bb/runqueue.py               |  6 +++++-
 bitbake/lib/bb/taskdata.py               | 13 ++++++++++++-
 bitbake/lib/bb/ui/crumbs/runningbuild.py | 10 ++++++++--
 bitbake/lib/bb/ui/knotty.py              |  9 +++++++--
 5 files changed, 34 insertions(+), 7 deletions(-)
Signature · 1 line
1.8.1.2
#1 lore raw

PATCH 1/2 runqueue: report close matches for an invalid task name

Help to pick up mistakes such as "bitbake -c cleanstate xyz" (instead of "bitbake -c cleansstate xyz".)

---
 bitbake/lib/bb/runqueue.py | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)
bitbake/lib/bb/runqueue.py +5 -1
index b2c9703..b3374f1 100644
@@ -601,7 +601,11 @@ class RunQueueData:
                 continue
 
             if target[1] not in taskData.tasks_lookup[fnid]:
-                bb.msg.fatal("RunQueue", "Task %s does not exist for target %s" % (target[1], target[0]))
+                import difflib
+                close_matches = difflib.get_close_matches(target[1], taskData.tasks_lookup[fnid], cutoff=0.7)
+                if close_matches:
+                    extra = ". Close matches:\n  %s" % "\n  ".join(close_matches)
+                bb.msg.fatal("RunQueue", "Task %s does not exist for target %s%s" % (target[1], target[0], extra))
 
             listid = taskData.tasks_lookup[fnid][target[1]]
 
Signature · 1 line
1.8.1.2
#2 lore raw

Re: [PATCH 1/2] runqueue: report close matches for an invalid task name

Quoted 13 lines · Paul Eggleton

Help to pick up mistakes such as "bitbake -c cleanstate xyz" (instead of "bitbake -c cleansstate xyz".)

---
 bitbake/lib/bb/runqueue.py | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)
bitbake/lib/bb/runqueue.py +0 -0
index b2c9703..b3374f1 100644

bitbake/lib/bb/runqueue.py class RunQueueData: · line 608

Quoted 9 lines
bitbake/lib/bb/runqueue.py +5 -1
@@ -601,7 +601,11 @@ class RunQueueData:
                 continue
 
             if target[1] not in taskData.tasks_lookup[fnid]:
-                bb.msg.fatal("RunQueue", "Task %s does not exist for target %s" % (target[1], target[0]))
+                import difflib
+                close_matches = difflib.get_close_matches(target[1], taskData.tasks_lookup[fnid], cutoff=0.7)
+                if close_matches:
+                    extra = ". Close matches:\n  %s" % "\n  ".join(close_matches)
+                bb.msg.fatal("RunQueue", "Task %s does not exist for target %s%s" % (target[1], target[0], extra))

Missing else: extra = ""?

Cheers,

Richard

#3 lore raw

Re: [PATCH 1/2] runqueue: report close matches for an invalid task name

Quoted 18 lines · On Tuesday 13 August 2013 21:18:18 Richard Purdie wrote:
Quoted 17 lines · Paul Eggleton

Help to pick up mistakes such as "bitbake -c cleanstate xyz" (instead of "bitbake -c cleansstate xyz".)

---

 bitbake/lib/bb/runqueue.py | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)
bitbake/lib/bb/runqueue.py +0 -0
index b2c9703..b3374f1 100644
@@ -601,7 +601,11 @@ class RunQueueData:
                 continue
 
Quoted 10 lines
Quoted 9 lines
bitbake/lib/bb/runqueue.py +0 -1
             if target[1] not in taskData.tasks_lookup[fnid]:
-                bb.msg.fatal("RunQueue", "Task %s does not exist for

target %s" % (target[1], target[0])) + import difflib
+ close_matches = difflib.get_close_matches(target[1],
taskData.tasks_lookup[fnid], cutoff=0.7) + if
close_matches:
+ extra = ". Close matches:\n %s" % "\n
".join(close_matches) + bb.msg.fatal("RunQueue", "Task %s
does not exist for target %s%s" % (target[1], target[0], extra))

Missing else: extra = ""?

Oops. Fixed on the branch.

Thanks,
Paul

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

PATCH 2/2 taskdata: report close matches with NoProvider errors

In reply to Paul Eggleton

Assuming there is no known reason why an item is not provided, show close matches on the assumption that it might have been a typo or other mistake.

---
 bitbake/lib/bb/event.py                  |  3 ++-
 bitbake/lib/bb/taskdata.py               | 13 ++++++++++++-
 bitbake/lib/bb/ui/crumbs/runningbuild.py | 10 ++++++++--
 bitbake/lib/bb/ui/knotty.py              |  9 +++++++--
 4 files changed, 29 insertions(+), 6 deletions(-)
bitbake/lib/bb/event.py +2 -1
index 9c134ee..ba25d38 100644
@@ -341,12 +341,13 @@ class DiskFull(Event):
 class NoProvider(Event):
     """No Provider for an Event"""
 
-    def __init__(self, item, runtime=False, dependees=None, reasons=[]):
+    def __init__(self, item, runtime=False, dependees=None, reasons=[], close_matches=[]):
         Event.__init__(self)
         self._item = item
         self._runtime = runtime
         self._dependees = dependees
         self._reasons = reasons
+        self._close_matches = close_matches
 
     def getItem(self):
         return self._item
bitbake/lib/bb/taskdata.py +12 -1
index c08186a..58fe199 100644
@@ -390,6 +390,17 @@ class TaskData:
                     reasons.append("%s PROVIDES %s but was skipped: %s" % (skipitem.pn, item, skipitem.skipreason))
         return reasons
 
+    def get_close_matches(self, item, provider_list):
+        import difflib
+        if self.skiplist:
+            skipped = []
+            for fn in self.skiplist:
+                skipped.append(self.skiplist[fn].pn)
+            full_list = provider_list + skipped
+        else:
+            full_list = provider_list
+        return difflib.get_close_matches(item, full_list, cutoff=0.7)
+
     def add_provider(self, cfgData, dataCache, item):
         try:
             self.add_provider_internal(cfgData, dataCache, item)
@@ -411,7 +422,7 @@ class TaskData:
             return
 
         if not item in dataCache.providers:
-            bb.event.fire(bb.event.NoProvider(item, dependees=self.get_dependees_str(item), reasons=self.get_reasons(item)), cfgData)
+            bb.event.fire(bb.event.NoProvider(item, dependees=self.get_dependees_str(item), reasons=self.get_reasons(item), close_matches=self.get_close_matches(item, dataCache.providers.keys())), cfgData)
             raise bb.providers.NoProvider(item)
 
         if self.have_build_target(item):
bitbake/lib/bb/ui/crumbs/runningbuild.py +8 -2
index 78fa141..abd3300 100644
@@ -375,10 +375,16 @@ class RunningBuild (gobject.GObject):
                 r = "R"
             else:
                 r = ""
+
+            extra = ''
+            if not event._reasons:
+                if event._close_matches:
+                    extra = ". Close matches:\n  %s" % '\n  '.join(event._close_matches)
+
             if event._dependees:
-                msg = "Nothing %sPROVIDES '%s' (but %s %sDEPENDS on or otherwise requires it)\n" % (r, event._item, ", ".join(event._dependees), r)
+                msg = "Nothing %sPROVIDES '%s' (but %s %sDEPENDS on or otherwise requires it)%s\n" % (r, event._item, ", ".join(event._dependees), r, extra)
             else:
-                msg = "Nothing %sPROVIDES '%s'\n" % (r, event._item)
+                msg = "Nothing %sPROVIDES '%s'%s\n" % (r, event._item, extra)
             if event._reasons:
                 for reason in event._reasons:
                     msg += ("%s\n" % reason)
bitbake/lib/bb/ui/knotty.py +7 -2
index 2c8293d..09ad99e 100644
@@ -416,10 +416,15 @@ def main(server, eventHandler, params, tf = TerminalFilter):
                 else:
                     r = ""
 
+                extra = ''
+                if not event._reasons:
+                    if event._close_matches:
+                        extra = ". Close matches:\n  %s" % '\n  '.join(event._close_matches)
+
                 if event._dependees:
-                    logger.error("Nothing %sPROVIDES '%s' (but %s %sDEPENDS on or otherwise requires it)", r, event._item, ", ".join(event._dependees), r)
+                    logger.error("Nothing %sPROVIDES '%s' (but %s %sDEPENDS on or otherwise requires it)%s", r, event._item, ", ".join(event._dependees), r, extra)
                 else:
-                    logger.error("Nothing %sPROVIDES '%s'", r, event._item)
+                    logger.error("Nothing %sPROVIDES '%s'%s", r, event._item, extra)
                 if event._reasons:
                     for reason in event._reasons:
                         logger.error("%s", reason)
Signature · 1 line
1.8.1.2