mirror of
https://git.yoctoproject.org/poky
synced 2026-04-25 15:32:13 +02:00
Add bitbake-dev to allow ease of testing and development of bitbake trunk
git-svn-id: https://svn.o-hand.com/repos/poky/trunk@5337 311d38ba-8fff-0310-9ca6-ca027cbcb966
This commit is contained in:
18
bitbake-dev/lib/bb/ui/__init__.py
Normal file
18
bitbake-dev/lib/bb/ui/__init__.py
Normal file
@@ -0,0 +1,18 @@
|
||||
#
|
||||
# BitBake UI Implementation
|
||||
#
|
||||
# Copyright (C) 2006-2007 Richard Purdie
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License version 2 as
|
||||
# published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
271
bitbake-dev/lib/bb/ui/depexplorer.py
Normal file
271
bitbake-dev/lib/bb/ui/depexplorer.py
Normal file
@@ -0,0 +1,271 @@
|
||||
#
|
||||
# BitBake Graphical GTK based Dependency Explorer
|
||||
#
|
||||
# Copyright (C) 2007 Ross Burton
|
||||
# Copyright (C) 2007 - 2008 Richard Purdie
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License version 2 as
|
||||
# published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
import gobject
|
||||
import gtk
|
||||
import threading
|
||||
|
||||
# Package Model
|
||||
(COL_PKG_NAME) = (0)
|
||||
|
||||
# Dependency Model
|
||||
(TYPE_DEP, TYPE_RDEP) = (0, 1)
|
||||
(COL_DEP_TYPE, COL_DEP_PARENT, COL_DEP_PACKAGE) = (0, 1, 2)
|
||||
|
||||
class PackageDepView(gtk.TreeView):
|
||||
def __init__(self, model, dep_type, label):
|
||||
gtk.TreeView.__init__(self)
|
||||
self.current = None
|
||||
self.dep_type = dep_type
|
||||
self.filter_model = model.filter_new()
|
||||
self.filter_model.set_visible_func(self._filter)
|
||||
self.set_model(self.filter_model)
|
||||
#self.connect("row-activated", self.on_package_activated, COL_DEP_PACKAGE)
|
||||
self.append_column(gtk.TreeViewColumn(label, gtk.CellRendererText(), text=COL_DEP_PACKAGE))
|
||||
|
||||
def _filter(self, model, iter):
|
||||
(this_type, package) = model.get(iter, COL_DEP_TYPE, COL_DEP_PARENT)
|
||||
if this_type != self.dep_type: return False
|
||||
return package == self.current
|
||||
|
||||
def set_current_package(self, package):
|
||||
self.current = package
|
||||
self.filter_model.refilter()
|
||||
|
||||
class PackageReverseDepView(gtk.TreeView):
|
||||
def __init__(self, model, label):
|
||||
gtk.TreeView.__init__(self)
|
||||
self.current = None
|
||||
self.filter_model = model.filter_new()
|
||||
self.filter_model.set_visible_func(self._filter)
|
||||
self.set_model(self.filter_model)
|
||||
self.append_column(gtk.TreeViewColumn(label, gtk.CellRendererText(), text=COL_DEP_PARENT))
|
||||
|
||||
def _filter(self, model, iter):
|
||||
package = model.get_value(iter, COL_DEP_PACKAGE)
|
||||
return package == self.current
|
||||
|
||||
def set_current_package(self, package):
|
||||
self.current = package
|
||||
self.filter_model.refilter()
|
||||
|
||||
class DepExplorer(gtk.Window):
|
||||
def __init__(self):
|
||||
gtk.Window.__init__(self)
|
||||
self.set_title("Dependency Explorer")
|
||||
self.set_default_size(500, 500)
|
||||
self.connect("delete-event", gtk.main_quit)
|
||||
|
||||
# Create the data models
|
||||
self.pkg_model = gtk.ListStore(gobject.TYPE_STRING)
|
||||
self.depends_model = gtk.ListStore(gobject.TYPE_INT, gobject.TYPE_STRING, gobject.TYPE_STRING)
|
||||
|
||||
pane = gtk.HPaned()
|
||||
pane.set_position(250)
|
||||
self.add(pane)
|
||||
|
||||
# The master list of packages
|
||||
scrolled = gtk.ScrolledWindow()
|
||||
scrolled.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
|
||||
scrolled.set_shadow_type(gtk.SHADOW_IN)
|
||||
self.pkg_treeview = gtk.TreeView(self.pkg_model)
|
||||
self.pkg_treeview.get_selection().connect("changed", self.on_cursor_changed)
|
||||
self.pkg_treeview.append_column(gtk.TreeViewColumn("Package", gtk.CellRendererText(), text=COL_PKG_NAME))
|
||||
pane.add1(scrolled)
|
||||
scrolled.add(self.pkg_treeview)
|
||||
|
||||
box = gtk.VBox(homogeneous=True, spacing=4)
|
||||
|
||||
# Runtime Depends
|
||||
scrolled = gtk.ScrolledWindow()
|
||||
scrolled.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
|
||||
scrolled.set_shadow_type(gtk.SHADOW_IN)
|
||||
self.rdep_treeview = PackageDepView(self.depends_model, TYPE_RDEP, "Runtime Depends")
|
||||
self.rdep_treeview.connect("row-activated", self.on_package_activated, COL_DEP_PACKAGE)
|
||||
scrolled.add(self.rdep_treeview)
|
||||
box.add(scrolled)
|
||||
|
||||
# Build Depends
|
||||
scrolled = gtk.ScrolledWindow()
|
||||
scrolled.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
|
||||
scrolled.set_shadow_type(gtk.SHADOW_IN)
|
||||
self.dep_treeview = PackageDepView(self.depends_model, TYPE_DEP, "Build Depends")
|
||||
self.dep_treeview.connect("row-activated", self.on_package_activated, COL_DEP_PACKAGE)
|
||||
scrolled.add(self.dep_treeview)
|
||||
box.add(scrolled)
|
||||
pane.add2(box)
|
||||
|
||||
# Reverse Depends
|
||||
scrolled = gtk.ScrolledWindow()
|
||||
scrolled.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
|
||||
scrolled.set_shadow_type(gtk.SHADOW_IN)
|
||||
self.revdep_treeview = PackageReverseDepView(self.depends_model, "Reverse Depends")
|
||||
self.revdep_treeview.connect("row-activated", self.on_package_activated, COL_DEP_PARENT)
|
||||
scrolled.add(self.revdep_treeview)
|
||||
box.add(scrolled)
|
||||
pane.add2(box)
|
||||
|
||||
self.show_all()
|
||||
|
||||
def on_package_activated(self, treeview, path, column, data_col):
|
||||
model = treeview.get_model()
|
||||
package = model.get_value(model.get_iter(path), data_col)
|
||||
|
||||
pkg_path = []
|
||||
def finder(model, path, iter, needle):
|
||||
package = model.get_value(iter, COL_PKG_NAME)
|
||||
if package == needle:
|
||||
pkg_path.append(path)
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
self.pkg_model.foreach(finder, package)
|
||||
if pkg_path:
|
||||
self.pkg_treeview.get_selection().select_path(pkg_path[0])
|
||||
self.pkg_treeview.scroll_to_cell(pkg_path[0])
|
||||
|
||||
def on_cursor_changed(self, selection):
|
||||
(model, it) = selection.get_selected()
|
||||
if iter is None:
|
||||
current_package = None
|
||||
else:
|
||||
current_package = model.get_value(it, COL_PKG_NAME)
|
||||
self.rdep_treeview.set_current_package(current_package)
|
||||
self.dep_treeview.set_current_package(current_package)
|
||||
self.revdep_treeview.set_current_package(current_package)
|
||||
|
||||
|
||||
def parse(depgraph, pkg_model, depends_model):
|
||||
|
||||
for package in depgraph["pn"]:
|
||||
pkg_model.set(pkg_model.append(), COL_PKG_NAME, package)
|
||||
|
||||
for package in depgraph["depends"]:
|
||||
for depend in depgraph["depends"][package]:
|
||||
depends_model.set (depends_model.append(),
|
||||
COL_DEP_TYPE, TYPE_DEP,
|
||||
COL_DEP_PARENT, package,
|
||||
COL_DEP_PACKAGE, depend)
|
||||
|
||||
for package in depgraph["rdepends-pn"]:
|
||||
for rdepend in depgraph["rdepends-pn"][package]:
|
||||
depends_model.set (depends_model.append(),
|
||||
COL_DEP_TYPE, TYPE_RDEP,
|
||||
COL_DEP_PARENT, package,
|
||||
COL_DEP_PACKAGE, rdepend)
|
||||
|
||||
class ProgressBar(gtk.Window):
|
||||
def __init__(self):
|
||||
|
||||
gtk.Window.__init__(self)
|
||||
self.set_title("Parsing .bb files, please wait...")
|
||||
self.set_default_size(500, 0)
|
||||
self.connect("delete-event", gtk.main_quit)
|
||||
|
||||
self.progress = gtk.ProgressBar()
|
||||
self.add(self.progress)
|
||||
self.show_all()
|
||||
|
||||
class gtkthread(threading.Thread):
|
||||
quit = threading.Event()
|
||||
def __init__(self, shutdown):
|
||||
threading.Thread.__init__(self)
|
||||
self.setDaemon(True)
|
||||
self.shutdown = shutdown
|
||||
|
||||
def run(self):
|
||||
gobject.threads_init()
|
||||
gtk.gdk.threads_init()
|
||||
gtk.main()
|
||||
gtkthread.quit.set()
|
||||
|
||||
def init(server, eventHandler):
|
||||
|
||||
try:
|
||||
cmdline = server.runCommand(["getCmdLineAction"])
|
||||
if not cmdline or cmdline[0] != "generateDotGraph":
|
||||
print "This UI is only compatible with the -g option"
|
||||
return
|
||||
ret = server.runCommand(["generateDepTreeEvent", cmdline[1]])
|
||||
if ret != True:
|
||||
print "Couldn't run command! %s" % ret
|
||||
return
|
||||
except xmlrpclib.Fault, x:
|
||||
print "XMLRPC Fault getting commandline:\n %s" % x
|
||||
return
|
||||
|
||||
shutdown = 0
|
||||
|
||||
gtkgui = gtkthread(shutdown)
|
||||
gtkgui.start()
|
||||
|
||||
gtk.gdk.threads_enter()
|
||||
pbar = ProgressBar()
|
||||
dep = DepExplorer()
|
||||
gtk.gdk.threads_leave()
|
||||
|
||||
while True:
|
||||
try:
|
||||
event = eventHandler.waitEvent(0.25)
|
||||
if gtkthread.quit.isSet():
|
||||
break
|
||||
|
||||
if event is None:
|
||||
continue
|
||||
if event[0].startswith('bb.event.ParseProgress'):
|
||||
x = event[1]['sofar']
|
||||
y = event[1]['total']
|
||||
if x == y:
|
||||
print("\nParsing finished. %d cached, %d parsed, %d skipped, %d masked, %d errors."
|
||||
% ( event[1]['cached'], event[1]['parsed'], event[1]['skipped'], event[1]['masked'], event[1]['errors']))
|
||||
pbar.hide()
|
||||
gtk.gdk.threads_enter()
|
||||
pbar.progress.set_fraction(float(x)/float(y))
|
||||
pbar.progress.set_text("%d/%d (%2d %%)" % (x, y, x*100/y))
|
||||
gtk.gdk.threads_leave()
|
||||
continue
|
||||
|
||||
if event[0] == "bb.event.DepTreeGenerated":
|
||||
gtk.gdk.threads_enter()
|
||||
parse(event[1]['_depgraph'], dep.pkg_model, dep.depends_model)
|
||||
gtk.gdk.threads_leave()
|
||||
|
||||
if event[0] == 'bb.command.CookerCommandCompleted':
|
||||
continue
|
||||
if event[0] == 'bb.command.CookerCommandFailed':
|
||||
print "Command execution failed: %s" % event[1]['error']
|
||||
break
|
||||
if event[0] == 'bb.cooker.CookerExit':
|
||||
break
|
||||
|
||||
continue
|
||||
|
||||
except KeyboardInterrupt:
|
||||
if shutdown == 2:
|
||||
print "\nThird Keyboard Interrupt, exit.\n"
|
||||
break
|
||||
if shutdown == 1:
|
||||
print "\nSecond Keyboard Interrupt, stopping...\n"
|
||||
server.runCommand(["stateStop"])
|
||||
if shutdown == 0:
|
||||
print "\nKeyboard Interrupt, closing down...\n"
|
||||
server.runCommand(["stateShutdown"])
|
||||
shutdown = shutdown + 1
|
||||
pass
|
||||
|
||||
157
bitbake-dev/lib/bb/ui/knotty.py
Normal file
157
bitbake-dev/lib/bb/ui/knotty.py
Normal file
@@ -0,0 +1,157 @@
|
||||
#
|
||||
# BitBake (No)TTY UI Implementation
|
||||
#
|
||||
# Handling output to TTYs or files (no TTY)
|
||||
#
|
||||
# Copyright (C) 2006-2007 Richard Purdie
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License version 2 as
|
||||
# published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
import os
|
||||
import bb
|
||||
from bb import cooker
|
||||
|
||||
import sys
|
||||
import time
|
||||
import itertools
|
||||
import xmlrpclib
|
||||
|
||||
parsespin = itertools.cycle( r'|/-\\' )
|
||||
|
||||
def init(server, eventHandler):
|
||||
|
||||
# Get values of variables which control our output
|
||||
includelogs = server.runCommand(["readVariable", "BBINCLUDELOGS"])
|
||||
loglines = server.runCommand(["readVariable", "BBINCLUDELOGS_LINES"])
|
||||
|
||||
try:
|
||||
cmdline = server.runCommand(["getCmdLineAction"])
|
||||
#print cmdline
|
||||
if not cmdline:
|
||||
return 1
|
||||
ret = server.runCommand(cmdline)
|
||||
if ret != True:
|
||||
print "Couldn't get default commandline! %s" % ret
|
||||
return 1
|
||||
except xmlrpclib.Fault, x:
|
||||
print "XMLRPC Fault getting commandline:\n %s" % x
|
||||
return 1
|
||||
|
||||
shutdown = 0
|
||||
return_value = 0
|
||||
while True:
|
||||
try:
|
||||
event = eventHandler.waitEvent(0.25)
|
||||
if event is None:
|
||||
continue
|
||||
#print event
|
||||
if event[0].startswith('bb.event.Pkg'):
|
||||
print "NOTE: %s" % event[1]['_message']
|
||||
continue
|
||||
if event[0].startswith('bb.msg.MsgPlain'):
|
||||
print event[1]['_message']
|
||||
continue
|
||||
if event[0].startswith('bb.msg.MsgDebug'):
|
||||
print 'DEBUG: ' + event[1]['_message']
|
||||
continue
|
||||
if event[0].startswith('bb.msg.MsgNote'):
|
||||
print 'NOTE: ' + event[1]['_message']
|
||||
continue
|
||||
if event[0].startswith('bb.msg.MsgWarn'):
|
||||
print 'WARNING: ' + event[1]['_message']
|
||||
continue
|
||||
if event[0].startswith('bb.msg.MsgError'):
|
||||
return_value = 1
|
||||
print 'ERROR: ' + event[1]['_message']
|
||||
continue
|
||||
if event[0].startswith('bb.build.TaskFailed'):
|
||||
return_value = 1
|
||||
logfile = event[1]['logfile']
|
||||
if logfile:
|
||||
print "ERROR: Logfile of failure stored in %s." % logfile
|
||||
if includelogs:
|
||||
print "Log data follows:"
|
||||
f = open(logfile, "r")
|
||||
lines = []
|
||||
while True:
|
||||
l = f.readline()
|
||||
if l == '':
|
||||
break
|
||||
l = l.rstrip()
|
||||
if loglines:
|
||||
lines.append(' | %s' % l)
|
||||
if len(lines) > int(loglines):
|
||||
lines.pop(0)
|
||||
else:
|
||||
print '| %s' % l
|
||||
f.close()
|
||||
if lines:
|
||||
for line in lines:
|
||||
print line
|
||||
if event[0].startswith('bb.build.Task'):
|
||||
print "NOTE: %s" % event[1]['_message']
|
||||
continue
|
||||
if event[0].startswith('bb.event.ParseProgress'):
|
||||
x = event[1]['sofar']
|
||||
y = event[1]['total']
|
||||
if os.isatty(sys.stdout.fileno()):
|
||||
sys.stdout.write("\rNOTE: Handling BitBake files: %s (%04d/%04d) [%2d %%]" % ( parsespin.next(), x, y, x*100/y ) )
|
||||
sys.stdout.flush()
|
||||
else:
|
||||
if x == 1:
|
||||
sys.stdout.write("Parsing .bb files, please wait...")
|
||||
sys.stdout.flush()
|
||||
if x == y:
|
||||
sys.stdout.write("done.")
|
||||
sys.stdout.flush()
|
||||
if x == y:
|
||||
print("\nParsing finished. %d cached, %d parsed, %d skipped, %d masked, %d errors."
|
||||
% ( event[1]['cached'], event[1]['parsed'], event[1]['skipped'], event[1]['masked'], event[1]['errors']))
|
||||
continue
|
||||
|
||||
if event[0] == 'bb.command.CookerCommandCompleted':
|
||||
break
|
||||
if event[0] == 'bb.command.CookerCommandFailed':
|
||||
return_value = 1
|
||||
print "Command execution failed: %s" % event[1]['error']
|
||||
break
|
||||
if event[0] == 'bb.cooker.CookerExit':
|
||||
break
|
||||
|
||||
# ignore
|
||||
if event[0].startswith('bb.event.BuildStarted'):
|
||||
continue
|
||||
if event[0].startswith('bb.event.BuildCompleted'):
|
||||
continue
|
||||
if event[0].startswith('bb.event.MultipleProviders'):
|
||||
continue
|
||||
if event[0].startswith('bb.runqueue.runQueue'):
|
||||
continue
|
||||
if event[0].startswith('bb.event.StampUpdate'):
|
||||
continue
|
||||
print "Unknown Event: %s" % event
|
||||
|
||||
except KeyboardInterrupt:
|
||||
if shutdown == 2:
|
||||
print "\nThird Keyboard Interrupt, exit.\n"
|
||||
break
|
||||
if shutdown == 1:
|
||||
print "\nSecond Keyboard Interrupt, stopping...\n"
|
||||
server.runCommand(["stateStop"])
|
||||
if shutdown == 0:
|
||||
print "\nKeyboard Interrupt, closing down...\n"
|
||||
server.runCommand(["stateShutdown"])
|
||||
shutdown = shutdown + 1
|
||||
pass
|
||||
return return_value
|
||||
333
bitbake-dev/lib/bb/ui/ncurses.py
Normal file
333
bitbake-dev/lib/bb/ui/ncurses.py
Normal file
@@ -0,0 +1,333 @@
|
||||
#
|
||||
# BitBake Curses UI Implementation
|
||||
#
|
||||
# Implements an ncurses frontend for the BitBake utility.
|
||||
#
|
||||
# Copyright (C) 2006 Michael 'Mickey' Lauer
|
||||
# Copyright (C) 2006-2007 Richard Purdie
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License version 2 as
|
||||
# published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
"""
|
||||
We have the following windows:
|
||||
|
||||
1.) Main Window: Shows what we are ultimately building and how far we are. Includes status bar
|
||||
2.) Thread Activity Window: Shows one status line for every concurrent bitbake thread.
|
||||
3.) Command Line Window: Contains an interactive command line where you can interact w/ Bitbake.
|
||||
|
||||
Basic window layout is like that:
|
||||
|
||||
|---------------------------------------------------------|
|
||||
| <Main Window> | <Thread Activity Window> |
|
||||
| | 0: foo do_compile complete|
|
||||
| Building Gtk+-2.6.10 | 1: bar do_patch complete |
|
||||
| Status: 60% | ... |
|
||||
| | ... |
|
||||
| | ... |
|
||||
|---------------------------------------------------------|
|
||||
|<Command Line Window> |
|
||||
|>>> which virtual/kernel |
|
||||
|openzaurus-kernel |
|
||||
|>>> _ |
|
||||
|---------------------------------------------------------|
|
||||
|
||||
"""
|
||||
|
||||
import os, sys, curses, time, random, threading, itertools, time
|
||||
from curses.textpad import Textbox
|
||||
import bb
|
||||
from bb import ui
|
||||
from bb.ui import uihelper
|
||||
|
||||
parsespin = itertools.cycle( r'|/-\\' )
|
||||
|
||||
X = 0
|
||||
Y = 1
|
||||
WIDTH = 2
|
||||
HEIGHT = 3
|
||||
|
||||
MAXSTATUSLENGTH = 32
|
||||
|
||||
class NCursesUI:
|
||||
"""
|
||||
NCurses UI Class
|
||||
"""
|
||||
class Window:
|
||||
"""Base Window Class"""
|
||||
def __init__( self, x, y, width, height, fg=curses.COLOR_BLACK, bg=curses.COLOR_WHITE ):
|
||||
self.win = curses.newwin( height, width, y, x )
|
||||
self.dimensions = ( x, y, width, height )
|
||||
"""
|
||||
if curses.has_colors():
|
||||
color = 1
|
||||
curses.init_pair( color, fg, bg )
|
||||
self.win.bkgdset( ord(' '), curses.color_pair(color) )
|
||||
else:
|
||||
self.win.bkgdset( ord(' '), curses.A_BOLD )
|
||||
"""
|
||||
self.erase()
|
||||
self.setScrolling()
|
||||
self.win.noutrefresh()
|
||||
|
||||
def erase( self ):
|
||||
self.win.erase()
|
||||
|
||||
def setScrolling( self, b = True ):
|
||||
self.win.scrollok( b )
|
||||
self.win.idlok( b )
|
||||
|
||||
def setBoxed( self ):
|
||||
self.boxed = True
|
||||
self.win.box()
|
||||
self.win.noutrefresh()
|
||||
|
||||
def setText( self, x, y, text, *args ):
|
||||
self.win.addstr( y, x, text, *args )
|
||||
self.win.noutrefresh()
|
||||
|
||||
def appendText( self, text, *args ):
|
||||
self.win.addstr( text, *args )
|
||||
self.win.noutrefresh()
|
||||
|
||||
def drawHline( self, y ):
|
||||
self.win.hline( y, 0, curses.ACS_HLINE, self.dimensions[WIDTH] )
|
||||
self.win.noutrefresh()
|
||||
|
||||
class DecoratedWindow( Window ):
|
||||
"""Base class for windows with a box and a title bar"""
|
||||
def __init__( self, title, x, y, width, height, fg=curses.COLOR_BLACK, bg=curses.COLOR_WHITE ):
|
||||
NCursesUI.Window.__init__( self, x+1, y+3, width-2, height-4, fg, bg )
|
||||
self.decoration = NCursesUI.Window( x, y, width, height, fg, bg )
|
||||
self.decoration.setBoxed()
|
||||
self.decoration.win.hline( 2, 1, curses.ACS_HLINE, width-2 )
|
||||
self.setTitle( title )
|
||||
|
||||
def setTitle( self, title ):
|
||||
self.decoration.setText( 1, 1, title.center( self.dimensions[WIDTH]-2 ), curses.A_BOLD )
|
||||
|
||||
#-------------------------------------------------------------------------#
|
||||
# class TitleWindow( Window ):
|
||||
#-------------------------------------------------------------------------#
|
||||
# """Title Window"""
|
||||
# def __init__( self, x, y, width, height ):
|
||||
# NCursesUI.Window.__init__( self, x, y, width, height )
|
||||
# version = bb.__version__
|
||||
# title = "BitBake %s" % version
|
||||
# credit = "(C) 2003-2007 Team BitBake"
|
||||
# #self.win.hline( 2, 1, curses.ACS_HLINE, width-2 )
|
||||
# self.win.border()
|
||||
# self.setText( 1, 1, title.center( self.dimensions[WIDTH]-2 ), curses.A_BOLD )
|
||||
# self.setText( 1, 2, credit.center( self.dimensions[WIDTH]-2 ), curses.A_BOLD )
|
||||
|
||||
#-------------------------------------------------------------------------#
|
||||
class ThreadActivityWindow( DecoratedWindow ):
|
||||
#-------------------------------------------------------------------------#
|
||||
"""Thread Activity Window"""
|
||||
def __init__( self, x, y, width, height ):
|
||||
NCursesUI.DecoratedWindow.__init__( self, "Thread Activity", x, y, width, height )
|
||||
|
||||
def setStatus( self, thread, text ):
|
||||
line = "%02d: %s" % ( thread, text )
|
||||
width = self.dimensions[WIDTH]
|
||||
if ( len(line) > width ):
|
||||
line = line[:width-3] + "..."
|
||||
else:
|
||||
line = line.ljust( width )
|
||||
self.setText( 0, thread, line )
|
||||
|
||||
#-------------------------------------------------------------------------#
|
||||
class MainWindow( DecoratedWindow ):
|
||||
#-------------------------------------------------------------------------#
|
||||
"""Main Window"""
|
||||
def __init__( self, x, y, width, height ):
|
||||
self.StatusPosition = width - MAXSTATUSLENGTH
|
||||
NCursesUI.DecoratedWindow.__init__( self, None, x, y, width, height )
|
||||
curses.nl()
|
||||
|
||||
def setTitle( self, title ):
|
||||
title = "BitBake %s" % bb.__version__
|
||||
self.decoration.setText( 2, 1, title, curses.A_BOLD )
|
||||
self.decoration.setText( self.StatusPosition - 8, 1, "Status:", curses.A_BOLD )
|
||||
|
||||
def setStatus(self, status):
|
||||
while len(status) < MAXSTATUSLENGTH:
|
||||
status = status + " "
|
||||
self.decoration.setText( self.StatusPosition, 1, status, curses.A_BOLD )
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------#
|
||||
class ShellOutputWindow( DecoratedWindow ):
|
||||
#-------------------------------------------------------------------------#
|
||||
"""Interactive Command Line Output"""
|
||||
def __init__( self, x, y, width, height ):
|
||||
NCursesUI.DecoratedWindow.__init__( self, "Command Line Window", x, y, width, height )
|
||||
|
||||
#-------------------------------------------------------------------------#
|
||||
class ShellInputWindow( Window ):
|
||||
#-------------------------------------------------------------------------#
|
||||
"""Interactive Command Line Input"""
|
||||
def __init__( self, x, y, width, height ):
|
||||
NCursesUI.Window.__init__( self, x, y, width, height )
|
||||
|
||||
# self.textbox = Textbox( self.win )
|
||||
# t = threading.Thread()
|
||||
# t.run = self.textbox.edit
|
||||
# t.start()
|
||||
|
||||
#-------------------------------------------------------------------------#
|
||||
def main(self, stdscr, server, eventHandler):
|
||||
#-------------------------------------------------------------------------#
|
||||
height, width = stdscr.getmaxyx()
|
||||
|
||||
# for now split it like that:
|
||||
# MAIN_y + THREAD_y = 2/3 screen at the top
|
||||
# MAIN_x = 2/3 left, THREAD_y = 1/3 right
|
||||
# CLI_y = 1/3 of screen at the bottom
|
||||
# CLI_x = full
|
||||
|
||||
main_left = 0
|
||||
main_top = 0
|
||||
main_height = ( height / 3 * 2 )
|
||||
main_width = ( width / 3 ) * 2
|
||||
clo_left = main_left
|
||||
clo_top = main_top + main_height
|
||||
clo_height = height - main_height - main_top - 1
|
||||
clo_width = width
|
||||
cli_left = main_left
|
||||
cli_top = clo_top + clo_height
|
||||
cli_height = 1
|
||||
cli_width = width
|
||||
thread_left = main_left + main_width
|
||||
thread_top = main_top
|
||||
thread_height = main_height
|
||||
thread_width = width - main_width
|
||||
|
||||
#tw = self.TitleWindow( 0, 0, width, main_top )
|
||||
mw = self.MainWindow( main_left, main_top, main_width, main_height )
|
||||
taw = self.ThreadActivityWindow( thread_left, thread_top, thread_width, thread_height )
|
||||
clo = self.ShellOutputWindow( clo_left, clo_top, clo_width, clo_height )
|
||||
cli = self.ShellInputWindow( cli_left, cli_top, cli_width, cli_height )
|
||||
cli.setText( 0, 0, "BB>" )
|
||||
|
||||
mw.setStatus("Idle")
|
||||
|
||||
helper = uihelper.BBUIHelper()
|
||||
shutdown = 0
|
||||
|
||||
try:
|
||||
cmdline = server.runCommand(["getCmdLineAction"])
|
||||
if not cmdline:
|
||||
return
|
||||
ret = server.runCommand(cmdline)
|
||||
if ret != True:
|
||||
print "Couldn't get default commandlind! %s" % ret
|
||||
return
|
||||
except xmlrpclib.Fault, x:
|
||||
print "XMLRPC Fault getting commandline:\n %s" % x
|
||||
return
|
||||
|
||||
exitflag = False
|
||||
while not exitflag:
|
||||
try:
|
||||
event = eventHandler.waitEvent(0.25)
|
||||
if not event:
|
||||
continue
|
||||
helper.eventHandler(event)
|
||||
#mw.appendText("%s\n" % event[0])
|
||||
if event[0].startswith('bb.event.Pkg'):
|
||||
mw.appendText("NOTE: %s\n" % event[1]['_message'])
|
||||
if event[0].startswith('bb.build.Task'):
|
||||
mw.appendText("NOTE: %s\n" % event[1]['_message'])
|
||||
if event[0].startswith('bb.msg.MsgDebug'):
|
||||
mw.appendText('DEBUG: ' + event[1]['_message'] + '\n')
|
||||
if event[0].startswith('bb.msg.MsgNote'):
|
||||
mw.appendText('NOTE: ' + event[1]['_message'] + '\n')
|
||||
if event[0].startswith('bb.msg.MsgWarn'):
|
||||
mw.appendText('WARNING: ' + event[1]['_message'] + '\n')
|
||||
if event[0].startswith('bb.msg.MsgError'):
|
||||
mw.appendText('ERROR: ' + event[1]['_message'] + '\n')
|
||||
if event[0].startswith('bb.msg.MsgFatal'):
|
||||
mw.appendText('FATAL: ' + event[1]['_message'] + '\n')
|
||||
if event[0].startswith('bb.event.ParseProgress'):
|
||||
x = event[1]['sofar']
|
||||
y = event[1]['total']
|
||||
if x == y:
|
||||
mw.setStatus("Idle")
|
||||
mw.appendText("Parsing finished. %d cached, %d parsed, %d skipped, %d masked."
|
||||
% ( event[1]['cached'], event[1]['parsed'], event[1]['skipped'], event[1]['masked'] ))
|
||||
else:
|
||||
mw.setStatus("Parsing: %s (%04d/%04d) [%2d %%]" % ( parsespin.next(), x, y, x*100/y ) )
|
||||
# if event[0].startswith('bb.build.TaskFailed'):
|
||||
# if event[1]['logfile']:
|
||||
# if data.getVar("BBINCLUDELOGS", d):
|
||||
# bb.msg.error(bb.msg.domain.Build, "log data follows (%s)" % logfile)
|
||||
# number_of_lines = data.getVar("BBINCLUDELOGS_LINES", d)
|
||||
# if number_of_lines:
|
||||
# os.system('tail -n%s %s' % (number_of_lines, logfile))
|
||||
# else:
|
||||
# f = open(logfile, "r")
|
||||
# while True:
|
||||
# l = f.readline()
|
||||
# if l == '':
|
||||
# break
|
||||
# l = l.rstrip()
|
||||
# print '| %s' % l
|
||||
# f.close()
|
||||
# else:
|
||||
# bb.msg.error(bb.msg.domain.Build, "see log in %s" % logfile)
|
||||
|
||||
if event[0] == 'bb.command.CookerCommandCompleted':
|
||||
exitflag = True
|
||||
if event[0] == 'bb.command.CookerCommandFailed':
|
||||
mw.appendText("Command execution failed: %s" % event[1]['error'])
|
||||
time.sleep(2)
|
||||
exitflag = True
|
||||
if event[0] == 'bb.cooker.CookerExit':
|
||||
exitflag = True
|
||||
|
||||
if helper.needUpdate:
|
||||
activetasks, failedtasks = helper.getTasks()
|
||||
taw.erase()
|
||||
taw.setText(0, 0, "")
|
||||
if activetasks:
|
||||
taw.appendText("Active Tasks:\n")
|
||||
for task in activetasks:
|
||||
taw.appendText(task)
|
||||
if failedtasks:
|
||||
taw.appendText("Failed Tasks:\n")
|
||||
for task in failedtasks:
|
||||
taw.appendText(task)
|
||||
|
||||
curses.doupdate()
|
||||
except KeyboardInterrupt:
|
||||
if shutdown == 2:
|
||||
mw.appendText("Third Keyboard Interrupt, exit.\n")
|
||||
exitflag = True
|
||||
if shutdown == 1:
|
||||
mw.appendText("Second Keyboard Interrupt, stopping...\n")
|
||||
server.runCommand(["stateStop"])
|
||||
if shutdown == 0:
|
||||
mw.appendText("Keyboard Interrupt, closing down...\n")
|
||||
server.runCommand(["stateShutdown"])
|
||||
shutdown = shutdown + 1
|
||||
pass
|
||||
|
||||
def init(server, eventHandler):
|
||||
ui = NCursesUI()
|
||||
try:
|
||||
curses.wrapper(ui.main, server, eventHandler)
|
||||
except:
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
127
bitbake-dev/lib/bb/ui/uievent.py
Normal file
127
bitbake-dev/lib/bb/ui/uievent.py
Normal file
@@ -0,0 +1,127 @@
|
||||
# ex:ts=4:sw=4:sts=4:et
|
||||
# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
|
||||
#
|
||||
# Copyright (C) 2006 - 2007 Michael 'Mickey' Lauer
|
||||
# Copyright (C) 2006 - 2007 Richard Purdie
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License version 2 as
|
||||
# published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
|
||||
"""
|
||||
Use this class to fork off a thread to recieve event callbacks from the bitbake
|
||||
server and queue them for the UI to process. This process must be used to avoid
|
||||
client/server deadlocks.
|
||||
"""
|
||||
|
||||
import sys, socket, threading
|
||||
from SimpleXMLRPCServer import SimpleXMLRPCServer, SimpleXMLRPCRequestHandler
|
||||
|
||||
class BBUIEventQueue:
|
||||
def __init__(self, BBServer):
|
||||
|
||||
self.eventQueue = []
|
||||
self.eventQueueLock = threading.Lock()
|
||||
self.eventQueueNotify = threading.Event()
|
||||
|
||||
self.BBServer = BBServer
|
||||
|
||||
self.t = threading.Thread()
|
||||
self.t.setDaemon(True)
|
||||
self.t.run = self.startCallbackHandler
|
||||
self.t.start()
|
||||
|
||||
def getEvent(self):
|
||||
|
||||
self.eventQueueLock.acquire()
|
||||
|
||||
if len(self.eventQueue) == 0:
|
||||
self.eventQueueLock.release()
|
||||
return None
|
||||
|
||||
item = self.eventQueue.pop(0)
|
||||
|
||||
if len(self.eventQueue) == 0:
|
||||
self.eventQueueNotify.clear()
|
||||
|
||||
self.eventQueueLock.release()
|
||||
|
||||
return item
|
||||
|
||||
def waitEvent(self, delay):
|
||||
self.eventQueueNotify.wait(delay)
|
||||
return self.getEvent()
|
||||
|
||||
def queue_event(self, event):
|
||||
|
||||
self.eventQueueLock.acquire()
|
||||
self.eventQueue.append(event)
|
||||
self.eventQueueNotify.set()
|
||||
self.eventQueueLock.release()
|
||||
|
||||
def startCallbackHandler(self):
|
||||
|
||||
server = UIXMLRPCServer()
|
||||
self.host, self.port = server.socket.getsockname()
|
||||
|
||||
server.register_function( self.system_quit, "event.quit" )
|
||||
server.register_function( self.queue_event, "event.send" )
|
||||
server.socket.settimeout(1)
|
||||
|
||||
self.EventHandle = self.BBServer.registerEventHandler(self.host, self.port)
|
||||
|
||||
self.server = server
|
||||
while not server.quit:
|
||||
server.handle_request()
|
||||
server.server_close()
|
||||
|
||||
def system_quit( self ):
|
||||
"""
|
||||
Shut down the callback thread
|
||||
"""
|
||||
try:
|
||||
self.BBServer.unregisterEventHandler(self.EventHandle)
|
||||
except:
|
||||
pass
|
||||
self.server.quit = True
|
||||
|
||||
class UIXMLRPCServer (SimpleXMLRPCServer):
|
||||
|
||||
def __init__( self, interface = ("localhost", 0) ):
|
||||
self.quit = False
|
||||
SimpleXMLRPCServer.__init__( self,
|
||||
interface,
|
||||
requestHandler=SimpleXMLRPCRequestHandler,
|
||||
logRequests=False, allow_none=True)
|
||||
|
||||
def get_request(self):
|
||||
while not self.quit:
|
||||
try:
|
||||
sock, addr = self.socket.accept()
|
||||
sock.settimeout(1)
|
||||
return (sock, addr)
|
||||
except socket.timeout:
|
||||
pass
|
||||
return (None,None)
|
||||
|
||||
def close_request(self, request):
|
||||
if request is None:
|
||||
return
|
||||
SimpleXMLRPCServer.close_request(self, request)
|
||||
|
||||
def process_request(self, request, client_address):
|
||||
if request is None:
|
||||
return
|
||||
SimpleXMLRPCServer.process_request(self, request, client_address)
|
||||
|
||||
|
||||
49
bitbake-dev/lib/bb/ui/uihelper.py
Normal file
49
bitbake-dev/lib/bb/ui/uihelper.py
Normal file
@@ -0,0 +1,49 @@
|
||||
# ex:ts=4:sw=4:sts=4:et
|
||||
# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
|
||||
#
|
||||
# Copyright (C) 2006 - 2007 Michael 'Mickey' Lauer
|
||||
# Copyright (C) 2006 - 2007 Richard Purdie
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License version 2 as
|
||||
# published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
class BBUIHelper:
|
||||
def __init__(self):
|
||||
self.needUpdate = False
|
||||
self.running_tasks = {}
|
||||
self.failed_tasks = {}
|
||||
|
||||
def eventHandler(self, event):
|
||||
if event[0].startswith('bb.build.TaskStarted'):
|
||||
self.running_tasks["%s %s\n" % (event[1]['_package'], event[1]['_task'])] = ""
|
||||
self.needUpdate = True
|
||||
if event[0].startswith('bb.build.TaskSucceeded'):
|
||||
del self.running_tasks["%s %s\n" % (event[1]['_package'], event[1]['_task'])]
|
||||
self.needUpdate = True
|
||||
if event[0].startswith('bb.build.TaskFailed'):
|
||||
del self.running_tasks["%s %s\n" % (event[1]['_package'], event[1]['_task'])]
|
||||
self.failed_tasks["%s %s\n" % (event[1]['_package'], event[1]['_task'])] = ""
|
||||
self.needUpdate = True
|
||||
|
||||
# Add runqueue event handling
|
||||
#if event[0].startswith('bb.runqueue.runQueueTaskCompleted'):
|
||||
# a = 1
|
||||
#if event[0].startswith('bb.runqueue.runQueueTaskStarted'):
|
||||
# a = 1
|
||||
#if event[0].startswith('bb.runqueue.runQueueTaskFailed'):
|
||||
# a = 1
|
||||
#if event[0].startswith('bb.runqueue.runQueueExitWait'):
|
||||
# a = 1
|
||||
|
||||
def getTasks(self):
|
||||
return (self.running_tasks, self.failed_tasks)
|
||||
Reference in New Issue
Block a user