mirror of
https://git.yoctoproject.org/poky
synced 2026-03-24 00:00:18 +01:00
Compare commits
21 Commits
1.6_M3.fin
...
toaster-do
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1182665de0 | ||
|
|
6302d1baf5 | ||
|
|
3390674247 | ||
|
|
0e6bbf8181 | ||
|
|
3b113312fd | ||
|
|
6f9c4d9778 | ||
|
|
f20de8ac90 | ||
|
|
e5cf3e598e | ||
|
|
46814c99ee | ||
|
|
b0c24033bb | ||
|
|
25f50e24c7 | ||
|
|
a6b357a9af | ||
|
|
57beaf994f | ||
|
|
e1aebfe018 | ||
|
|
f6847b0cd2 | ||
|
|
1e6e27d98d | ||
|
|
73293c6481 | ||
|
|
d7b8f82a64 | ||
|
|
4b64eb444a | ||
|
|
db2a7845a9 | ||
|
|
cb1338dedc |
8
.gitignore
vendored
8
.gitignore
vendored
@@ -16,8 +16,8 @@ hob-image-*.bb
|
||||
*~
|
||||
!meta-yocto
|
||||
!meta-yocto-bsp
|
||||
!meta-yocto-imported
|
||||
documentation/user-manual/user-manual.html
|
||||
documentation/user-manual/user-manual.pdf
|
||||
documentation/user-manual/user-manual.tgz
|
||||
bitbake/doc/manual/html/
|
||||
bitbake/doc/manual/pdf/
|
||||
bitbake/doc/manual/txt/
|
||||
bitbake/doc/manual/xhtml/
|
||||
pull-*/
|
||||
|
||||
16
LICENSE
16
LICENSE
@@ -1,14 +1,14 @@
|
||||
Different components of OpenEmbedded are under different licenses (a mix
|
||||
of MIT and GPLv2). Please see:
|
||||
Different components of Poky are under different licenses (a mix of
|
||||
MIT and GPLv2). Please see:
|
||||
|
||||
meta/COPYING.GPLv2 (GPLv2)
|
||||
bitbake/COPYING (GPLv2)
|
||||
meta/COPYING.MIT (MIT)
|
||||
meta-selftest/COPYING.MIT (MIT)
|
||||
meta-skeleton/COPYING.MIT (MIT)
|
||||
meta-extras/COPYING.MIT (MIT)
|
||||
|
||||
All metadata is MIT licensed unless otherwise stated. Source code
|
||||
included in tree for individual recipes is under the LICENSE stated in
|
||||
the associated recipe (.bb file) unless otherwise stated.
|
||||
which cover the components in those subdirectories. This means all
|
||||
metadata is MIT licensed unless otherwise stated. Source code included
|
||||
in tree for individual recipes is under the LICENSE stated in the .bb
|
||||
file for those software projects unless otherwise stated.
|
||||
|
||||
License information for any other files is either explicitly stated
|
||||
or defaults to GPL version 2.
|
||||
|
||||
2
README
2
README
@@ -22,7 +22,7 @@ reference manual which can be found at:
|
||||
|
||||
OpenEmbedded-Core is a layer containing the core metadata for current versions
|
||||
of OpenEmbedded. It is distro-less (can build a functional image with
|
||||
DISTRO = "nodistro") and contains only emulated machine support.
|
||||
DISTRO = "") and contains only emulated machine support.
|
||||
|
||||
For information about OpenEmbedded, see the OpenEmbedded website:
|
||||
http://www.openembedded.org/
|
||||
|
||||
@@ -41,7 +41,7 @@ from bb import ui
|
||||
from bb import server
|
||||
from bb import cookerdata
|
||||
|
||||
__version__ = "1.21.1"
|
||||
__version__ = "1.20.0"
|
||||
logger = logging.getLogger("BitBake")
|
||||
|
||||
# Python multiprocessing requires /dev/shm
|
||||
@@ -190,9 +190,6 @@ class BitBakeConfigParameters(cookerdata.ConfigParameters):
|
||||
parser.add_option("", "--observe-only", help = "Connect to a server as an observing-only client.",
|
||||
action = "store_true", dest = "observe_only", default = False)
|
||||
|
||||
parser.add_option("", "--status-only", help = "Check the status of the remote bitbake server.",
|
||||
action = "store_true", dest = "status_only", default = False)
|
||||
|
||||
options, targets = parser.parse_args(sys.argv)
|
||||
|
||||
# some environmental variables set also configuration options
|
||||
@@ -208,10 +205,8 @@ def start_server(servermodule, configParams, configuration):
|
||||
if configParams.bind:
|
||||
(host, port) = configParams.bind.split(':')
|
||||
server.initServer((host, int(port)))
|
||||
configuration.interface = [ server.serverImpl.host, server.serverImpl.port ]
|
||||
else:
|
||||
server.initServer()
|
||||
configuration.interface = []
|
||||
|
||||
try:
|
||||
configuration.setServerRegIdleCallback(server.getServerIdleCB())
|
||||
@@ -289,9 +284,7 @@ def main():
|
||||
|
||||
# Ensure logging messages get sent to the UI as events
|
||||
handler = bb.event.LogHandler()
|
||||
if not configParams.status_only:
|
||||
# In status only mode there are no logs and no UI
|
||||
logger.addHandler(handler)
|
||||
logger.addHandler(handler)
|
||||
|
||||
# Clear away any spurious environment variables while we stoke up the cooker
|
||||
cleanedvars = bb.utils.clean_environment()
|
||||
@@ -304,31 +297,13 @@ def main():
|
||||
# we start a stub server that is actually a XMLRPClient that connects to a real server
|
||||
server = servermodule.BitBakeXMLRPCClient(configParams.observe_only)
|
||||
server.saveConnectionDetails(configParams.remote_server)
|
||||
server.saveConnectionConfigParams(configParams)
|
||||
|
||||
if not configParams.server_only:
|
||||
# Collect the feature set for the UI
|
||||
featureset = getattr(ui_module, "featureSet", [])
|
||||
|
||||
if configParams.status_only:
|
||||
try:
|
||||
server_connection = server.establishConnection(featureset)
|
||||
except:
|
||||
sys.exit(1)
|
||||
if not server_connection:
|
||||
sys.exit(1)
|
||||
server_connection.terminate()
|
||||
sys.exit(0)
|
||||
|
||||
# Setup a connection to the server (cooker)
|
||||
server_connection = server.establishConnection(featureset)
|
||||
if not server_connection:
|
||||
if configParams.kill_server:
|
||||
bb.fatal("Server already killed")
|
||||
configParams.bind = configParams.remote_server
|
||||
start_server(servermodule, configParams, configuration)
|
||||
bb.event.ui_queue = []
|
||||
server_connection = server.establishConnection(featureset)
|
||||
|
||||
# Restore the environment in case the UI needs it
|
||||
for k in cleanedvars:
|
||||
@@ -343,7 +318,6 @@ def main():
|
||||
server_connection.terminate()
|
||||
else:
|
||||
print("server address: %s, server port: %s" % (server.serverImpl.host, server.serverImpl.port))
|
||||
return 0
|
||||
|
||||
return 1
|
||||
|
||||
|
||||
@@ -55,16 +55,10 @@ def main(args):
|
||||
|
||||
class Commands(cmd.Cmd):
|
||||
def __init__(self):
|
||||
self.bbhandler = None
|
||||
self.returncode = 0
|
||||
self.bblayers = []
|
||||
cmd.Cmd.__init__(self)
|
||||
|
||||
def init_bbhandler(self, config_only = False):
|
||||
if not self.bbhandler:
|
||||
self.bbhandler = bb.tinfoil.Tinfoil()
|
||||
self.bblayers = (self.bbhandler.config_data.getVar('BBLAYERS', True) or "").split()
|
||||
self.bbhandler.prepare(config_only)
|
||||
self.bbhandler = bb.tinfoil.Tinfoil()
|
||||
self.returncode = 0
|
||||
self.bblayers = (self.bbhandler.config_data.getVar('BBLAYERS', True) or "").split()
|
||||
|
||||
def default(self, line):
|
||||
"""Handle unrecognised commands"""
|
||||
@@ -89,7 +83,7 @@ class Commands(cmd.Cmd):
|
||||
|
||||
def do_show_layers(self, args):
|
||||
"""show current configured layers"""
|
||||
self.init_bbhandler(config_only = True)
|
||||
self.bbhandler.prepare(config_only = True)
|
||||
logger.plain("%s %s %s" % ("layer".ljust(20), "path".ljust(40), "priority"))
|
||||
logger.plain('=' * 74)
|
||||
for layerdir in self.bblayers:
|
||||
@@ -126,7 +120,7 @@ Options:
|
||||
recipes with the ones they overlay indented underneath
|
||||
-s only list overlayed recipes where the version is the same
|
||||
"""
|
||||
self.init_bbhandler()
|
||||
self.bbhandler.prepare()
|
||||
|
||||
show_filenames = False
|
||||
show_same_ver_only = False
|
||||
@@ -209,7 +203,7 @@ Options:
|
||||
-m only list where multiple recipes (in the same layer or different
|
||||
layers) exist for the same recipe name
|
||||
"""
|
||||
self.init_bbhandler()
|
||||
self.bbhandler.prepare()
|
||||
|
||||
show_filenames = False
|
||||
show_multi_provider_only = False
|
||||
@@ -347,7 +341,7 @@ build results (as the layer priority order has effectively changed).
|
||||
logger.error('Directory %s exists and is non-empty, please clear it out first' % outputdir)
|
||||
return
|
||||
|
||||
self.init_bbhandler()
|
||||
self.bbhandler.prepare()
|
||||
layers = self.bblayers
|
||||
if len(arglist) > 2:
|
||||
layernames = arglist[:-1]
|
||||
@@ -503,7 +497,7 @@ usage: show-appends
|
||||
|
||||
Recipes are listed with the bbappends that apply to them as subitems.
|
||||
"""
|
||||
self.init_bbhandler()
|
||||
self.bbhandler.prepare()
|
||||
if not self.bbhandler.cooker.collection.appendlist:
|
||||
logger.plain('No append files found')
|
||||
return
|
||||
@@ -576,7 +570,7 @@ Options:
|
||||
NOTE:
|
||||
The .bbappend file can impact the dependency.
|
||||
"""
|
||||
self.init_bbhandler()
|
||||
self.bbhandler.prepare()
|
||||
|
||||
show_filenames = False
|
||||
for arg in args.split():
|
||||
|
||||
@@ -81,7 +81,7 @@ def workerlog_write(msg):
|
||||
lf.write(msg)
|
||||
lf.flush()
|
||||
|
||||
def fork_off_task(cfg, data, workerdata, fn, task, taskname, appends, taskdepdata, quieterrors=False):
|
||||
def fork_off_task(cfg, data, workerdata, fn, task, taskname, appends, quieterrors=False):
|
||||
# We need to setup the environment BEFORE the fork, since
|
||||
# a fork() or exec*() activates PSEUDO...
|
||||
|
||||
@@ -97,8 +97,7 @@ def fork_off_task(cfg, data, workerdata, fn, task, taskname, appends, taskdepdat
|
||||
except TypeError:
|
||||
umask = taskdep['umask'][taskname]
|
||||
|
||||
# We can't use the fakeroot environment in a dry run as it possibly hasn't been built
|
||||
if 'fakeroot' in taskdep and taskname in taskdep['fakeroot'] and not cfg.dry_run:
|
||||
if 'fakeroot' in taskdep and taskname in taskdep['fakeroot']:
|
||||
envvars = (workerdata["fakerootenv"][fn] or "").split()
|
||||
for key, value in (var.split('=') for var in envvars):
|
||||
envbackup[key] = os.environ.get(key)
|
||||
@@ -148,7 +147,6 @@ def fork_off_task(cfg, data, workerdata, fn, task, taskname, appends, taskdepdat
|
||||
os.umask(umask)
|
||||
|
||||
data.setVar("BB_WORKERCONTEXT", "1")
|
||||
data.setVar("BB_TASKDEPDATA", taskdepdata)
|
||||
data.setVar("BUILDNAME", workerdata["buildname"])
|
||||
data.setVar("DATE", workerdata["date"])
|
||||
data.setVar("TIME", workerdata["time"])
|
||||
@@ -301,10 +299,10 @@ class BitbakeWorker(object):
|
||||
sys.exit(0)
|
||||
|
||||
def handle_runtask(self, data):
|
||||
fn, task, taskname, quieterrors, appends, taskdepdata = pickle.loads(data)
|
||||
fn, task, taskname, quieterrors, appends = pickle.loads(data)
|
||||
workerlog_write("Handling runtask %s %s %s\n" % (task, fn, taskname))
|
||||
|
||||
pid, pipein, pipeout = fork_off_task(self.cookercfg, self.data, self.workerdata, fn, task, taskname, appends, taskdepdata, quieterrors)
|
||||
pid, pipein, pipeout = fork_off_task(self.cookercfg, self.data, self.workerdata, fn, task, taskname, appends, quieterrors)
|
||||
|
||||
self.build_pids[pid] = task
|
||||
self.build_pipes[pid] = runQueueWorkerPipe(pipein, pipeout)
|
||||
|
||||
@@ -40,22 +40,10 @@ function webserverStartAll()
|
||||
{
|
||||
retval=0
|
||||
python $BBBASEDIR/lib/toaster/manage.py syncdb || retval=1
|
||||
python $BBBASEDIR/lib/toaster/manage.py migrate orm || retval=2
|
||||
if [ $retval -eq 1 ]; then
|
||||
echo "Failed db sync, stopping system start" 1>&2
|
||||
elif [ $retval -eq 2 ]; then
|
||||
echo -e "\nError on migration, trying to recover... \n"
|
||||
python $BBBASEDIR/lib/toaster/manage.py migrate orm 0001_initial --fake
|
||||
retval=0
|
||||
python $BBBASEDIR/lib/toaster/manage.py migrate orm || retval=1
|
||||
fi
|
||||
if [ $retval -eq 0 ]; then
|
||||
else
|
||||
python $BBBASEDIR/lib/toaster/manage.py runserver 0.0.0.0:8000 </dev/null >${BUILDDIR}/toaster_web.log 2>&1 & echo $! >${BUILDDIR}/.toastermain.pid
|
||||
sleep 1
|
||||
if ! cat "${BUILDDIR}/.toastermain.pid" | xargs -I{} kill -0 {} ; then
|
||||
retval=1
|
||||
rm "${BUILDDIR}/.toastermain.pid"
|
||||
fi
|
||||
fi
|
||||
return $retval
|
||||
}
|
||||
@@ -99,18 +87,11 @@ BBBASEDIR=`dirname ${BASH_SOURCE}`/..
|
||||
|
||||
# Verify prerequisites
|
||||
|
||||
if ! echo "import django; print (1,5) == django.VERSION[0:2]" | python 2>/dev/null | grep True >/dev/null; then
|
||||
echo -e "This program needs Django 1.5. Please install with\n\nsudo pip install django==1.5"
|
||||
if ! echo "import django; print (1,4,5) == django.VERSION[0:3]" | python 2>/dev/null | grep True >/dev/null; then
|
||||
echo -e "This program needs Django 1.4.5. Please install with\n\nsudo pip install django==1.4.5"
|
||||
return 2
|
||||
fi
|
||||
|
||||
if ! echo "import south; print [0,8,4] == map(int,south.__version__.split(\".\"))" | python 2>/dev/null | grep True >/dev/null; then
|
||||
echo -e "This program needs South 0.8.4. Please install with\n\nsudo pip install south==0.8.4"
|
||||
return 2
|
||||
fi
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# Determine the action. If specified by arguments, fine, if not, toggle it
|
||||
@@ -125,13 +106,9 @@ else
|
||||
fi
|
||||
|
||||
NOTOASTERUI=0
|
||||
for param in $*; do
|
||||
case $param in
|
||||
noui )
|
||||
NOTOASTERUI=1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
if [ "x$2" == "xnoui" ]; then
|
||||
NOTOASTERUI=1
|
||||
fi
|
||||
|
||||
echo "The system will $CMD."
|
||||
|
||||
@@ -166,38 +143,22 @@ fi
|
||||
|
||||
case $CMD in
|
||||
start )
|
||||
start_success=1
|
||||
addtoConfiguration "INHERIT+=\"toaster buildhistory\"" toaster.conf
|
||||
if ! webserverStartAll; then
|
||||
echo "Failed ${CMD}."
|
||||
return 4
|
||||
fi
|
||||
webserverStartAll || return 4
|
||||
unset BBSERVER
|
||||
bitbake --postread conf/toaster.conf --server-only -t xmlrpc -B localhost:8200
|
||||
if [ $? -ne 0 ]; then
|
||||
start_success=0
|
||||
echo "Bitbake server start failed"
|
||||
else
|
||||
export BBSERVER=localhost:8200
|
||||
if [ $NOTOASTERUI == 0 ]; then # we start the TOASTERUI only if not inhibited
|
||||
bitbake --observe-only -u toasterui >${BUILDDIR}/toaster_ui.log 2>&1 & echo $! >${BUILDDIR}/.toasterui.pid
|
||||
fi
|
||||
fi
|
||||
if [ $start_success -eq 1 ]; then
|
||||
# set fail safe stop system on terminal exit
|
||||
trap stop_system SIGHUP
|
||||
echo "Successful ${CMD}."
|
||||
else
|
||||
# failed start, do stop
|
||||
stop_system
|
||||
echo "Failed ${CMD}."
|
||||
export BBSERVER=localhost:8200
|
||||
if [ $NOTOASTERUI == 0 ]; then # we start the TOASTERUI only if not inhibited
|
||||
bitbake --observe-only -u toasterui >${BUILDDIR}/toaster_ui.log 2>&1 & echo $! >${BUILDDIR}/.toasterui.pid
|
||||
fi
|
||||
# stop system on terminal exit
|
||||
trap stop_system SIGHUP
|
||||
;;
|
||||
stop )
|
||||
stop_system
|
||||
trap '' SIGHUP
|
||||
echo "Successful ${CMD}."
|
||||
;;
|
||||
esac
|
||||
|
||||
echo "Successful ${CMD}."
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ endif
|
||||
fun! <SID>GetUserName()
|
||||
let l:user_name = system("git config --get user.name")
|
||||
if v:shell_error
|
||||
return "Unknown User"
|
||||
return "Unknow User"
|
||||
else
|
||||
return substitute(l:user_name, "\n", "", "")
|
||||
endfun
|
||||
|
||||
@@ -1,77 +0,0 @@
|
||||
# This is a single Makefile to handle all generated BitBake documents.
|
||||
# The Makefile needs to live in the documentation directory and all figures used
|
||||
# in any manuals must be .PNG files and live in the individual book's figures
|
||||
# directory.
|
||||
#
|
||||
# The Makefile has these targets:
|
||||
#
|
||||
# pdf: generates a PDF version of a manual.
|
||||
# html: generates an HTML version of a manual.
|
||||
# tarball: creates a tarball for the doc files.
|
||||
# validate: validates
|
||||
# clean: removes files
|
||||
#
|
||||
# The Makefile generates an HTML and PDF version of every document. The
|
||||
# variable DOC indicates the folder name for a given manual.
|
||||
#
|
||||
# To build a manual, you must invoke 'make' with the DOC argument.
|
||||
#
|
||||
# Examples:
|
||||
#
|
||||
# make DOC=user-manual
|
||||
# make pdf DOC=user-manual
|
||||
#
|
||||
# The first example generates the HTML and PDF versions of the User Manual.
|
||||
# The second example generates the HTML version only of the User Manual.
|
||||
#
|
||||
|
||||
ifeq ($(DOC),user-manual)
|
||||
XSLTOPTS = --stringparam html.stylesheet user-manual-style.css \
|
||||
--stringparam chapter.autolabel 1 \
|
||||
--stringparam section.autolabel 1 \
|
||||
--stringparam section.label.includes.component.label 1 \
|
||||
--xinclude
|
||||
ALLPREQ = html pdf tarball
|
||||
TARFILES = user-manual-style.css user-manual.html user-manual.pdf figures/bitbake-title.png
|
||||
MANUALS = $(DOC)/$(DOC).html $(DOC)/$(DOC).pdf
|
||||
FIGURES = figures
|
||||
STYLESHEET = $(DOC)/*.css
|
||||
|
||||
endif
|
||||
|
||||
##
|
||||
# These URI should be rewritten by your distribution's xml catalog to
|
||||
# match your localy installed XSL stylesheets.
|
||||
XSL_BASE_URI = http://docbook.sourceforge.net/release/xsl/current
|
||||
XSL_XHTML_URI = $(XSL_BASE_URI)/xhtml/docbook.xsl
|
||||
|
||||
all: $(ALLPREQ)
|
||||
|
||||
pdf:
|
||||
ifeq ($(DOC),user-manual)
|
||||
@echo " "
|
||||
@echo "********** Building."$(DOC)
|
||||
@echo " "
|
||||
cd $(DOC); ../tools/docbook-to-pdf $(DOC).xml ../template; cd ..
|
||||
endif
|
||||
|
||||
html:
|
||||
ifeq ($(DOC),user-manual)
|
||||
# See http://www.sagehill.net/docbookxsl/HtmlOutput.html
|
||||
@echo " "
|
||||
@echo "******** Building "$(DOC)
|
||||
@echo " "
|
||||
cd $(DOC); xsltproc $(XSLTOPTS) -o $(DOC).html $(DOC)-customization.xsl $(DOC).xml; cd ..
|
||||
endif
|
||||
|
||||
tarball: html
|
||||
@echo " "
|
||||
@echo "******** Creating Tarball of document files"
|
||||
@echo " "
|
||||
cd $(DOC); tar -cvzf $(DOC).tgz $(TARFILES); cd ..
|
||||
|
||||
validate:
|
||||
cd $(DOC); xmllint --postvalid --xinclude --noout $(DOC).xml; cd ..
|
||||
|
||||
clean:
|
||||
rm -rf $(MANUALS); rm $(DOC)/$(DOC).tgz;
|
||||
@@ -1,39 +0,0 @@
|
||||
Documentation
|
||||
=============
|
||||
|
||||
This is the directory that contains the BitBake documentation.
|
||||
|
||||
Manual Organization
|
||||
===================
|
||||
|
||||
Folders exist for individual manuals as follows:
|
||||
|
||||
* user-manual - The BitBake User Manual
|
||||
|
||||
Each folder is self-contained regarding content and figures.
|
||||
|
||||
If you want to find HTML versions of the BitBake manuals on the web,
|
||||
go to http://www.openembedded.org/wiki/Documentation.
|
||||
|
||||
Makefile
|
||||
========
|
||||
|
||||
The Makefile processes manual directories to create HTML, PDF,
|
||||
tarballs, etc. Details on how the Makefile work are documented
|
||||
inside the Makefile. See that file for more information.
|
||||
|
||||
To build a manual, you run the make command and pass it the name
|
||||
of the folder containing the manual's contents.
|
||||
For example, the following command run from the documentation directory
|
||||
creates an HTML and a PDF version of the BitBake User Manual.
|
||||
The DOC variable specifies the manual you are making:
|
||||
|
||||
$ make DOC=user-manual
|
||||
|
||||
template
|
||||
========
|
||||
Contains various templates, fonts, and some old PNG files.
|
||||
|
||||
tools
|
||||
=====
|
||||
Contains a tool to convert the DocBook files to PDF format.
|
||||
56
bitbake/doc/manual/Makefile
Normal file
56
bitbake/doc/manual/Makefile
Normal file
@@ -0,0 +1,56 @@
|
||||
topdir = .
|
||||
manual = $(topdir)/usermanual.xml
|
||||
# types = pdf txt rtf ps xhtml html man tex texi dvi
|
||||
# types = pdf txt
|
||||
types = $(xmltotypes) $(htmltypes)
|
||||
xmltotypes = pdf txt
|
||||
htmltypes = html xhtml
|
||||
htmlxsl = $(if $(filter $@,$(foreach type,$(htmltypes),$(type)-nochunks)),http://docbook.sourceforge.net/release/xsl/current/xhtml/docbook.xsl,http://docbook.sourceforge.net/release/xsl/current/$@/chunk.xsl)
|
||||
htmlcssfile = docbook.css
|
||||
htmlcss = $(topdir)/html.css
|
||||
# htmlcssfile =
|
||||
# htmlcss =
|
||||
cleanfiles = $(foreach i,$(types),$(topdir)/$(i))
|
||||
|
||||
ifdef DEBUG
|
||||
define command
|
||||
$(1)
|
||||
endef
|
||||
else
|
||||
define command
|
||||
@echo $(2) $(3) $(4)
|
||||
@$(1) >/dev/null
|
||||
endef
|
||||
endif
|
||||
|
||||
all: $(types)
|
||||
|
||||
lint: $(manual) FORCE
|
||||
$(call command,xmllint --xinclude --postvalid --noout $(manual),XMLLINT $(manual))
|
||||
|
||||
$(types) $(foreach type,$(htmltypes),$(type)-nochunks): lint FORCE
|
||||
|
||||
$(foreach type,$(htmltypes),$(type)-nochunks): $(if $(htmlcss),$(htmlcss)) $(manual)
|
||||
@mkdir -p $@
|
||||
ifdef htmlcss
|
||||
$(call command,install -m 0644 $(htmlcss) $@/$(htmlcssfile),CP $(htmlcss) $@/$(htmlcssfile))
|
||||
endif
|
||||
$(call command,xsltproc --stringparam base.dir $@/ $(if $(htmlcssfile),--stringparam html.stylesheet $(htmlcssfile)) $(htmlxsl) $(manual) > $@/index.$(patsubst %-nochunks,%,$@),XSLTPROC $@ $(manual))
|
||||
|
||||
$(htmltypes): $(if $(htmlcss),$(htmlcss)) $(manual)
|
||||
@mkdir -p $@
|
||||
ifdef htmlcss
|
||||
$(call command,install -m 0644 $(htmlcss) $@/$(htmlcssfile),CP $(htmlcss) $@/$(htmlcssfile))
|
||||
endif
|
||||
$(call command,xsltproc --stringparam base.dir $@/ $(if $(htmlcssfile),--stringparam html.stylesheet $(htmlcssfile)) $(htmlxsl) $(manual),XSLTPROC $@ $(manual))
|
||||
|
||||
$(xmltotypes): $(manual)
|
||||
$(call command,xmlto --with-dblatex --extensions -o $(topdir)/$@ $@ $(manual),XMLTO $@ $(manual))
|
||||
|
||||
clean:
|
||||
rm -rf $(cleanfiles)
|
||||
|
||||
$(foreach i,$(types) $(foreach type,$(htmltypes),$(type)-nochunks),clean-$(i)):
|
||||
rm -rf $(patsubst clean-%,%,$@)
|
||||
|
||||
FORCE:
|
||||
627
bitbake/doc/manual/usermanual.xml
Normal file
627
bitbake/doc/manual/usermanual.xml
Normal file
@@ -0,0 +1,627 @@
|
||||
<?xml version="1.0"?>
|
||||
<!--
|
||||
ex:ts=4:sw=4:sts=4:et
|
||||
-*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
|
||||
-->
|
||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
|
||||
<book>
|
||||
<bookinfo>
|
||||
<title>BitBake User Manual</title>
|
||||
<authorgroup>
|
||||
<corpauthor>BitBake Team</corpauthor>
|
||||
</authorgroup>
|
||||
<copyright>
|
||||
<year>2004, 2005, 2006, 2011</year>
|
||||
<holder>Chris Larson</holder>
|
||||
<holder>Phil Blundell</holder>
|
||||
<holder>Richard Purdie</holder>
|
||||
</copyright>
|
||||
<legalnotice>
|
||||
<para>This work is licensed under the Creative Commons Attribution License. To view a copy of this license, visit <ulink url="http://creativecommons.org/licenses/by/2.5/">http://creativecommons.org/licenses/by/2.5/</ulink> or send a letter to Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.</para>
|
||||
</legalnotice>
|
||||
</bookinfo>
|
||||
<chapter>
|
||||
<title>Introduction</title>
|
||||
<section>
|
||||
<title>Overview</title>
|
||||
<para>BitBake is, at its simplest, a tool for executing
|
||||
tasks and managing metadata. As such, its similarities to GNU make and other
|
||||
build tools are readily apparent. It was inspired by Portage, the package management system used by the Gentoo Linux distribution. BitBake is the basis of the <ulink url="http://www.openembedded.org/">OpenEmbedded</ulink> project, which is being used to build and maintain a number of embedded Linux distributions/projects such as Angstrom and the Yocto project.</para>
|
||||
</section>
|
||||
<section>
|
||||
<title>Background and goals</title>
|
||||
<para>Prior to BitBake, no other build tool adequately met
|
||||
the needs of an aspiring embedded Linux distribution. All of the
|
||||
buildsystems used by traditional desktop Linux distributions lacked
|
||||
important functionality, and none of the ad-hoc
|
||||
<emphasis>buildroot</emphasis> systems, prevalent in the
|
||||
embedded space, were scalable or maintainable.</para>
|
||||
|
||||
<para>Some important original goals for BitBake were:
|
||||
<itemizedlist>
|
||||
<listitem><para>Handle crosscompilation.</para></listitem>
|
||||
<listitem><para>Handle interpackage dependencies (build time on target architecture, build time on native architecture, and runtime).</para></listitem>
|
||||
<listitem><para>Support running any number of tasks within a given package, including, but not limited to, fetching upstream sources, unpacking them, patching them, configuring them, et cetera.</para></listitem>
|
||||
<listitem><para>Must be Linux distribution agnostic (both build and target).</para></listitem>
|
||||
<listitem><para>Must be architecture agnostic</para></listitem>
|
||||
<listitem><para>Must support multiple build and target operating systems (including Cygwin, the BSDs, etc).</para></listitem>
|
||||
<listitem><para>Must be able to be self contained, rather than tightly integrated into the build machine's root filesystem.</para></listitem>
|
||||
<listitem><para>There must be a way to handle conditional metadata (on target architecture, operating system, distribution, machine).</para></listitem>
|
||||
<listitem><para>It must be easy for the person using the tools to supply their own local metadata and packages to operate against.</para></listitem>
|
||||
<listitem><para>Must make it easy to collaborate
|
||||
between multiple projects using BitBake for their
|
||||
builds.</para></listitem>
|
||||
<listitem><para>Should provide an inheritance mechanism to
|
||||
share common metadata between many packages.</para></listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
<para>Over time it has become apparent that some further requirements were necessary:
|
||||
<itemizedlist>
|
||||
<listitem><para>Handle variants of a base recipe (native, sdk, multilib).</para></listitem>
|
||||
<listitem><para>Able to split metadata into layers and allow layers to override each other.</para></listitem>
|
||||
<listitem><para>Allow representation of a given set of input variables to a task as a checksum.</para></listitem>
|
||||
<listitem><para>based on that checksum, allow acceleration of builds with prebuilt components.</para></listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
|
||||
<para>BitBake satisfies all the original requirements and many more with extensions being made to the basic functionality to reflect the additionl requirements. Flexibility and power have always been the priorities. It is highly extensible, supporting embedded Python code and execution of any arbitrary tasks.</para>
|
||||
</section>
|
||||
</chapter>
|
||||
<chapter>
|
||||
<title>Metadata</title>
|
||||
<section>
|
||||
<title>Description</title>
|
||||
<itemizedlist>
|
||||
<para>BitBake metadata can be classified into 3 major areas:</para>
|
||||
<listitem>
|
||||
<para>Configuration Files</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>.bb Files</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>Classes</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<para>What follows are a large number of examples of BitBake metadata. Any syntax which isn't supported in any of the aforementioned areas will be documented as such.</para>
|
||||
<section>
|
||||
<title>Basic variable setting</title>
|
||||
<para><screen><varname>VARIABLE</varname> = "value"</screen></para>
|
||||
<para>In this example, <varname>VARIABLE</varname> is <literal>value</literal>.</para>
|
||||
</section>
|
||||
<section>
|
||||
<title>Variable expansion</title>
|
||||
<para>BitBake supports variables referencing one another's contents using a syntax which is similar to shell scripting</para>
|
||||
<para><screen><varname>A</varname> = "aval"
|
||||
<varname>B</varname> = "pre${A}post"</screen></para>
|
||||
<para>This results in <varname>A</varname> containing <literal>aval</literal> and <varname>B</varname> containing <literal>preavalpost</literal>.</para>
|
||||
</section>
|
||||
<section>
|
||||
<title>Setting a default value (?=)</title>
|
||||
<para><screen><varname>A</varname> ?= "aval"</screen></para>
|
||||
<para>If <varname>A</varname> is set before the above is called, it will retain its previous value. If <varname>A</varname> is unset prior to the above call, <varname>A</varname> will be set to <literal>aval</literal>. Note that this assignment is immediate, so if there are multiple ?= assignments to a single variable, the first of those will be used.</para>
|
||||
</section>
|
||||
<section>
|
||||
<title>Setting a weak default value (??=)</title>
|
||||
<para><screen><varname>A</varname> ??= "somevalue"
|
||||
<varname>A</varname> ??= "someothervalue"</screen></para>
|
||||
<para>If <varname>A</varname> is set before the above, it will retain that value. If <varname>A</varname> is unset prior to the above, <varname>A</varname> will be set to <literal>someothervalue</literal>. This is a lazy/weak assignment in that the assignment does not occur until the end of the parsing process, so that the last, rather than the first, ??= assignment to a given variable will be used. Any other setting of A using = or ?= will however override the value set with ??=</para>
|
||||
</section>
|
||||
<section>
|
||||
<title>Immediate variable expansion (:=)</title>
|
||||
<para>:= results in a variable's contents being expanded immediately, rather than when the variable is actually used.</para>
|
||||
<para><screen><varname>T</varname> = "123"
|
||||
<varname>A</varname> := "${B} ${A} test ${T}"
|
||||
<varname>T</varname> = "456"
|
||||
<varname>B</varname> = "${T} bval"
|
||||
|
||||
<varname>C</varname> = "cval"
|
||||
<varname>C</varname> := "${C}append"</screen></para>
|
||||
<para>In that example, <varname>A</varname> would contain <literal> test 123</literal>, <varname>B</varname> would contain <literal>456 bval</literal>, and <varname>C</varname> would be <literal>cvalappend</literal>.</para>
|
||||
</section>
|
||||
<section>
|
||||
<title>Appending (+=) and prepending (=+)</title>
|
||||
<para><screen><varname>B</varname> = "bval"
|
||||
<varname>B</varname> += "additionaldata"
|
||||
<varname>C</varname> = "cval"
|
||||
<varname>C</varname> =+ "test"</screen></para>
|
||||
<para>In this example, <varname>B</varname> is now <literal>bval additionaldata</literal> and <varname>C</varname> is <literal>test cval</literal>.</para>
|
||||
</section>
|
||||
<section>
|
||||
<title>Appending (.=) and prepending (=.) without spaces</title>
|
||||
<para><screen><varname>B</varname> = "bval"
|
||||
<varname>B</varname> .= "additionaldata"
|
||||
<varname>C</varname> = "cval"
|
||||
<varname>C</varname> =. "test"</screen></para>
|
||||
<para>In this example, <varname>B</varname> is now <literal>bvaladditionaldata</literal> and <varname>C</varname> is <literal>testcval</literal>. In contrast to the above appending and prepending operators, no additional space
|
||||
will be introduced.</para>
|
||||
</section>
|
||||
<section>
|
||||
<title>Appending and Prepending (override style syntax)</title>
|
||||
<para><screen><varname>B</varname> = "bval"
|
||||
<varname>B_append</varname> = " additional data"
|
||||
<varname>C</varname> = "cval"
|
||||
<varname>C_prepend</varname> = "additional data "</screen></para>
|
||||
<para>This example results in <varname>B</varname> becoming <literal>bval additional data</literal>
|
||||
and <varname>C</varname> becoming <literal>additional data cval</literal>. Note the spaces in the append.
|
||||
Unlike the += operator, additional space is not automatically added. You must take steps to add space
|
||||
yourself.</para>
|
||||
</section>
|
||||
<section>
|
||||
<title>Removing (override style syntax)</title>
|
||||
<para><screen><varname>FOO</varname> = "123 456 789 123456 123 456 123 456"
|
||||
<varname>FOO_remove</varname> = "123"
|
||||
<varname>FOO_remove</varname> = "456"</screen></para>
|
||||
<para>In this example, <varname>FOO</varname> is now <literal>789 123456</literal>.</para>
|
||||
</section>
|
||||
<section>
|
||||
<title>Conditional metadata set</title>
|
||||
<para>OVERRIDES is a <quote>:</quote> separated variable containing each item you want to satisfy conditions. So, if you have a variable which is conditional on <quote>arm</quote>, and <quote>arm</quote> is in OVERRIDES, then the <quote>arm</quote> specific version of the variable is used rather than the non-conditional version. Example:</para>
|
||||
<para><screen><varname>OVERRIDES</varname> = "architecture:os:machine"
|
||||
<varname>TEST</varname> = "defaultvalue"
|
||||
<varname>TEST_os</varname> = "osspecificvalue"
|
||||
<varname>TEST_condnotinoverrides</varname> = "othercondvalue"</screen></para>
|
||||
<para>In this example, <varname>TEST</varname> would be <literal>osspecificvalue</literal>, due to the condition <quote>os</quote> being in <varname>OVERRIDES</varname>.</para>
|
||||
</section>
|
||||
<section>
|
||||
<title>Conditional appending</title>
|
||||
<para>BitBake also supports appending and prepending to variables based on whether something is in OVERRIDES. Example:</para>
|
||||
<para><screen><varname>DEPENDS</varname> = "glibc ncurses"
|
||||
<varname>OVERRIDES</varname> = "machine:local"
|
||||
<varname>DEPENDS_append_machine</varname> = " libmad"</screen></para>
|
||||
<para>In this example, <varname>DEPENDS</varname> is set to <literal>glibc ncurses libmad</literal>.</para>
|
||||
</section>
|
||||
<section>
|
||||
<title>Inclusion</title>
|
||||
<para>Next, there is the <literal>include</literal> directive, which causes BitBake to parse whatever file you specify, and insert it at that location, which is not unlike <command>make</command>. However, if the path specified on the <literal>include</literal> line is a relative path, BitBake will locate the first one it can find within <envar>BBPATH</envar>.</para>
|
||||
</section>
|
||||
<section>
|
||||
<title>Requiring inclusion</title>
|
||||
<para>In contrast to the <literal>include</literal> directive, <literal>require</literal> will
|
||||
raise an ParseError if the file to be included cannot be found. Otherwise it will behave just like the <literal>
|
||||
include</literal> directive.</para>
|
||||
</section>
|
||||
<section>
|
||||
<title>Python variable expansion</title>
|
||||
<para><screen><varname>DATE</varname> = "${@time.strftime('%Y%m%d',time.gmtime())}"</screen></para>
|
||||
<para>This would result in the <varname>DATE</varname> variable containing today's date.</para>
|
||||
</section>
|
||||
<section>
|
||||
<title>Defining executable metadata</title>
|
||||
<para><emphasis>NOTE:</emphasis> This is only supported in .bb and .bbclass files.</para>
|
||||
<para><screen>do_mytask () {
|
||||
echo "Hello, world!"
|
||||
}</screen></para>
|
||||
<para>This is essentially identical to setting a variable, except that this variable happens to be executable shell code.</para>
|
||||
<para><screen>python do_printdate () {
|
||||
import time
|
||||
print time.strftime('%Y%m%d', time.gmtime())
|
||||
}</screen></para>
|
||||
<para>This is the similar to the previous, but flags it as Python so that BitBake knows it is Python code.</para>
|
||||
</section>
|
||||
<section>
|
||||
<title>Defining Python functions into the global Python namespace</title>
|
||||
<para><emphasis>NOTE:</emphasis> This is only supported in .bb and .bbclass files.</para>
|
||||
<para><screen>def get_depends(bb, d):
|
||||
if d.getVar('SOMECONDITION', True):
|
||||
return "dependencywithcond"
|
||||
else:
|
||||
return "dependency"
|
||||
|
||||
<varname>SOMECONDITION</varname> = "1"
|
||||
<varname>DEPENDS</varname> = "${@get_depends(bb, d)}"</screen></para>
|
||||
<para>This would result in <varname>DEPENDS</varname> containing <literal>dependencywithcond</literal>.</para>
|
||||
</section>
|
||||
<section>
|
||||
<title>Variable flags</title>
|
||||
<para>Variables can have associated flags which provide a way of tagging extra information onto a variable. Several flags are used internally by BitBake but they can be used externally too if needed. The standard operations mentioned above also work on flags.</para>
|
||||
<para><screen><varname>VARIABLE</varname>[<varname>SOMEFLAG</varname>] = "value"</screen></para>
|
||||
<para>In this example, <varname>VARIABLE</varname> has a flag, <varname>SOMEFLAG</varname> which is set to <literal>value</literal>.</para>
|
||||
</section>
|
||||
<section>
|
||||
<title>Inheritance</title>
|
||||
<para><emphasis>NOTE:</emphasis> This is only supported in .bb and .bbclass files.</para>
|
||||
<para>The <literal>inherit</literal> directive is a means of specifying what classes of functionality your .bb requires. It is a rudimentary form of inheritance. For example, you can easily abstract out the tasks involved in building a package that uses autoconf and automake, and put that into a bbclass for your packages to make use of. A given bbclass is located by searching for classes/filename.bbclass in <envar>BBPATH</envar>, where filename is what you inherited.</para>
|
||||
</section>
|
||||
<section>
|
||||
<title>Tasks</title>
|
||||
<para><emphasis>NOTE:</emphasis> This is only supported in .bb and .bbclass files.</para>
|
||||
<para>In BitBake, each step that needs to be run for a given .bb is known as a task. There is a command <literal>addtask</literal> to add new tasks (must be a defined Python executable metadata and must start with <quote>do_</quote>) and describe intertask dependencies.</para>
|
||||
<para><screen>python do_printdate () {
|
||||
import time
|
||||
print time.strftime('%Y%m%d', time.gmtime())
|
||||
}
|
||||
|
||||
addtask printdate before do_build</screen></para>
|
||||
<para>This defines the necessary Python function and adds it as a task which is now a dependency of do_build, the default task. If anyone executes the do_build task, that will result in do_printdate being run first.</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Task Flags</title>
|
||||
<para>Tasks support a number of flags which control various functionality of the task. These are as follows:</para>
|
||||
<para>'dirs' - directories which should be created before the task runs</para>
|
||||
<para>'cleandirs' - directories which should created before the task runs but should be empty</para>
|
||||
<para>'noexec' - marks the tasks as being empty and no execution required. These are used as dependency placeholders or used when added tasks need to be subsequently disabled.</para>
|
||||
<para>'nostamp' - don't generate a stamp file for a task. This means the task is always rexecuted.</para>
|
||||
<para>'fakeroot' - this task needs to be run in a fakeroot environment, obtained by adding the variables in FAKEROOTENV to the environment.</para>
|
||||
<para>'umask' - the umask to run the task under.</para>
|
||||
<para> For the 'deptask', 'rdeptask', 'depends', 'rdepends' and 'recrdeptask' flags please see the dependencies section.</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Events</title>
|
||||
<para><emphasis>NOTE:</emphasis> This is only supported in .bb and .bbclass files.</para>
|
||||
<para>BitBake allows installation of event handlers. Events are triggered at certain points during operation, such as the beginning of operation against a given .bb, the start of a given task, task failure, task success, et cetera. The intent is to make it easy to do things like email notification on build failure.</para>
|
||||
<para><screen>addhandler myclass_eventhandler
|
||||
python myclass_eventhandler() {
|
||||
from bb.event import getName
|
||||
from bb import data
|
||||
|
||||
print("The name of the Event is %s" % getName(e))
|
||||
print("The file we run for is %s" % data.getVar('FILE', e.data, True))
|
||||
}
|
||||
</screen></para><para>
|
||||
This event handler gets called every time an event is triggered. A global variable <varname>e</varname> is defined. <varname>e</varname>.data contains an instance of bb.data. With the getName(<varname>e</varname>)
|
||||
method one can get the name of the triggered event.</para><para>The above event handler prints the name
|
||||
of the event and the content of the <varname>FILE</varname> variable.</para>
|
||||
</section>
|
||||
<section>
|
||||
<title>Variants</title>
|
||||
<para>Two BitBake features exist to facilitate the creation of multiple buildable incarnations from a single recipe file.</para>
|
||||
<para>The first is <varname>BBCLASSEXTEND</varname>. This variable is a space separated list of classes used to "extend" the recipe for each variant. As an example, setting <screen>BBCLASSEXTEND = "native"</screen> results in a second incarnation of the current recipe being available. This second incarnation will have the "native" class inherited.</para>
|
||||
<para>The second feature is <varname>BBVERSIONS</varname>. This variable allows a single recipe to build multiple versions of a project from a single recipe file, and allows you to specify conditional metadata (using the <varname>OVERRIDES</varname> mechanism) for a single version, or an optionally named range of versions:</para>
|
||||
<para><screen>BBVERSIONS = "1.0 2.0 git"
|
||||
SRC_URI_git = "git://someurl/somepath.git"</screen></para>
|
||||
<para><screen>BBVERSIONS = "1.0.[0-6]:1.0.0+ \
|
||||
1.0.[7-9]:1.0.7+"
|
||||
SRC_URI_append_1.0.7+ = "file://some_patch_which_the_new_versions_need.patch;patch=1"</screen></para>
|
||||
<para>Note that the name of the range will default to the original version of the recipe, so given OE, a recipe file of foo_1.0.0+.bb will default the name of its versions to 1.0.0+. This is useful, as the range name is not only placed into overrides; it's also made available for the metadata to use in the form of the <varname>BPV</varname> variable, for use in file:// search paths (<varname>FILESPATH</varname>).</para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Variable interaction: Worked Examples</title>
|
||||
<para>Despite the documentation of the different forms of variable definition above, it can be hard to work out what happens when variable operators are combined. This section documents some common questions people have regarding the way variables interact.</para>
|
||||
|
||||
<section>
|
||||
<title>Override and append ordering</title>
|
||||
|
||||
<para>There is often confusion about which order overrides and the various append operators take effect.</para>
|
||||
|
||||
<para><screen><varname>OVERRIDES</varname> = "foo"
|
||||
<varname>A_foo_append</varname> = "X"</screen></para>
|
||||
<para>In this case, X is unconditionally appended to the variable <varname>A_foo</varname>. Since foo is an override, A_foo would then replace <varname>A</varname>.</para>
|
||||
|
||||
<para><screen><varname>OVERRIDES</varname> = "foo"
|
||||
<varname>A</varname> = "X"
|
||||
<varname>A_append_foo</varname> = "Y"</screen></para>
|
||||
<para>In this case, only when foo is in OVERRIDES, Y is appended to the variable <varname>A</varname> so the value of <varname>A</varname> would become XY (NB: no spaces are appended).</para>
|
||||
|
||||
<para><screen><varname>OVERRIDES</varname> = "foo"
|
||||
<varname>A_foo_append</varname> = "X"
|
||||
<varname>A_foo_append</varname> += "Y"</screen></para>
|
||||
<para>This behaves as per the first case above, but the value of <varname>A</varname> would be "X Y" instead of just "X".</para>
|
||||
|
||||
<para><screen><varname>A</varname> = "1"
|
||||
<varname>A_append</varname> = "2"
|
||||
<varname>A_append</varname> = "3"
|
||||
<varname>A</varname> += "4"
|
||||
<varname>A</varname> .= "5"</screen></para>
|
||||
|
||||
<para>Would ultimately result in <varname>A</varname> taking the value "1 4523" since the _append operator executes at the same time as the expansion of other overrides.</para>
|
||||
|
||||
</section>
|
||||
<section>
|
||||
<title>Key Expansion</title>
|
||||
|
||||
<para>Key expansion happens at the data store finalisation time just before overrides are expanded.</para>
|
||||
|
||||
<para><screen><varname>A${B}</varname> = "X"
|
||||
<varname>B</varname> = "2"
|
||||
<varname>A2</varname> = "Y"</screen></para>
|
||||
<para>So in this case <varname>A2</varname> would take the value of "X".</para>
|
||||
</section>
|
||||
|
||||
</section>
|
||||
<section>
|
||||
<title>Dependency handling</title>
|
||||
<para>BitBake handles dependencies at the task level since to allow for efficient operation with multiple processed executing in parallel. A robust method of specifying task dependencies is therefore needed. </para>
|
||||
<section>
|
||||
<title>Dependencies internal to the .bb file</title>
|
||||
<para>Where the dependencies are internal to a given .bb file, the dependencies are handled by the previously detailed addtask directive.</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Build Dependencies</title>
|
||||
<para>DEPENDS lists build time dependencies. The 'deptask' flag for tasks is used to signify the task of each item listed in DEPENDS which must have completed before that task can be executed.</para>
|
||||
<para><screen>do_configure[deptask] = "do_populate_staging"</screen></para>
|
||||
<para>means the do_populate_staging task of each item in DEPENDS must have completed before do_configure can execute.</para>
|
||||
</section>
|
||||
<section>
|
||||
<title>Runtime Dependencies</title>
|
||||
<para>The PACKAGES variable lists runtime packages and each of these can have RDEPENDS and RRECOMMENDS runtime dependencies. The 'rdeptask' flag for tasks is used to signify the task of each item runtime dependency which must have completed before that task can be executed.</para>
|
||||
<para><screen>do_package_write[rdeptask] = "do_package"</screen></para>
|
||||
<para>means the do_package task of each item in RDEPENDS must have completed before do_package_write can execute.</para>
|
||||
</section>
|
||||
<section>
|
||||
<title>Recursive Dependencies</title>
|
||||
<para>These are specified with the 'recrdeptask' flag which is used signify the task(s) of dependencies which must have completed before that task can be executed. It works by looking though the build and runtime dependencies of the current recipe as well as any inter-task dependencies the task has, then adding a dependency on the listed task. It will then recurse through the dependencies of those tasks and so on.</para>
|
||||
<para>It may be desireable to recurse not just through the dependencies of those tasks but through the build and runtime dependencies of dependent tasks too. If that is the case, the taskname itself should be referenced in the task list, e.g. do_a[recrdeptask] = "do_a do_b".</para>
|
||||
</section>
|
||||
<section>
|
||||
<title>Inter task</title>
|
||||
<para>The 'depends' flag for tasks is a more generic form of which allows an interdependency on specific tasks rather than specifying the data in DEPENDS.</para>
|
||||
<para><screen>do_patch[depends] = "quilt-native:do_populate_staging"</screen></para>
|
||||
<para>means the do_populate_staging task of the target quilt-native must have completed before the do_patch can execute.</para>
|
||||
<para>The 'rdepends' flag works in a similar way but takes targets in the runtime namespace instead of the build time dependency namespace.</para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Parsing</title>
|
||||
<section>
|
||||
<title>Configuration files</title>
|
||||
<para>The first kind of metadata in BitBake is configuration metadata. This metadata is global, and therefore affects <emphasis>all</emphasis> packages and tasks which are executed.</para>
|
||||
<para>BitBake will first search the current working directory for an optional "conf/bblayers.conf" configuration file. This file is expected to contain a BBLAYERS variable which is a space delimited list of 'layer' directories. For each directory in this list, a "conf/layer.conf" file will be searched for and parsed with the LAYERDIR variable being set to the directory where the layer was found. The idea is these files will setup BBPATH and other variables correctly for a given build directory automatically for the user.</para>
|
||||
<para>BitBake will then expect to find 'conf/bitbake.conf' somewhere in the user specified <envar>BBPATH</envar>. That configuration file generally has include directives to pull in any other metadata (generally files specific to architecture, machine, <emphasis>local</emphasis> and so on).</para>
|
||||
<para>Only variable definitions and include directives are allowed in .conf files.</para>
|
||||
</section>
|
||||
<section>
|
||||
<title>Classes</title>
|
||||
<para>BitBake classes are our rudimentary inheritance mechanism. As briefly mentioned in the metadata introduction, they're parsed when an <literal>inherit</literal> directive is encountered, and they are located in classes/ relative to the directories in <envar>BBPATH</envar>.</para>
|
||||
</section>
|
||||
<section>
|
||||
<title>.bb files</title>
|
||||
<para>A BitBake (.bb) file is a logical unit of tasks to be executed. Normally this is a package to be built. Inter-.bb dependencies are obeyed. The files themselves are located via the <varname>BBFILES</varname> variable, which is set to a space separated list of .bb files, and does handle wildcards.</para>
|
||||
</section>
|
||||
</section>
|
||||
</chapter>
|
||||
|
||||
<chapter>
|
||||
<title>File download support</title>
|
||||
<section>
|
||||
<title>Overview</title>
|
||||
<para>BitBake provides support to download files this procedure is called fetching and it handled by the fetch and fetch2 modules. At this point the original fetch code is considered to be replaced by fetch2 and this manual only related to the fetch2 codebase.</para>
|
||||
|
||||
<para>The SRC_URI is normally used to tell BitBake which files to fetch. The next sections will describe the available fetchers and their options. Each fetcher honors a set of variables and per URI parameters separated by a <quote>;</quote> consisting of a key and a value. The semantics of the variables and parameters are defined by the fetcher. BitBake tries to have consistent semantics between the different fetchers.
|
||||
</para>
|
||||
|
||||
<para>The overall fetch process is that first, fetches are attempted from PREMIRRORS. If those don't work, the original SRC_URI is attempted and if that fails, BitBake will fall back to MIRRORS. Cross urls are supported, so its possible to mirror a git repository on an http server as a tarball for example. Some example commonly used mirror definitions are:</para>
|
||||
|
||||
<para><screen><varname>PREMIRRORS</varname> ?= "\
|
||||
bzr://.*/.* http://somemirror.org/sources/ \n \
|
||||
cvs://.*/.* http://somemirror.org/sources/ \n \
|
||||
git://.*/.* http://somemirror.org/sources/ \n \
|
||||
hg://.*/.* http://somemirror.org/sources/ \n \
|
||||
osc://.*/.* http://somemirror.org/sources/ \n \
|
||||
p4://.*/.* http://somemirror.org/sources/ \n \
|
||||
svk://.*/.* http://somemirror.org/sources/ \n \
|
||||
svn://.*/.* http://somemirror.org/sources/ \n"
|
||||
|
||||
<varname>MIRRORS</varname> =+ "\
|
||||
ftp://.*/.* http://somemirror.org/sources/ \n \
|
||||
http://.*/.* http://somemirror.org/sources/ \n \
|
||||
https://.*/.* http://somemirror.org/sources/ \n"</screen></para>
|
||||
|
||||
<para>Non-local downloaded output is placed into the directory specified by the <varname>DL_DIR</varname>. For non local archive downloads the code can verify sha256 and md5 checksums for the download to ensure the file has been downloaded correctly. These may be specified either in the form <varname>SRC_URI[md5sum]</varname> for the md5 checksum and <varname>SRC_URI[sha256sum]</varname> for the sha256 checksum or as parameters on the SRC_URI such as SRC_URI="http://example.com/foobar.tar.bz2;md5sum=4a8e0f237e961fd7785d19d07fdb994d". If <varname>BB_STRICT_CHECKSUM</varname> is set, any download without a checksum will trigger an error message. In cases where multiple files are listed in SRC_URI, the name parameter is used assign names to the urls and these are then specified in the checksums in the form SRC_URI[name.sha256sum].</para>
|
||||
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Local file fetcher</title>
|
||||
<para>The URN for the local file fetcher is <emphasis>file</emphasis>. The filename can be either absolute or relative. If the filename is relative, <varname>FILESPATH</varname> and failing that <varname>FILESDIR</varname> will be used to find the appropriate relative file. The metadata usually extend these variables to include variations of the values in <varname>OVERRIDES</varname>. Single files and complete directories can be specified.
|
||||
<screen><varname>SRC_URI</varname>= "file://relativefile.patch"
|
||||
<varname>SRC_URI</varname>= "file://relativefile.patch;this=ignored"
|
||||
<varname>SRC_URI</varname>= "file:///Users/ich/very_important_software"
|
||||
</screen>
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>CVS fetcher</title>
|
||||
<para>The URN for the CVS fetcher is <emphasis>cvs</emphasis>. This fetcher honors the variables <varname>CVSDIR</varname>, <varname>SRCDATE</varname>, <varname>FETCHCOMMAND_cvs</varname>, <varname>UPDATECOMMAND_cvs</varname>. <varname>DL_DIR</varname> specifies where a temporary checkout is saved. <varname>SRCDATE</varname> specifies which date to use when doing the fetching (the special value of "now" will cause the checkout to be updated on every build). <varname>FETCHCOMMAND</varname> and <varname>UPDATECOMMAND</varname> specify which executables to use for the CVS checkout or update.
|
||||
</para>
|
||||
<para>The supported parameters are <varname>module</varname>, <varname>tag</varname>, <varname>date</varname>, <varname>method</varname>, <varname>localdir</varname>, <varname>rsh</varname> and <varname>scmdata</varname>. The <varname>module</varname> specifies which module to check out, the <varname>tag</varname> describes which CVS TAG should be used for the checkout. By default the TAG is empty. A <varname>date</varname> can be specified to override the SRCDATE of the configuration to checkout a specific date. The special value of "now" will cause the checkout to be updated on every build.<varname>method</varname> is by default <emphasis>pserver</emphasis>. If <emphasis>ext</emphasis> is used the <varname>rsh</varname> parameter will be evaluated and <varname>CVS_RSH</varname> will be set. Finally, <varname>localdir</varname> is used to checkout into a special directory relative to <varname>CVSDIR</varname>.
|
||||
|
||||
<screen><varname>SRC_URI</varname> = "cvs://CVSROOT;module=mymodule;tag=some-version;method=ext"
|
||||
<varname>SRC_URI</varname> = "cvs://CVSROOT;module=mymodule;date=20060126;localdir=usethat"
|
||||
</screen>
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>HTTP/FTP fetcher</title>
|
||||
<para>The URNs for the HTTP/FTP fetcher are <emphasis>http</emphasis>, <emphasis>https</emphasis> and <emphasis>ftp</emphasis>. This fetcher honors the variables <varname>FETCHCOMMAND_wget</varname>. <varname>FETCHCOMMAND</varname> contains the command used for fetching. <quote>${URI}</quote> and <quote>${FILES}</quote> will be replaced by the URI and basename of the file to be fetched.
|
||||
</para>
|
||||
<para><screen><varname>SRC_URI</varname> = "http://oe.handhelds.org/not_there.aac"
|
||||
<varname>SRC_URI</varname> = "ftp://oe.handhelds.org/not_there_as_well.aac"
|
||||
<varname>SRC_URI</varname> = "ftp://you@oe.handheld.sorg/home/you/secret.plan"
|
||||
</screen></para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>SVN fetcher</title>
|
||||
<para>The URN for the SVN fetcher is <emphasis>svn</emphasis>.
|
||||
</para>
|
||||
<para>This fetcher honors the variables <varname>FETCHCOMMAND_svn</varname>, <varname>SVNDIR</varname>, <varname>SRCREV</varname>. <varname>FETCHCOMMAND</varname> contains the subversion command. <varname>SRCREV</varname> specifies which revision to use when doing the fetching.
|
||||
</para>
|
||||
<para>The supported parameters are <varname>proto</varname>, <varname>rev</varname> and <varname>scmdata</varname>. <varname>proto</varname> is the Subversion protocol, <varname>rev</varname> is the Subversion revision. If <varname>scmdata</varname> is set to <quote>keep</quote>, the <quote>.svn</quote> directories will be available during compile-time.
|
||||
</para>
|
||||
<para><screen><varname>SRC_URI</varname> = "svn://svn.oe.handhelds.org/svn;module=vip;proto=http;rev=667"
|
||||
<varname>SRC_URI</varname> = "svn://svn.oe.handhelds.org/svn/;module=opie;proto=svn+ssh;date=20060126"
|
||||
</screen></para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>GIT fetcher</title>
|
||||
<para>The URN for the GIT Fetcher is <emphasis>git</emphasis>.
|
||||
</para>
|
||||
<para>The variable <varname>GITDIR</varname> will be used as the base directory where the git tree is cloned to.
|
||||
</para>
|
||||
<para>The parameters are <emphasis>tag</emphasis>, <emphasis>protocol</emphasis> and <emphasis>scmdata</emphasis>. <emphasis>tag</emphasis> is a Git tag, the default is <quote>master</quote>. <emphasis>protocol</emphasis> is the Git protocol to use and defaults to <quote>git</quote> if a hostname is set, otherwise its <quote>file</quote>. If <emphasis>scmdata</emphasis> is set to <quote>keep</quote>, the <quote>.git</quote> directory will be available during compile-time.
|
||||
</para>
|
||||
<para><screen><varname>SRC_URI</varname> = "git://git.oe.handhelds.org/git/vip.git;tag=version-1"
|
||||
<varname>SRC_URI</varname> = "git://git.oe.handhelds.org/git/vip.git;protocol=http"
|
||||
</screen></para>
|
||||
</section>
|
||||
|
||||
</chapter>
|
||||
|
||||
|
||||
<chapter>
|
||||
<title>The BitBake command</title>
|
||||
<section>
|
||||
<title>Introduction</title>
|
||||
<para>bitbake is the primary command in the system. It facilitates executing tasks in a single .bb file, or executing a given task on a set of multiple .bb files, accounting for interdependencies amongst them.</para>
|
||||
</section>
|
||||
<section>
|
||||
<title>Usage and syntax</title>
|
||||
<para>
|
||||
<screen><prompt>$ </prompt>bitbake --help
|
||||
usage: bitbake [options] [package ...]
|
||||
|
||||
Executes the specified task (default is 'build') for a given set of BitBake files.
|
||||
It expects that BBFILES is defined, which is a space separated list of files to
|
||||
be executed. BBFILES does support wildcards.
|
||||
Default BBFILES are the .bb files in the current directory.
|
||||
|
||||
options:
|
||||
--version show program's version number and exit
|
||||
-h, --help show this help message and exit
|
||||
-b BUILDFILE, --buildfile=BUILDFILE
|
||||
execute the task against this .bb file, rather than a
|
||||
package from BBFILES.
|
||||
-k, --continue continue as much as possible after an error. While the
|
||||
target that failed, and those that depend on it,
|
||||
cannot be remade, the other dependencies of these
|
||||
targets can be processed all the same.
|
||||
-f, --force force run of specified cmd, regardless of stamp status
|
||||
-i, --interactive drop into the interactive mode also called the BitBake
|
||||
shell.
|
||||
-c CMD, --cmd=CMD Specify task to execute. Note that this only executes
|
||||
the specified task for the providee and the packages
|
||||
it depends on, i.e. 'compile' does not implicitly call
|
||||
stage for the dependencies (IOW: use only if you know
|
||||
what you are doing). Depending on the base.bbclass a
|
||||
listtasks task is defined and will show available
|
||||
tasks
|
||||
-r FILE, --read=FILE read the specified file before bitbake.conf
|
||||
-v, --verbose output more chit-chat to the terminal
|
||||
-D, --debug Increase the debug level. You can specify this more
|
||||
than once.
|
||||
-n, --dry-run don't execute, just go through the motions
|
||||
-p, --parse-only quit after parsing the BB files (developers only)
|
||||
-s, --show-versions show current and preferred versions of all packages
|
||||
-e, --environment show the global or per-package environment (this is
|
||||
what used to be bbread)
|
||||
-g, --graphviz emit the dependency trees of the specified packages in
|
||||
the dot syntax
|
||||
-I IGNORED_DOT_DEPS, --ignore-deps=IGNORED_DOT_DEPS
|
||||
Stop processing at the given list of dependencies when
|
||||
generating dependency graphs. This can help to make
|
||||
the graph more appealing
|
||||
-l DEBUG_DOMAINS, --log-domains=DEBUG_DOMAINS
|
||||
Show debug logging for the specified logging domains
|
||||
-P, --profile profile the command and print a report
|
||||
|
||||
|
||||
</screen>
|
||||
</para>
|
||||
<para>
|
||||
<example>
|
||||
<title>Executing a task against a single .bb</title>
|
||||
<para>Executing tasks for a single file is relatively simple. You specify the file in question, and BitBake parses it and executes the specified task (or <quote>build</quote> by default). It obeys intertask dependencies when doing so.</para>
|
||||
<para><quote>clean</quote> task:</para>
|
||||
<para><screen><prompt>$ </prompt>bitbake -b blah_1.0.bb -c clean</screen></para>
|
||||
<para><quote>build</quote> task:</para>
|
||||
<para><screen><prompt>$ </prompt>bitbake -b blah_1.0.bb</screen></para>
|
||||
</example>
|
||||
</para>
|
||||
<para>
|
||||
<example>
|
||||
<title>Executing tasks against a set of .bb files</title>
|
||||
<para>There are a number of additional complexities introduced when one wants to manage multiple .bb files. Clearly there needs to be a way to tell BitBake what files are available, and of those, which we want to execute at this time. There also needs to be a way for each .bb to express its dependencies, both for build time and runtime. There must be a way for the user to express their preferences when multiple .bb's provide the same functionality, or when there are multiple versions of a .bb.</para>
|
||||
<para>The next section, Metadata, outlines how to specify such things.</para>
|
||||
<para>Note that the bitbake command, when not using --buildfile, accepts a <varname>PROVIDER</varname>, not a filename or anything else. By default, a .bb generally PROVIDES its packagename, packagename-version, and packagename-version-revision.</para>
|
||||
<screen><prompt>$ </prompt>bitbake blah</screen>
|
||||
<screen><prompt>$ </prompt>bitbake blah-1.0</screen>
|
||||
<screen><prompt>$ </prompt>bitbake blah-1.0-r0</screen>
|
||||
<screen><prompt>$ </prompt>bitbake -c clean blah</screen>
|
||||
<screen><prompt>$ </prompt>bitbake virtual/whatever</screen>
|
||||
<screen><prompt>$ </prompt>bitbake -c clean virtual/whatever</screen>
|
||||
</example>
|
||||
<example>
|
||||
<title>Generating dependency graphs</title>
|
||||
<para>BitBake is able to generate dependency graphs using the dot syntax. These graphs can be converted
|
||||
to images using the <application>dot</application> application from <ulink url="http://www.graphviz.org">Graphviz</ulink>.
|
||||
Two files will be written into the current working directory, <emphasis>depends.dot</emphasis> containing dependency information at the package level and <emphasis>task-depends.dot</emphasis> containing a breakdown of the dependencies at the task level. To stop depending on common depends, one can use the <prompt>-I depend</prompt> to omit these from the graph. This can lead to more readable graphs. This way, <varname>DEPENDS</varname> from inherited classes such as base.bbclass can be removed from the graph.</para>
|
||||
<screen><prompt>$ </prompt>bitbake -g blah</screen>
|
||||
<screen><prompt>$ </prompt>bitbake -g -I virtual/whatever -I bloom blah</screen>
|
||||
</example>
|
||||
</para>
|
||||
</section>
|
||||
<section>
|
||||
<title>Special variables</title>
|
||||
<para>Certain variables affect BitBake operation:</para>
|
||||
<section>
|
||||
<title><varname>BB_NUMBER_THREADS</varname></title>
|
||||
<para> The number of threads BitBake should run at once (default: 1).</para>
|
||||
</section>
|
||||
</section>
|
||||
<section>
|
||||
<title>Metadata</title>
|
||||
<para>As you may have seen in the usage information, or in the information about .bb files, the <varname>BBFILES</varname> variable is how the BitBake tool locates its files. This variable is a space separated list of files that are available, and supports wildcards.
|
||||
<example>
|
||||
<title>Setting BBFILES</title>
|
||||
<programlisting><varname>BBFILES</varname> = "/path/to/bbfiles/*.bb"</programlisting>
|
||||
</example></para>
|
||||
<para>With regard to dependencies, it expects the .bb to define a <varname>DEPENDS</varname> variable, which contains a space separated list of <quote>package names</quote>, which themselves are the <varname>PN</varname> variable. The <varname>PN</varname> variable is, in general, set to a component of the .bb filename by default.</para>
|
||||
<example>
|
||||
<title>Depending on another .bb</title>
|
||||
<para>a.bb:
|
||||
<screen>PN = "package-a"
|
||||
DEPENDS += "package-b"</screen>
|
||||
</para>
|
||||
<para>b.bb:
|
||||
<screen>PN = "package-b"</screen>
|
||||
</para>
|
||||
</example>
|
||||
<example>
|
||||
<title>Using PROVIDES</title>
|
||||
<para>This example shows the usage of the <varname>PROVIDES</varname> variable, which allows a given .bb to specify what functionality it provides.</para>
|
||||
<para>package1.bb:
|
||||
<screen>PROVIDES += "virtual/package"</screen>
|
||||
</para>
|
||||
<para>package2.bb:
|
||||
<screen>DEPENDS += "virtual/package"</screen>
|
||||
</para>
|
||||
<para>package3.bb:
|
||||
<screen>PROVIDES += "virtual/package"</screen>
|
||||
</para>
|
||||
<para>As you can see, we have two different .bb's that provide the same functionality (virtual/package). Clearly, there needs to be a way for the person running BitBake to control which of those providers gets used. There is, indeed, such a way.</para>
|
||||
<para>The following would go into a .conf file, to select package1:
|
||||
<screen>PREFERRED_PROVIDER_virtual/package = "package1"</screen>
|
||||
</para>
|
||||
</example>
|
||||
<example>
|
||||
<title>Specifying version preference</title>
|
||||
<para>When there are multiple <quote>versions</quote> of a given package, BitBake defaults to selecting the most recent version, unless otherwise specified. If the .bb in question has a <varname>DEFAULT_PREFERENCE</varname> set lower than the other .bb's (default is 0), then it will not be selected. This allows the person or persons maintaining the repository of .bb files to specify their preference for the default selected version. In addition, the user can specify their preferred version.</para>
|
||||
<para>If the first .bb is named <filename>a_1.1.bb</filename>, then the <varname>PN</varname> variable will be set to <quote>a</quote>, and the <varname>PV</varname> variable will be set to 1.1.</para>
|
||||
<para>If we then have an <filename>a_1.2.bb</filename>, BitBake will choose 1.2 by default. However, if we define the following variable in a .conf that BitBake parses, we can change that.
|
||||
<screen>PREFERRED_VERSION_a = "1.1"</screen>
|
||||
</para>
|
||||
</example>
|
||||
<example>
|
||||
<title>Using <quote>bbfile collections</quote></title>
|
||||
<para>bbfile collections exist to allow the user to have multiple repositories of bbfiles that contain the same exact package. For example, one could easily use them to make one's own local copy of an upstream repository, but with custom modifications that one does not want upstream. Usage:</para>
|
||||
<screen>BBFILES = "/stuff/openembedded/*/*.bb /stuff/openembedded.modified/*/*.bb"
|
||||
BBFILE_COLLECTIONS = "upstream local"
|
||||
BBFILE_PATTERN_upstream = "^/stuff/openembedded/"
|
||||
BBFILE_PATTERN_local = "^/stuff/openembedded.modified/"
|
||||
BBFILE_PRIORITY_upstream = "5"
|
||||
BBFILE_PRIORITY_local = "10"</screen>
|
||||
</example>
|
||||
</section>
|
||||
</chapter>
|
||||
</book>
|
||||
@@ -1,59 +0,0 @@
|
||||
<!ENTITY DISTRO "1.4">
|
||||
<!ENTITY DISTRO_NAME "tbd">
|
||||
<!ENTITY YOCTO_DOC_VERSION "1.4">
|
||||
<!ENTITY POKYVERSION "8.0">
|
||||
<!ENTITY YOCTO_POKY "poky-&DISTRO_NAME;-&POKYVERSION;">
|
||||
<!ENTITY COPYRIGHT_YEAR "2010-2013">
|
||||
<!ENTITY YOCTO_DL_URL "http://downloads.yoctoproject.org">
|
||||
<!ENTITY YOCTO_HOME_URL "http://www.yoctoproject.org">
|
||||
<!ENTITY YOCTO_LISTS_URL "http://lists.yoctoproject.org">
|
||||
<!ENTITY YOCTO_BUGZILLA_URL "http://bugzilla.yoctoproject.org">
|
||||
<!ENTITY YOCTO_WIKI_URL "https://wiki.yoctoproject.org">
|
||||
<!ENTITY YOCTO_AB_URL "http://autobuilder.yoctoproject.org">
|
||||
<!ENTITY YOCTO_GIT_URL "http://git.yoctoproject.org">
|
||||
<!ENTITY YOCTO_ADTREPO_URL "http://adtrepo.yoctoproject.org">
|
||||
<!ENTITY OE_HOME_URL "http://www.openembedded.org">
|
||||
<!ENTITY OE_LISTS_URL "http://lists.linuxtogo.org/cgi-bin/mailman">
|
||||
<!ENTITY OE_DOCS_URL "http://docs.openembedded.org">
|
||||
<!ENTITY OH_HOME_URL "http://o-hand.com">
|
||||
<!ENTITY BITBAKE_HOME_URL "http://developer.berlios.de/projects/bitbake/">
|
||||
<!ENTITY ECLIPSE_MAIN_URL "http://www.eclipse.org/downloads">
|
||||
<!ENTITY ECLIPSE_DL_URL "http://download.eclipse.org">
|
||||
<!ENTITY ECLIPSE_DL_PLUGIN_URL "&YOCTO_DL_URL;/releases/eclipse-plugin/&DISTRO;">
|
||||
<!ENTITY ECLIPSE_UPDATES_URL "&ECLIPSE_DL_URL;/tm/updates/3.3">
|
||||
<!ENTITY ECLIPSE_INDIGO_URL "&ECLIPSE_DL_URL;/releases/indigo">
|
||||
<!ENTITY ECLIPSE_JUNO_URL "&ECLIPSE_DL_URL;/releases/juno">
|
||||
<!ENTITY ECLIPSE_INDIGO_CDT_URL "&ECLIPSE_DL_URL;tools/cdt/releases/indigo">
|
||||
<!ENTITY YOCTO_DOCS_URL "&YOCTO_HOME_URL;/docs">
|
||||
<!ENTITY YOCTO_SOURCES_URL "&YOCTO_HOME_URL;/sources/">
|
||||
<!ENTITY YOCTO_AB_PORT_URL "&YOCTO_AB_URL;:8010">
|
||||
<!ENTITY YOCTO_AB_NIGHTLY_URL "&YOCTO_AB_URL;/nightly/">
|
||||
<!ENTITY YOCTO_POKY_URL "&YOCTO_DL_URL;/releases/poky/">
|
||||
<!ENTITY YOCTO_RELEASE_DL_URL "&YOCTO_DL_URL;/releases/yocto/yocto-&DISTRO;">
|
||||
<!ENTITY YOCTO_TOOLCHAIN_DL_URL "&YOCTO_RELEASE_DL_URL;/toolchain/">
|
||||
<!ENTITY YOCTO_ECLIPSE_DL_URL "&YOCTO_RELEASE_DL_URL;/eclipse-plugin/indigo;">
|
||||
<!ENTITY YOCTO_ADTINSTALLER_DL_URL "&YOCTO_RELEASE_DL_URL;/adt_installer">
|
||||
<!ENTITY YOCTO_POKY_DL_URL "&YOCTO_RELEASE_DL_URL;/&YOCTO_POKY;.tar.bz2">
|
||||
<!ENTITY YOCTO_MACHINES_DL_URL "&YOCTO_RELEASE_DL_URL;/machines">
|
||||
<!ENTITY YOCTO_QEMU_DL_URL "&YOCTO_MACHINES_DL_URL;/qemu">
|
||||
<!ENTITY YOCTO_PYTHON-i686_DL_URL "&YOCTO_DL_URL;/releases/miscsupport/python-nativesdk-standalone-i686.tar.bz2">
|
||||
<!ENTITY YOCTO_PYTHON-x86_64_DL_URL "&YOCTO_DL_URL;/releases/miscsupport/python-nativesdk-standalone-x86_64.tar.bz2">
|
||||
<!ENTITY YOCTO_DOCS_QS_URL "&YOCTO_DOCS_URL;/&YOCTO_DOC_VERSION;/yocto-project-qs/yocto-project-qs.html">
|
||||
<!ENTITY YOCTO_DOCS_ADT_URL "&YOCTO_DOCS_URL;/&YOCTO_DOC_VERSION;/adt-manual/adt-manual.html">
|
||||
<!ENTITY YOCTO_DOCS_REF_URL "&YOCTO_DOCS_URL;/&YOCTO_DOC_VERSION;/ref-manual/ref-manual.html">
|
||||
<!ENTITY YOCTO_DOCS_BSP_URL "&YOCTO_DOCS_URL;/&YOCTO_DOC_VERSION;/bsp-guide/bsp-guide.html">
|
||||
<!ENTITY YOCTO_DOCS_DEV_URL "&YOCTO_DOCS_URL;/&YOCTO_DOC_VERSION;/dev-manual/dev-manual.html">
|
||||
<!ENTITY YOCTO_DOCS_KERNEL_URL "&YOCTO_DOCS_URL;/&YOCTO_DOC_VERSION;/kernel-manual/kernel-manual.html">
|
||||
<!ENTITY YOCTO_ADTPATH_DIR "/opt/poky/&DISTRO;">
|
||||
<!ENTITY YOCTO_POKY_TARBALL "&YOCTO_POKY;.tar.bz2">
|
||||
<!ENTITY OE_INIT_PATH "&YOCTO_POKY;/oe-init-build-env">
|
||||
<!ENTITY OE_INIT_FILE "oe-init-build-env">
|
||||
<!ENTITY UBUNTU_HOST_PACKAGES_ESSENTIAL "gawk wget git-core diffstat unzip texinfo \
|
||||
build-essential chrpath">
|
||||
<!ENTITY FEDORA_HOST_PACKAGES_ESSENTIAL "gawk make wget tar bzip2 gzip python unzip perl patch \
|
||||
diffutils diffstat git cpp gcc gcc-c++ eglibc-devel texinfo chrpath \
|
||||
ccache">
|
||||
<!ENTITY OPENSUSE_HOST_PACKAGES_ESSENTIAL "python gcc gcc-c++ git chrpath make wget python-xml \
|
||||
diffstat texinfo python-curses">
|
||||
<!ENTITY CENTOS_HOST_PACKAGES_ESSENTIAL "gawk make wget tar bzip2 gzip python unzip perl patch \
|
||||
diffutils diffstat git cpp gcc gcc-c++ glibc-devel texinfo chrpath">
|
||||
BIN
bitbake/doc/template/Vera.ttf
vendored
BIN
bitbake/doc/template/Vera.ttf
vendored
Binary file not shown.
1
bitbake/doc/template/Vera.xml
vendored
1
bitbake/doc/template/Vera.xml
vendored
File diff suppressed because one or more lines are too long
BIN
bitbake/doc/template/VeraMoBd.ttf
vendored
BIN
bitbake/doc/template/VeraMoBd.ttf
vendored
Binary file not shown.
1
bitbake/doc/template/VeraMoBd.xml
vendored
1
bitbake/doc/template/VeraMoBd.xml
vendored
File diff suppressed because one or more lines are too long
BIN
bitbake/doc/template/VeraMono.ttf
vendored
BIN
bitbake/doc/template/VeraMono.ttf
vendored
Binary file not shown.
1
bitbake/doc/template/VeraMono.xml
vendored
1
bitbake/doc/template/VeraMono.xml
vendored
File diff suppressed because one or more lines are too long
64
bitbake/doc/template/db-pdf.xsl
vendored
64
bitbake/doc/template/db-pdf.xsl
vendored
@@ -1,64 +0,0 @@
|
||||
<?xml version='1.0'?>
|
||||
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://www.w3.org/1999/xhtml" xmlns:fo="http://www.w3.org/1999/XSL/Format" version="1.0">
|
||||
|
||||
<xsl:import href="http://docbook.sourceforge.net/release/xsl/current/fo/docbook.xsl" />
|
||||
|
||||
<!-- check project-plan.sh for how this is generated, needed to tweak
|
||||
the cover page
|
||||
-->
|
||||
<xsl:include href="/tmp/titlepage.xsl"/>
|
||||
|
||||
<!-- To force a page break in document, i.e per section add a
|
||||
<?hard-pagebreak?> tag.
|
||||
-->
|
||||
<xsl:template match="processing-instruction('hard-pagebreak')">
|
||||
<fo:block break-before='page' />
|
||||
</xsl:template>
|
||||
|
||||
<!--Fix for defualt indent getting TOC all wierd..
|
||||
See http://sources.redhat.com/ml/docbook-apps/2005-q1/msg00455.html
|
||||
FIXME: must be a better fix
|
||||
-->
|
||||
<xsl:param name="body.start.indent" select="'0'"/>
|
||||
<!--<xsl:param name="title.margin.left" select="'0'"/>-->
|
||||
|
||||
<!-- stop long-ish header titles getting wrapped -->
|
||||
<xsl:param name="header.column.widths">1 10 1</xsl:param>
|
||||
|
||||
<!-- customise headers and footers a little -->
|
||||
|
||||
<xsl:template name="head.sep.rule">
|
||||
<xsl:if test="$header.rule != 0">
|
||||
<xsl:attribute name="border-bottom-width">0.5pt</xsl:attribute>
|
||||
<xsl:attribute name="border-bottom-style">solid</xsl:attribute>
|
||||
<xsl:attribute name="border-bottom-color">#cccccc</xsl:attribute>
|
||||
</xsl:if>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template name="foot.sep.rule">
|
||||
<xsl:if test="$footer.rule != 0">
|
||||
<xsl:attribute name="border-top-width">0.5pt</xsl:attribute>
|
||||
<xsl:attribute name="border-top-style">solid</xsl:attribute>
|
||||
<xsl:attribute name="border-top-color">#cccccc</xsl:attribute>
|
||||
</xsl:if>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:attribute-set name="header.content.properties">
|
||||
<xsl:attribute name="color">#cccccc</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<xsl:attribute-set name="footer.content.properties">
|
||||
<xsl:attribute name="color">#cccccc</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
|
||||
<!-- general settings -->
|
||||
|
||||
<xsl:param name="fop1.extensions" select="1"></xsl:param>
|
||||
<xsl:param name="paper.type" select="'A4'"></xsl:param>
|
||||
<xsl:param name="section.autolabel" select="1"></xsl:param>
|
||||
<xsl:param name="body.font.family" select="'verasans'"></xsl:param>
|
||||
<xsl:param name="title.font.family" select="'verasans'"></xsl:param>
|
||||
<xsl:param name="monospace.font.family" select="'veramono'"></xsl:param>
|
||||
|
||||
</xsl:stylesheet>
|
||||
BIN
bitbake/doc/template/draft.png
vendored
BIN
bitbake/doc/template/draft.png
vendored
Binary file not shown.
|
Before Width: | Height: | Size: 24 KiB |
58
bitbake/doc/template/fop-config.xml
vendored
58
bitbake/doc/template/fop-config.xml
vendored
@@ -1,58 +0,0 @@
|
||||
<fop version="1.0">
|
||||
|
||||
<!-- Strict user configuration -->
|
||||
<strict-configuration>true</strict-configuration>
|
||||
|
||||
<!-- Strict FO validation -->
|
||||
<strict-validation>true</strict-validation>
|
||||
|
||||
<!--
|
||||
Set the baseDir so common/openedhand.svg references in plans still
|
||||
work ok. Note, relative file references to current dir should still work.
|
||||
-->
|
||||
<base>../template</base>
|
||||
<font-base>../template</font-base>
|
||||
|
||||
<!-- Source resolution in dpi (dots/pixels per inch) for determining the
|
||||
size of pixels in SVG and bitmap images, default: 72dpi -->
|
||||
<!-- <source-resolution>72</source-resolution> -->
|
||||
<!-- Target resolution in dpi (dots/pixels per inch) for specifying the
|
||||
target resolution for generated bitmaps, default: 72dpi -->
|
||||
<!-- <target-resolution>72</target-resolution> -->
|
||||
|
||||
<!-- default page-height and page-width, in case
|
||||
value is specified as auto -->
|
||||
<default-page-settings height="11in" width="8.26in"/>
|
||||
|
||||
<!-- <use-cache>false</use-cache> -->
|
||||
|
||||
<renderers>
|
||||
<renderer mime="application/pdf">
|
||||
<fonts>
|
||||
<font metrics-file="VeraMono.xml"
|
||||
kerning="yes"
|
||||
embed-url="VeraMono.ttf">
|
||||
<font-triplet name="veramono" style="normal" weight="normal"/>
|
||||
</font>
|
||||
|
||||
<font metrics-file="VeraMoBd.xml"
|
||||
kerning="yes"
|
||||
embed-url="VeraMoBd.ttf">
|
||||
<font-triplet name="veramono" style="normal" weight="bold"/>
|
||||
</font>
|
||||
|
||||
<font metrics-file="Vera.xml"
|
||||
kerning="yes"
|
||||
embed-url="Vera.ttf">
|
||||
<font-triplet name="verasans" style="normal" weight="normal"/>
|
||||
<font-triplet name="verasans" style="normal" weight="bold"/>
|
||||
<font-triplet name="verasans" style="italic" weight="normal"/>
|
||||
<font-triplet name="verasans" style="italic" weight="bold"/>
|
||||
</font>
|
||||
|
||||
<auto-detect/>
|
||||
</fonts>
|
||||
</renderer>
|
||||
</renderers>
|
||||
</fop>
|
||||
|
||||
1259
bitbake/doc/template/titlepage.templates.xml
vendored
1259
bitbake/doc/template/titlepage.templates.xml
vendored
File diff suppressed because it is too large
Load Diff
@@ -1,51 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
if [ -z "$1" -o -z "$2" ]; then
|
||||
echo "usage: [-v] $0 <docbook file> <templatedir>"
|
||||
echo
|
||||
echo "*NOTE* you need xsltproc, fop and nwalsh docbook stylesheets"
|
||||
echo " installed for this to work!"
|
||||
echo
|
||||
exit 0
|
||||
fi
|
||||
|
||||
FO=`echo $1 | sed s/.xml/.fo/` || exit 1
|
||||
PDF=`echo $1 | sed s/.xml/.pdf/` || exit 1
|
||||
TEMPLATEDIR=$2
|
||||
|
||||
##
|
||||
# These URI should be rewritten by your distribution's xml catalog to
|
||||
# match your localy installed XSL stylesheets.
|
||||
XSL_BASE_URI="http://docbook.sourceforge.net/release/xsl/current"
|
||||
|
||||
# Creates a temporary XSL stylesheet based on titlepage.xsl
|
||||
xsltproc -o /tmp/titlepage.xsl \
|
||||
--xinclude \
|
||||
$XSL_BASE_URI/template/titlepage.xsl \
|
||||
$TEMPLATEDIR/titlepage.templates.xml || exit 1
|
||||
|
||||
# Creates the file needed for FOP
|
||||
xsltproc --xinclude \
|
||||
--stringparam hyphenate false \
|
||||
--stringparam formal.title.placement "figure after" \
|
||||
--stringparam ulink.show 1 \
|
||||
--stringparam body.font.master 9 \
|
||||
--stringparam title.font.master 11 \
|
||||
--stringparam draft.watermark.image "$TEMPLATEDIR/draft.png" \
|
||||
--stringparam chapter.autolabel 1 \
|
||||
--stringparam appendix.autolabel A \
|
||||
--stringparam section.autolabel 1 \
|
||||
--stringparam section.label.includes.component.label 1 \
|
||||
--output $FO \
|
||||
$TEMPLATEDIR/db-pdf.xsl \
|
||||
$1 || exit 1
|
||||
|
||||
# Invokes the Java version of FOP. Uses the additional configuration file common/fop-config.xml
|
||||
fop -c $TEMPLATEDIR/fop-config.xml -fo $FO -pdf $PDF || exit 1
|
||||
|
||||
rm -f $FO
|
||||
rm -f /tmp/titlepage.xsl
|
||||
|
||||
echo
|
||||
echo " #### Success! $PDF ready. ####"
|
||||
echo
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 5.0 KiB |
@@ -1,367 +0,0 @@
|
||||
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
|
||||
|
||||
<chapter>
|
||||
<title>The BitBake Command</title>
|
||||
|
||||
<section id='bitbake-command-introduction'>
|
||||
<title>Introduction</title>
|
||||
|
||||
<para>
|
||||
Bitbake is the primary command in the system.
|
||||
It facilitates executing tasks in a single <filename>.bb</filename>
|
||||
file, or executing a given task on a set of multiple
|
||||
<filename>.bb</filename> files, accounting for interdependencies
|
||||
amongst them.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id='usage-and-syntax'>
|
||||
<title>Usage and syntax</title>
|
||||
|
||||
<para>
|
||||
Following is the usage and syntax for BitBake:
|
||||
<literallayout class='monospaced'>
|
||||
$ bitbake -h
|
||||
Usage: bitbake [options] [recipename/target ...]
|
||||
|
||||
Executes the specified task (default is 'build') for a given set of target recipes (.bb files).
|
||||
It is assumed there is a conf/bblayers.conf available in cwd or in BBPATH which
|
||||
will provide the layer, BBFILES and other configuration information.
|
||||
|
||||
Options:
|
||||
--version show program's version number and exit
|
||||
-h, --help show this help message and exit
|
||||
-b BUILDFILE, --buildfile=BUILDFILE
|
||||
Execute tasks from a specific .bb recipe directly.
|
||||
WARNING: Does not handle any dependencies from other
|
||||
recipes.
|
||||
-k, --continue Continue as much as possible after an error. While the
|
||||
target that failed and anything depending on it cannot
|
||||
be built, as much as possible will be built before
|
||||
stopping.
|
||||
-a, --tryaltconfigs Continue with builds by trying to use alternative
|
||||
providers where possible.
|
||||
-f, --force Force the specified targets/task to run (invalidating
|
||||
any existing stamp file).
|
||||
-c CMD, --cmd=CMD Specify the task to execute. The exact options
|
||||
available depend on the metadata. Some examples might
|
||||
be 'compile' or 'populate_sysroot' or 'listtasks' may
|
||||
give a list of the tasks available.
|
||||
-C INVALIDATE_STAMP, --clear-stamp=INVALIDATE_STAMP
|
||||
Invalidate the stamp for the specified task such as
|
||||
'compile' and then run the default task for the
|
||||
specified target(s).
|
||||
-r PREFILE, --read=PREFILE
|
||||
Read the specified file before bitbake.conf.
|
||||
-R POSTFILE, --postread=POSTFILE
|
||||
Read the specified file after bitbake.conf.
|
||||
-v, --verbose Output more log message data to the terminal.
|
||||
-D, --debug Increase the debug level. You can specify this more
|
||||
than once.
|
||||
-n, --dry-run Don't execute, just go through the motions.
|
||||
-S, --dump-signatures
|
||||
Don't execute, just dump out the signature
|
||||
construction information.
|
||||
-p, --parse-only Quit after parsing the BB recipes.
|
||||
-s, --show-versions Show current and preferred versions of all recipes.
|
||||
-e, --environment Show the global or per-package environment complete
|
||||
with information about where variables were
|
||||
set/changed.
|
||||
-g, --graphviz Save dependency tree information for the specified
|
||||
targets in the dot syntax.
|
||||
-I EXTRA_ASSUME_PROVIDED, --ignore-deps=EXTRA_ASSUME_PROVIDED
|
||||
Assume these dependencies don't exist and are already
|
||||
provided (equivalent to ASSUME_PROVIDED). Useful to
|
||||
make dependency graphs more appealing
|
||||
-l DEBUG_DOMAINS, --log-domains=DEBUG_DOMAINS
|
||||
Show debug logging for the specified logging domains
|
||||
-P, --profile Profile the command and save reports.
|
||||
-u UI, --ui=UI The user interface to use (e.g. knotty, hob, depexp).
|
||||
-t SERVERTYPE, --servertype=SERVERTYPE
|
||||
Choose which server to use, process or xmlrpc.
|
||||
--revisions-changed Set the exit code depending on whether upstream
|
||||
floating revisions have changed or not.
|
||||
--server-only Run bitbake without a UI, only starting a server
|
||||
(cooker) process.
|
||||
-B BIND, --bind=BIND The name/address for the bitbake server to bind to.
|
||||
--no-setscene Do not run any setscene tasks. sstate will be ignored
|
||||
and everything needed, built.
|
||||
--remote-server=REMOTE_SERVER
|
||||
Connect to the specified server.
|
||||
-m, --kill-server Terminate the remote server.
|
||||
--observe-only Connect to a server as an observing-only client.
|
||||
--status-only Check the status of the remote bitbake server.
|
||||
|
||||
</literallayout>
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id='bitbake-examples'>
|
||||
<title>Examples</title>
|
||||
|
||||
<para>
|
||||
This section presents some examples showing how to use BitBake.
|
||||
</para>
|
||||
|
||||
<section id='example-executing-a-task-against-a-single-recipe'>
|
||||
<title>Executing a Task Against a Single Recipe</title>
|
||||
|
||||
<para>
|
||||
Executing tasks for a single recipe file is relatively simple.
|
||||
You specify the file in question, and BitBake parses
|
||||
it and executes the specified task (or “build” by default).
|
||||
BitBake obeys inter-task dependencies when doing
|
||||
so.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The following command runs the clean task on the
|
||||
<filename>foo_1.0.bb</filename> recipe file:
|
||||
<literallayout class='monospaced'>
|
||||
$ bitbake -b foo.bb -c clean
|
||||
</literallayout>
|
||||
The following command runs the build task, which is
|
||||
the default task, on the <filename>foo_1.0.bb</filename>
|
||||
recipe file:
|
||||
<literallayout class='monospaced'>
|
||||
$ bitbake -b foo_1.0.bb
|
||||
</literallayout>
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id='executing-tasks-against-a-set-of-recipe-files'>
|
||||
<title>Executing Tasks Against a Set of Recipe Files</title>
|
||||
|
||||
<para>
|
||||
There are a number of additional complexities introduced
|
||||
when one wants to manage multiple <filename>.bb</filename>
|
||||
files.
|
||||
Clearly there needs to be a way to tell BitBake what
|
||||
files are available, and of those, which we
|
||||
want to execute at this time.
|
||||
There also needs to be a way for each <filename>.bb</filename>
|
||||
to express its dependencies, both for build-time and
|
||||
runtime.
|
||||
There must be a way for the user to express their preferences
|
||||
when multiple recipes provide the same functionality, or when
|
||||
there are multiple versions of a <filename>.bb</filename> file.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The next section, Metadata, outlines how to specify such things.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The <filename>bitbake</filename> command, when not using
|
||||
"--buildfile", accepts a PROVIDER, not a filename or
|
||||
anything else.
|
||||
By default, a <filename>.bb</filename> generally PROVIDES its
|
||||
packagename, packagename-version, and packagename-version-revision.
|
||||
<literallayout class='monospaced'>
|
||||
$ bitbake foo
|
||||
|
||||
$ bitbake foo-1.0
|
||||
|
||||
$ bitbake foo-1.0-r0
|
||||
|
||||
$ bitbake -c clean foo
|
||||
|
||||
$ bitbake virtual/whatever
|
||||
|
||||
$ bitbake -c clean virtual/whatever
|
||||
</literallayout>
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id='generating-dependency-graphs'>
|
||||
<title>Generating Dependency Graphs</title>
|
||||
|
||||
<para>
|
||||
BitBake is able to generate dependency graphs using
|
||||
the dot syntax.
|
||||
These graphs can be converted to images using the dot
|
||||
application from
|
||||
<ulink url='http://www.graphviz.org'>Graphviz</ulink>.
|
||||
Two files will be written into the current working directory:
|
||||
<filename>depends.dot</filename> containing dependency information
|
||||
at the package level and <filename>task-depends.dot</filename>
|
||||
containing a breakdown of the dependencies at the task level.
|
||||
To stop depending on common depends, one can use the "-I" depend
|
||||
option to omit these from the graph.
|
||||
This can lead to more readable graphs.
|
||||
This way, <filename>DEPENDS</filename> from inherited classes
|
||||
such as <filename>base.bbclass</filename> can be removed from the
|
||||
graph.
|
||||
<literallayout class='monospaced'>
|
||||
$ bitbake -g foo
|
||||
|
||||
$ bitbake -g -I virtual/whatever -I bloom foo
|
||||
</literallayout>
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section id='special-variables'>
|
||||
<title>Special Variables</title>
|
||||
|
||||
<para>
|
||||
Certain variables affect BitBake operation:
|
||||
</para>
|
||||
|
||||
<section id='bb-number-threads'>
|
||||
<title><filename>BB_NUMBER_THREADS</filename></title>
|
||||
|
||||
<para>
|
||||
The number of threads BitBake should run at once (default: 1).
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section id='bitbake-command-metadata'>
|
||||
<title>Metadata</title>
|
||||
|
||||
<para>
|
||||
As you may have seen in the usage information, or in the
|
||||
information about <filename>.bb</filename> files, the
|
||||
<filename>BBFILES</filename> variable is how the BitBake
|
||||
tool locates its files.
|
||||
This variable is a space-separated list of files
|
||||
that are available, and supports wildcards.
|
||||
</para>
|
||||
|
||||
<section id='setting-bbfiles'>
|
||||
<title>Setting <filename>BBFILES</filename></title>
|
||||
|
||||
<para>
|
||||
<literallayout class='monospaced'>
|
||||
BBFILES = "/path/to/bbfiles/*.bb"
|
||||
</literallayout>
|
||||
With regard to dependencies, it expects the
|
||||
<filename>.bb</filename> to define a
|
||||
<filename>DEPENDS</filename> variable, which contains a
|
||||
space separated list of “package names”, which themselves
|
||||
are the <filename>PN</filename> variable. The
|
||||
<filename>PN</filename> variable is, in general,
|
||||
set to a component of the <filename>.bb</filename>
|
||||
filename by default.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id='depending-on-another-recipe-file'>
|
||||
<title>Depending on Another Recipe File</title>
|
||||
|
||||
<para>
|
||||
<literallayout class='monospaced'>
|
||||
a.bb:
|
||||
|
||||
PN = "package-a"
|
||||
DEPENDS += "package-b"
|
||||
|
||||
b.bb:
|
||||
|
||||
PN = "package-b"
|
||||
</literallayout>
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id='using-provides'>
|
||||
<title>Using <filename>PROVIDES</filename></title>
|
||||
|
||||
<para>
|
||||
This example shows the usage of the
|
||||
<filename>PROVIDES</filename> variable, which allows a
|
||||
given <filename>.bb</filename> to specify what
|
||||
functionality it provides.
|
||||
<literallayout class='monospaced'>
|
||||
package1.bb:
|
||||
|
||||
PROVIDES += "virtual/package"
|
||||
|
||||
package2.bb:
|
||||
|
||||
DEPENDS += "virtual/package"
|
||||
|
||||
package3.bb:
|
||||
|
||||
PROVIDES += "virtual/package"
|
||||
</literallayout>
|
||||
As you can see, we have two different
|
||||
recipes that provide the same functionality
|
||||
(virtual/package).
|
||||
Clearly, there needs to be a way for the person running
|
||||
BitBake to control which of those providers
|
||||
gets used.
|
||||
There is, indeed, such a way.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The following would go into a <filename>.conf</filename>
|
||||
file, to select package1:
|
||||
<literallayout class='monospaced'>
|
||||
PREFERRED_PROVIDER_virtual/package = "package1"
|
||||
</literallayout>
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id='specifying-version-preference'>
|
||||
<title>Specifying Version Preference</title>
|
||||
|
||||
<para>
|
||||
When there are multiple “versions” of a given package,
|
||||
BitBake defaults to selecting the most recent
|
||||
version, unless otherwise specified.
|
||||
If the <filename>.bb</filename> in question has a
|
||||
<filename>DEFAULT_PREFERENCE</filename> set lower than
|
||||
the other recipes (default is 0), then it will not be
|
||||
selected.
|
||||
This allows the person or persons maintaining
|
||||
the repository of <filename>.bb</filename> files to specify
|
||||
their preference for the default selected version.
|
||||
In addition, the user can specify their preferred version.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
If the first <filename>.bb</filename> is named
|
||||
<filename>a_1.1.bb</filename>, then the
|
||||
<filename>PN</filename> variable will be set to
|
||||
“a”, and the <filename>PV</filename> variable will be
|
||||
set to 1.1.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
If we then have an <filename>a_1.2.bb</filename>, BitBake
|
||||
will choose 1.2 by default.
|
||||
However, if we define the following variable in a
|
||||
<filename>.conf</filename> file that BitBake parses, we
|
||||
can change that.
|
||||
<literallayout class='monospaced'>
|
||||
PREFERRED_VERSION_a = "1.1"
|
||||
</literallayout>
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id='using-recipe-file-collections'>
|
||||
<title>Using Recipe File Collections</title>
|
||||
|
||||
<para>
|
||||
Recipe file collections exist to allow the user to
|
||||
have multiple repositories of
|
||||
<filename>.bb</filename> files that contain the same
|
||||
exact package.
|
||||
For example, one could easily use them to make one's
|
||||
own local copy of an upstream repository, but with
|
||||
custom modifications that one does not want upstream.
|
||||
Here is an example:
|
||||
<literallayout class='monospaced'>
|
||||
BBFILES = "/stuff/openembedded/*/*.bb /stuff/openembedded.modified/*/*.bb"
|
||||
BBFILE_COLLECTIONS = "upstream local"
|
||||
BBFILE_PATTERN_upstream = "^/stuff/openembedded/"
|
||||
BBFILE_PATTERN_local = "^/stuff/openembedded.modified/"
|
||||
BBFILE_PRIORITY_upstream = "5"
|
||||
BBFILE_PRIORITY_local = "10"
|
||||
</literallayout>
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
||||
</chapter>
|
||||
@@ -1,14 +0,0 @@
|
||||
<?xml version='1.0'?>
|
||||
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://www.w3.org/1999/xhtml" xmlns:fo="http://www.w3.org/1999/XSL/Format" version="1.0">
|
||||
|
||||
<xsl:import href="http://docbook.sourceforge.net/release/xsl/current/xhtml/docbook.xsl" />
|
||||
|
||||
<xsl:param name="html.stylesheet" select="'user-manual-style.css'" />
|
||||
<xsl:param name="chapter.autolabel" select="1" />
|
||||
<xsl:param name="appendix.autolabel" select="A" />
|
||||
<xsl:param name="section.autolabel" select="1" />
|
||||
<xsl:param name="section.label.includes.component.label" select="1" />
|
||||
|
||||
<!-- <xsl:param name="generate.toc" select="'article nop'"></xsl:param> -->
|
||||
|
||||
</xsl:stylesheet>
|
||||
@@ -1,230 +0,0 @@
|
||||
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
|
||||
|
||||
<chapter>
|
||||
<title>File download support</title>
|
||||
|
||||
<section id='file-download-overview'>
|
||||
<title>Overview</title>
|
||||
|
||||
<para>
|
||||
BitBake provides support to download files.
|
||||
This procedure is called fetching and is handled by the
|
||||
fetch and fetch2 modules.
|
||||
At this point, the original fetch code is considered to
|
||||
be replaced by fetch2 and this manual is only related
|
||||
to the fetch2 codebase.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The <filename>SRC_URI</filename> is normally used to
|
||||
tell BitBake which files to fetch.
|
||||
The next sections describe the available fetchers and
|
||||
their options.
|
||||
Each fetcher honors a set of variables and per
|
||||
URI parameters separated by a “;” consisting of a key and
|
||||
a value.
|
||||
The semantics of the variables and parameters are
|
||||
defined by the fetcher.
|
||||
BitBake tries to have consistent semantics between the
|
||||
different fetchers.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The overall fetch process first attempts to fetch from
|
||||
<filename>PREMIRRORS</filename>.
|
||||
If these fail, the original <filename>SRC_URI</filename>
|
||||
is attempted.
|
||||
If that fails, BitBake falls back to
|
||||
<filename>MIRRORS</filename>.
|
||||
Because cross-URLs are supported, it is possible to mirror
|
||||
a Git repository on an HTTP server as a tarball.
|
||||
Here are some examples that show commonly used mirror
|
||||
definitions:
|
||||
<literallayout class='monospaced'>
|
||||
PREMIRRORS ?= "\
|
||||
bzr://.*/.* http://somemirror.org/sources/ \n \
|
||||
cvs://.*/.* http://somemirror.org/sources/ \n \
|
||||
git://.*/.* http://somemirror.org/sources/ \n \
|
||||
hg://.*/.* http://somemirror.org/sources/ \n \
|
||||
osc://.*/.* http://somemirror.org/sources/ \n \
|
||||
p4://.*/.* http://somemirror.org/sources/ \n \
|
||||
svk://.*/.* http://somemirror.org/sources/ \n \
|
||||
svn://.*/.* http://somemirror.org/sources/ \n"
|
||||
|
||||
MIRRORS =+ "\
|
||||
ftp://.*/.* http://somemirror.org/sources/ \n \
|
||||
http://.*/.* http://somemirror.org/sources/ \n \
|
||||
https://.*/.* http://somemirror.org/sources/ \n"
|
||||
</literallayout>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Non-local downloaded output is placed
|
||||
into the directory specified by the
|
||||
<filename>DL_DIR</filename> variable.
|
||||
For non local archive downloads, the code can verify
|
||||
sha256 and md5 checksums for the download to ensure
|
||||
the file has been downloaded correctly.
|
||||
These can be specified in the following forms
|
||||
for md5 and sha256 checksums, respectively:
|
||||
<literallayout class='monospaced'>
|
||||
SRC_URI[md5sum]
|
||||
SRC_URI[sha256sum]
|
||||
</literallayout>
|
||||
You can also specify them as parameters on the
|
||||
<filename>SRC_URI</filename>:
|
||||
<literallayout class='monospaced'>
|
||||
SRC_URI="http://example.com/foobar.tar.bz2;md5sum=4a8e0f237e961fd7785d19d07fdb994d"
|
||||
</literallayout>
|
||||
If <filename>BB_STRICT_CHECKSUM</filename> is set, any download
|
||||
without a checksum will trigger an error message.
|
||||
In cases where multiple files are listed in
|
||||
<filename>SRC_URI</filename>, the name parameter is used
|
||||
assign names to the URLs and these are then specified
|
||||
in the checksums using the following form:
|
||||
<literallayout class='monospaced'>
|
||||
SRC_URI[name.sha256sum]
|
||||
</literallayout>
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id='local-file-fetcher'>
|
||||
<title>Local file fetcher</title>
|
||||
|
||||
<para>
|
||||
The URN for the local file fetcher is file.
|
||||
The filename can be either absolute or relative.
|
||||
If the filename is relative,
|
||||
<filename>FILESPATH</filename> and failing that
|
||||
<filename>FILESDIR</filename> will be used to find the
|
||||
appropriate relative file.
|
||||
The metadata usually extend these variables to include
|
||||
variations of the values in <filename>OVERRIDES</filename>.
|
||||
Single files and complete directories can be specified.
|
||||
<literallayout class='monospaced'>
|
||||
SRC_URI = "file://relativefile.patch"
|
||||
SRC_URI = "file://relativefile.patch;this=ignored"
|
||||
SRC_URI = "file:///Users/ich/very_important_software"
|
||||
</literallayout>
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id='cvs-fetcher'>
|
||||
<title>CVS fetcher</title>
|
||||
|
||||
<para>
|
||||
The URN for the CVS fetcher is cvs.
|
||||
This fetcher honors the variables <filename>CVSDIR</filename>,
|
||||
<filename>SRCDATE</filename>, <filename>FETCHCOMMAND_cvs</filename>,
|
||||
<filename>UPDATECOMMAND_cvs</filename>.
|
||||
<filename>DL_DIR</filename> specifies where a
|
||||
temporary checkout is saved.
|
||||
<filename>SRCDATE</filename> specifies which date to
|
||||
use when doing the fetching (the special value of "now"
|
||||
will cause the checkout to be updated on every build).
|
||||
<filename>FETCHCOMMAND</filename> and
|
||||
<filename>UPDATECOMMAND</filename> specify which executables
|
||||
to use for the CVS checkout or update.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The supported parameters are module, tag, date,
|
||||
method, localdir, rshand scmdata.
|
||||
The module specifies which module to check out,
|
||||
the tag describes which CVS TAG should be used for
|
||||
the checkout.
|
||||
By default, the TAG is empty.
|
||||
A date can be specified to override the
|
||||
<filename>SRCDATE</filename> of the
|
||||
configuration to checkout a specific date.
|
||||
The special value of "now" will cause the checkout to be
|
||||
updated on every build.
|
||||
method is by default pserver.
|
||||
If ext is used the rsh parameter will be evaluated
|
||||
and <filename>CVS_RSH</filename> will be set.
|
||||
Finally, localdir is used to checkout into a special
|
||||
directory relative to <filename>CVSDIR</filename>.
|
||||
<literallayout class='monospaced'>
|
||||
SRC_URI = "cvs://CVSROOT;module=mymodule;tag=some-version;method=ext"
|
||||
SRC_URI = "cvs://CVSROOT;module=mymodule;date=20060126;localdir=usethat"
|
||||
</literallayout>
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id='http-ftp-fetcher'>
|
||||
<title>HTTP/FTP fetcher</title>
|
||||
|
||||
<para>
|
||||
The URNs for the HTTP/FTP fetcher are http, https, and ftp.
|
||||
This fetcher honors the variables
|
||||
<filename>FETCHCOMMAND_wget</filename>.
|
||||
<filename>FETCHCOMMAND</filename> contains the command used
|
||||
for fetching.
|
||||
“${URI}” and “${FILES}” will be replaced by the URI and
|
||||
basename of the file to be fetched.
|
||||
<literallayout class='monospaced'>
|
||||
SRC_URI = "http://oe.handhelds.org/not_there.aac"
|
||||
SRC_URI = "ftp://oe.handhelds.org/not_there_as_well.aac"
|
||||
SRC_URI = "ftp://you@oe.handheld.sorg/home/you/secret.plan"
|
||||
</literallayout>
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id='svn-fetcher'>
|
||||
<title>SVN Fetcher</title>
|
||||
|
||||
<para>
|
||||
The URN for the SVN fetcher is svn.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
This fetcher honors the variables
|
||||
<filename>FETCHCOMMAND_svn</filename>,
|
||||
<filename>SVNDIR</filename>,
|
||||
and <filename>SRCREV</filename>.
|
||||
<filename>FETCHCOMMAND</filename> contains the
|
||||
subversion command.
|
||||
<filename>SRCREV</filename> specifies which revision
|
||||
to use when doing the fetching.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The supported parameters are proto, rev and scmdata.
|
||||
proto is the Subversion protocol, rev is the
|
||||
Subversion revision.
|
||||
If scmdata is set to “keep”, the “.svn” directories will
|
||||
be available during compile-time.
|
||||
<literallayout class='monospaced'>
|
||||
SRC_URI = "svn://svn.oe.handhelds.org/svn;module=vip;proto=http;rev=667"
|
||||
SRC_URI = "svn://svn.oe.handhelds.org/svn/;module=opie;proto=svn+ssh;date=20060126"
|
||||
</literallayout>
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id='git-fetcher'>
|
||||
<title>GIT Fetcher</title>
|
||||
|
||||
<para>
|
||||
The URN for the GIT Fetcher is git.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The variable <filename>GITDIR</filename> will be used as the
|
||||
base directory where the Git tree is cloned to.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The parameters are tag, protocol, and scmdata.
|
||||
The tag parameter is a Git tag, the default is “master”.
|
||||
The protocol tag is the Git protocol to use and defaults to “git”
|
||||
if a hostname is set, otherwise it is “file”.
|
||||
If scmdata is set to “keep”, the “.git” directory will be available
|
||||
during compile-time.
|
||||
<literallayout class='monospaced'>
|
||||
SRC_URI = "git://git.oe.handhelds.org/git/vip.git;tag=version-1"
|
||||
SRC_URI = "git://git.oe.handhelds.org/git/vip.git;protocol=http"
|
||||
</literallayout>
|
||||
</para>
|
||||
</section>
|
||||
</chapter>
|
||||
@@ -1,321 +0,0 @@
|
||||
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
|
||||
|
||||
<chapter id='hello'>
|
||||
<title>A BitBake Hello World</title>
|
||||
|
||||
<section id='bitbake-hello-world'>
|
||||
<title>BitBake Hello World</title>
|
||||
|
||||
<para>
|
||||
The simplest example commonly used to demonstrate any new
|
||||
programming language or tool is the
|
||||
<ulink url="http://en.wikipedia.org/wiki/Hello_world_program">Hello World</ulink>
|
||||
example.
|
||||
This chapter demonstrates, in tutorial form, Hello
|
||||
World within the context of BitBake.
|
||||
This tutorial describes how to create a new Project
|
||||
and the applicable metadata files necessary to allow
|
||||
BitBake to build it.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id='obtaining-bitbake'>
|
||||
<title>Obtaining BitBake</title>
|
||||
|
||||
<para>
|
||||
Please refer to Chapter 1 Section 1.7 for the various methods to
|
||||
obtain BitBake.
|
||||
Once the source code is on your machine the BitBake directory will
|
||||
appear as follows:
|
||||
<literallayout class='monospaced'>
|
||||
$ ls -al
|
||||
total 100
|
||||
drwxrwxr-x. 9 wmat wmat 4096 Jan 31 13:44 .
|
||||
drwxrwxr-x. 3 wmat wmat 4096 Feb 4 10:45 ..
|
||||
-rw-rw-r--. 1 wmat wmat 365 Nov 26 04:55 AUTHORS
|
||||
drwxrwxr-x. 2 wmat wmat 4096 Nov 26 04:55 bin
|
||||
drwxrwxr-x. 4 wmat wmat 4096 Jan 31 13:44 build
|
||||
-rw-rw-r--. 1 wmat wmat 16501 Nov 26 04:55 ChangeLog
|
||||
drwxrwxr-x. 2 wmat wmat 4096 Nov 26 04:55 classes
|
||||
drwxrwxr-x. 2 wmat wmat 4096 Nov 26 04:55 conf
|
||||
drwxrwxr-x. 3 wmat wmat 4096 Nov 26 04:55 contrib
|
||||
-rw-rw-r--. 1 wmat wmat 17987 Nov 26 04:55 COPYING
|
||||
drwxrwxr-x. 3 wmat wmat 4096 Nov 26 04:55 doc
|
||||
-rw-rw-r--. 1 wmat wmat 69 Nov 26 04:55 .gitignore
|
||||
-rw-rw-r--. 1 wmat wmat 849 Nov 26 04:55 HEADER
|
||||
drwxrwxr-x. 5 wmat wmat 4096 Jan 31 13:44 lib
|
||||
-rw-rw-r--. 1 wmat wmat 195 Nov 26 04:55 MANIFEST.in
|
||||
-rwxrwxr-x. 1 wmat wmat 3195 Jan 31 11:57 setup.py
|
||||
-rw-rw-r--. 1 wmat wmat 2887 Nov 26 04:55 TODO
|
||||
</literallayout>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
At this point you should have BitBake extracted or cloned to
|
||||
a directory and it should match the directory tree above.
|
||||
Please note that you'll see your username wherever
|
||||
"wmat" appears above.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id='setting-up-the-bitbake-environment'>
|
||||
<title>Setting Up the BitBake Environment</title>
|
||||
|
||||
<para>
|
||||
The recommended method to run BitBake is from a directory of your
|
||||
choice.
|
||||
The directory can be within your home directory or in
|
||||
<filename>/usr/local</filename>,
|
||||
depending on your preference.
|
||||
Let's run BitBake now to make sure it's working.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
From the BitBake source code directory, issue the following command:
|
||||
<literallayout class='monospaced'>
|
||||
$ ./bin/bitbake --version
|
||||
BitBake Build Tool Core version 1.19.0, bitbake version
|
||||
1.19.0
|
||||
</literallayout>
|
||||
You're now ready to use BitBake.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
A final step to make development easier is to add the executable
|
||||
binary to your environment <filename>PATH</filename>.
|
||||
First, have a look at your current <filename>PATH</filename> variable.
|
||||
If I check mine, I get:
|
||||
<literallayout class='monospaced'>
|
||||
$ echo $PATH
|
||||
/home/wmat/bin:/usr/lib/lightdm/lightdm:/usr/local/sbin:/usr/local/bin:
|
||||
/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games
|
||||
</literallayout>
|
||||
Now add the directory location for the BitBake binary to the <filename>PATH</filename>
|
||||
with:
|
||||
<literallayout class='monospaced'>
|
||||
$ export PATH={path to the bitbake executable}:$PATH
|
||||
</literallayout>
|
||||
This will add the directory to the beginning of your PATH environment
|
||||
variable.
|
||||
For example, on my machine:
|
||||
<literallayout class='monospaced'>
|
||||
$ export PATH=/media/wmat/Backups/dev/bitbake/bin:$PATH
|
||||
/media/wmat/Backups/dev/bitbake/bin:/home/wmat/bin:
|
||||
/usr/lib/lightdm/lightdm:/usr/local/sbin:/usr/local/bin:
|
||||
/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games
|
||||
</literallayout>
|
||||
Now, you should be able to simply enter the
|
||||
<filename>bitbake</filename>
|
||||
command at the command line to run bitbake.
|
||||
For a more permanent solution and assuming you are running the BASH
|
||||
shell, edit <filename>~/.bashrc</filename> and add the following to the end
|
||||
of that file:
|
||||
<literallayout class='monospaced'>
|
||||
PATH={path to the bitbake executable}:$PATH
|
||||
</literallayout>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Note that if you're a Vim user, you will find useful
|
||||
Vim configuration contributions in the
|
||||
<filename>contrib/vim</filename> directory.
|
||||
Copy the files from that directory to your
|
||||
<filename>/home/yourusername/.vim</filename>
|
||||
directory.
|
||||
If it doesn't exist, create it, and restart Vim.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id='the-hello-world-example'>
|
||||
<title>The Hello World Example</title>
|
||||
|
||||
<para>
|
||||
The following example leaps directly into how BitBake
|
||||
works.
|
||||
Every attempt is made to explain what is happening,
|
||||
however, further information can be found in the
|
||||
Metadata chapter.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The overall goal of this exercise is to create a Hello
|
||||
World example utilizing concepts used to
|
||||
build and construct a complete example application
|
||||
including Tasks and Layers.
|
||||
This is how modern projects such as OpenEmbedded and
|
||||
the Yocto Project utilize BitBake, therefore it
|
||||
provides an excellent starting point for understanding
|
||||
BitBake.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
It should be noted that this chapter was inspired by
|
||||
and draws heavily from several sources:
|
||||
<itemizedlist>
|
||||
<listitem><para>
|
||||
<ulink href="http://www.mail-archive.com/yocto@yoctoproject.org/msg09379.html">Mailing List post - The BitBake equivalent of "Hello, World!"</ulink>
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
<ulink href="http://hambedded.org/blog/2012/11/24/from-bitbake-hello-world-to-an-image/">Hambedded Linux blog post - From Bitbake Hello World to an Image</ulink>
|
||||
</para></listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
|
||||
<section id='a-reverse-walkthrough'>
|
||||
<title>A Reverse Walkthrough</title>
|
||||
|
||||
<para>
|
||||
One of the best means to understand anything is to walk
|
||||
through the steps to where we want to be by observing first
|
||||
principles.
|
||||
BitBake allows us to do this through the -D or Debug command
|
||||
line parameter.
|
||||
We know we want to eventually compile a HelloWorld example, but
|
||||
we don't know what we need to do that.
|
||||
Remember that BitBake utilizes three types of metadata files:
|
||||
Configuration Files, Classes, and Recipes.
|
||||
But where do they go, how does BitBake find them, etc. etc.?
|
||||
Hopefully we can use BitBake's error messaging to figure this
|
||||
out and better understand exactly what's going on.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
First, let's begin by setting up a directory for our HelloWorld
|
||||
project.
|
||||
I'll do this in my home directory and change into that
|
||||
directory:
|
||||
<literallayout class='monospaced'>
|
||||
$ mkdir ~/dev/hello && cd ~/dev/hello
|
||||
</literallayout>
|
||||
Within this new, empty directory, let's run BitBake with
|
||||
Debugging output and see what happens:
|
||||
<literallayout class='monospaced'>
|
||||
$ bitbake -DDD
|
||||
The BBPATH variable is not set
|
||||
DEBUG: Removed the following variables from the environment:
|
||||
GNOME_DESKTOP_SESSION_ID, LESSOPEN, WINDOWID,
|
||||
GNOME_KEYRING_CONTROL, DISPLAY, SSH_AGENT_PID, LANG,
|
||||
XDG_SESSION_PATH, XAUTHORITY, LANGUAGE, SESSION_MANAGER,
|
||||
SHLVL, MANDATORY_PATH, COMPIZ_CONFIG_PROFILE, TEXTDOMAIN,
|
||||
GPG_AGENT_INFO, SSH_AUTH_SOCK, XDG_RUNTIME_DIR,
|
||||
COMPIZ_BIN_PATH, GDMSESSION, DEFAULTS_PATH, TEXTDOMAINDIR,
|
||||
XDG_SEAT_PATH, XDG_CONFIG_DIRS, XDG_CURRENT_DESKTOP,
|
||||
DBUS_SESSION_BUS_ADDRESS, _, XDG_SESSION_COOKIE,
|
||||
DESKTOP_SESSION, LESSCLOSE, GNOME_KEYRING_PID,
|
||||
UBUNTU_MENUPROXY, OLDPWD, GTK_MODULES, XDG_DATA_DIRS,
|
||||
COLORTERM, LS_COLORS
|
||||
</literallayout>
|
||||
The majority of this output is specific to environment variables
|
||||
that are not directly relevant to BitBake.
|
||||
However, the very
|
||||
first message <filename>The BBPATH variable is not set</filename>
|
||||
is and needs to be rectified.
|
||||
So how do we set the BBPATH
|
||||
variable?
|
||||
</para>
|
||||
|
||||
<para>
|
||||
When BitBake is run it begins looking for metadata files.
|
||||
The BBPATH variable is what tells BitBake where to look.
|
||||
It is possible to set BBPATH as an environment variable as you
|
||||
did above for the BitBake exexcutable's PATH.
|
||||
However, it's much more flexible to set the BBPATH variable for
|
||||
each project, as this allows for greater flexibility.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Without BBPATH Bitbake will not find any <filename>.conf</filename>
|
||||
files or recipe files at all.
|
||||
It will also not find <filename>bitbake.conf</filename>.
|
||||
Note the reference to <filename>conf/</filename>.
|
||||
It is standard practice to organize the project's directory tree
|
||||
to include a <filename>conf/</filename> and a
|
||||
<filename>classes/</filename> directory.
|
||||
Add those now to your project directory:
|
||||
<literallayout class='monospaced'>
|
||||
$ mkdir conf classes
|
||||
</literallayout>
|
||||
Now let's copy the sample configuration files provided in the
|
||||
BitBake source tree to their appropriate conf and classes
|
||||
directory.
|
||||
Change to the BitBake source tree directory and:
|
||||
<literallayout class='monospaced'>
|
||||
cp conf/bitbake.conf ~/dev/hello/conf/
|
||||
cp classes/base.bbclass ~/dev/hello/classes/
|
||||
</literallayout>
|
||||
At this point your project directory structure should look like
|
||||
the following:
|
||||
<literallayout class='monospaced'>
|
||||
~/dev/hello$ tree
|
||||
.
|
||||
├── classes
|
||||
│ └── base.bbclass
|
||||
└── conf
|
||||
└── bitbake.conf
|
||||
</literallayout>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
But what about BBPATH, we still haven't set it?
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The first configuration file that BitBake looks for is always
|
||||
<filename>bblayers.conf</filename>.
|
||||
With this knowledge we know that to resolve our BBPATH error we
|
||||
can add a <filename>conf/bblayers.conf</filename> file to our
|
||||
project source tree and populate it with the BBPATH variable
|
||||
declaration.
|
||||
From your project source tree:
|
||||
<literallayout class='monospaced'>
|
||||
$ vim conf/bblayers.conf
|
||||
</literallayout>
|
||||
Add the following to the empty bblayers.conf file:
|
||||
<literallayout class='monospaced'>
|
||||
BBPATH := "${TOPDIR}"
|
||||
</literallayout>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Now from the root of our project directory, let's run BitBake
|
||||
again and see what happens:
|
||||
<literallayout class='monospaced'>
|
||||
$ bitbake -DDD
|
||||
Nothing to do. Use 'bitbake world' to build everything, or run
|
||||
'bitbake --help' for usage information.
|
||||
DEBUG: Removed the following variables from the environment:
|
||||
GNOME_DESKTOP_SESSION_ID, LESSOPEN, WINDOWID,
|
||||
GNOME_KEYRING_CONTROL, DISPLAY, SSH_AGENT_PID, LANG,
|
||||
XDG_SESSION_PATH, XAUTHORITY, LANGUAGE, SESSION_MANAGER,
|
||||
SHLVL, MANDATORY_PATH, COMPIZ_CONFIG_PROFILE, TEXTDOMAIN,
|
||||
GPG_AGENT_INFO, SSH_AUTH_SOCK, XDG_RUNTIME_DIR,
|
||||
COMPIZ_BIN_PATH, GDMSESSION, DEFAULTS_PATH, TEXTDOMAINDIR,
|
||||
XDG_SEAT_PATH, XDG_CONFIG_DIRS, XDG_CURRENT_DESKTOP,
|
||||
DBUS_SESSION_BUS_ADDRESS, _, XDG_SESSION_COOKIE,
|
||||
DESKTOP_SESSION, LESSCLOSE, GNOME_KEYRING_PID, UBUNTU_MENUPROXY,
|
||||
OLDPWD, GTK_MODULES, XDG_DATA_DIRS, COLORTERM, LS_COLORS
|
||||
DEBUG: Found bblayers.conf (/home/wmat/dev/hello/conf/
|
||||
bblayers.conf)
|
||||
DEBUG: LOAD /home/wmat/dev/hello/conf/bblayers.conf
|
||||
DEBUG: LOAD /home/wmat/dev/hello/conf/bitbake.conf
|
||||
DEBUG: BB configuration INHERITs:0: inheriting /home/wmat/dev/
|
||||
hello/classes/base.bbclass
|
||||
DEBUG: BB /home/wmat/dev/hello/classes/base.bbclass: handle
|
||||
(data, include)
|
||||
DEBUG: LOAD /home/wmat/dev/hello/classes/base.bbclass
|
||||
DEBUG: Clearing SRCREV cache due to cache policy of: clear
|
||||
DEBUG: Using cache in '/home/wmat/dev/hello/tmp/cache/
|
||||
local_file_checksum_cache.dat'
|
||||
DEBUG: Using cache in '/home/wmat/dev/hello/tmp/cache/
|
||||
bb_codeparser.dat'
|
||||
</literallayout>
|
||||
<note>
|
||||
From this point forward, the environment variable
|
||||
removal messages will be ignored and omitted.
|
||||
Let's examine the relevant DEBUG messages:
|
||||
</note>
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
||||
</chapter>
|
||||
@@ -1,316 +0,0 @@
|
||||
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
|
||||
|
||||
<chapter id="user-manual-intro">
|
||||
<title>Overview</title>
|
||||
|
||||
<section id="intro">
|
||||
<title>Introduction</title>
|
||||
|
||||
<para>
|
||||
fundamentally, BitBake is a generic task execution
|
||||
engine that allows shell and Python tasks to be run
|
||||
efficiently and in parallel while working within
|
||||
complex inter-task dependency constraints.
|
||||
One of BitBake's main users, OpenEmbedded, takes this core
|
||||
and builds embedded Linux software stacks using
|
||||
a task-oriented approach.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Conceptually, BitBake is similar to GNU Make in
|
||||
some regards but has significant differences:
|
||||
<itemizedlist>
|
||||
<listitem><para>
|
||||
BitBake executes tasks according to provided
|
||||
metadata that builds up the tasks.
|
||||
Metadata is stored in recipe (<filename>.bb</filename>),
|
||||
configuration (<filename>.conf</filename>), and class
|
||||
(<filename>.bbclass</filename>) files and provides
|
||||
BitBake with instructions on what tasks to run and
|
||||
the dependencies between those tasks.
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
BitBake includes a fetcher library for obtaining source
|
||||
code from various places such as source control
|
||||
systems or websites.
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
The instructions for each unit to be built (e.g. a piece
|
||||
of software) are known as recipe files and
|
||||
contain all the information about the unit
|
||||
(dependencies, source file locations, checksums, description
|
||||
and so on).
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
BitBake includes a client/server abstraction and can
|
||||
be used from a command line or used as a service over XMLRPC and
|
||||
has several different user interfaces.
|
||||
</para></listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="history-and-goals">
|
||||
<title>History and Goals</title>
|
||||
|
||||
<para>
|
||||
BitBake was originally a part of the OpenEmbedded project.
|
||||
It was inspired by the Portage package management system
|
||||
used by the Gentoo Linux distribution.
|
||||
On December 7, 2004, OpenEmbedded project team member,
|
||||
Chris Larson split the project into two distinct pieces:
|
||||
<itemizedlist>
|
||||
<listitem><para>BitBake, a generic task executor</para></listitem>
|
||||
<listitem><para>OpenEmbedded, a metadata set utilized by
|
||||
BitBake</para></listitem>
|
||||
</itemizedlist>
|
||||
Today, BitBake is the primary basis of the
|
||||
<ulink url="http://www.openembedded.org/">OpenEmbedded</ulink>
|
||||
project, which is being used to build and maintain a
|
||||
number of projects and embedded Linux distributions
|
||||
such as the Angstrom Distribution and the Yocto
|
||||
Project.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Prior to BitBake, no other build tool adequately met the needs of
|
||||
an aspiring embedded Linux distribution.
|
||||
All of the build systems used by traditional desktop Linux
|
||||
distributions lacked important functionality, and none of the
|
||||
ad-hoc buildroot systems, prevalent in the
|
||||
embedded space, were scalable or maintainable.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Some important original goals for BitBake were:
|
||||
<itemizedlist>
|
||||
<listitem><para>
|
||||
Handle cross-compilation.
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
Handle inter-package dependencies (build time on
|
||||
target architecture, build time on native
|
||||
architecture, and runtime).
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
Support running any number of tasks within a given
|
||||
package, including, but not limited to, fetching
|
||||
upstream sources, unpacking them, patching them,
|
||||
configuring them, and so forth.
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
Be Linux distribution agnostic for both build and
|
||||
target systems.
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
Be architecture agnostic.
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
Support multiple build and target operating systems
|
||||
(e.g. Cygwin, the BSDs, and so forth).
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
Be self contained, rather than tightly
|
||||
integrated into the build machine's root
|
||||
filesystem.
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
Handle conditional metadata on the target architecture,
|
||||
operating system, distribution, and machine.
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
Be easy to use the tools to supply local metadata and packages
|
||||
against which to operate.
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
Be easy to use BitBake to collaborate between multiple
|
||||
projects for their builds.
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
Provide an inheritance mechanism that share
|
||||
common metadata between many packages.
|
||||
</para></listitem>
|
||||
</itemizedlist>
|
||||
Over time it became apparent that some further requirements
|
||||
were necessary:
|
||||
<itemizedlist>
|
||||
<listitem><para>
|
||||
Handle variants of a base recipe (e.g. native, sdk,
|
||||
and multilib).
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
Split metadata into layers and allow layers
|
||||
to override each other.
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
Allow representation of a given set of input variables
|
||||
to a task as a checksum.
|
||||
Based on that checksum, allow acceleration of builds
|
||||
with prebuilt components.
|
||||
</para></listitem>
|
||||
</itemizedlist>
|
||||
BitBake satisfies all the original requirements and many more
|
||||
with extensions being made to the basic functionality to
|
||||
reflect the additional requirements.
|
||||
Flexibility and power have always been the priorities.
|
||||
BitBake is highly extensible and supports embedded Python code and
|
||||
execution of any arbitrary tasks.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="Concepts">
|
||||
<title>Concepts</title>
|
||||
|
||||
<para>
|
||||
BitBake is a program written in the Python language.
|
||||
At the highest level, BitBake interprets metadata, decides
|
||||
what tasks are required to run, and executes those tasks.
|
||||
Similar to GNU Make, BitBake controls how software is
|
||||
built.
|
||||
GNU Make achieves its control through "makefiles".
|
||||
BitBake uses "recipes".
|
||||
</para>
|
||||
|
||||
<para>
|
||||
BitBake extends the capabilities of a simple
|
||||
tool like GNU Make by allowing for much more complex tasks
|
||||
to be completed, such as assembling entire embedded Linux
|
||||
distributions.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The remainder of this section introduces several concepts
|
||||
that should be understood in order to better leverage
|
||||
the power of BitBake.
|
||||
</para>
|
||||
|
||||
<section id='recipes'>
|
||||
<title>Recipes</title>
|
||||
|
||||
<para>
|
||||
BitBake Recipes, which are denoted by the file extension
|
||||
<filename>.bb</filename>, are the most basic metadata files.
|
||||
These recipe files provide BitBake the following:
|
||||
<itemizedlist>
|
||||
<listitem><para>Descriptive information about the package</para></listitem>
|
||||
<listitem><para>The version of the recipe</para></listitem>
|
||||
<listitem><para>When dependencies exist</para></listitem>
|
||||
<listitem><para>Where the source code resides</para></listitem>
|
||||
<listitem><para>Whether the source code requires any patches</para></listitem>
|
||||
<listitem><para>How to compile the source code</para></listitem>
|
||||
<listitem><para>Where on the target machine to install the
|
||||
package being compiled</para></listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Within the context of BitBake, or any project utilizing BitBake
|
||||
as it's build system, files with the <filename>.bb</filename>
|
||||
extension are referred to as recipes.
|
||||
<note>
|
||||
The term "package" is also commonly used to describe recipes.
|
||||
However, since the same word is used to describe packaged
|
||||
output from a project, it is best to maintain a single
|
||||
descriptive term, "recipes".
|
||||
</note>
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id='configuration-files'>
|
||||
<title>Configuration Files</title>
|
||||
|
||||
<para>
|
||||
Configuration files, which are denoted by the
|
||||
<filename>.conf</filename> extension, define
|
||||
various configuration variables that govern the project's build
|
||||
process.
|
||||
These files fall into several areas that define
|
||||
machine configuration options, distribution configuration
|
||||
options, compiler tuning options, general common
|
||||
configuration options, and user configuration options.
|
||||
The main configuration file is the sample
|
||||
<filename>bitbake.conf</filename> file, which is
|
||||
located within the BitBake source tree
|
||||
<filename>conf</filename> directory.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id='classes'>
|
||||
<title>Classes</title>
|
||||
|
||||
<para>
|
||||
Class files, which are denoted by the
|
||||
<filename>.bbclass</filename> extension, contain
|
||||
information that is useful to share between metadata files.
|
||||
The BitBake source tree currently comes with one class metadata file
|
||||
called <filename>base.bbclass</filename>.
|
||||
You can find this file in the
|
||||
<filename>classes</filename> directory.
|
||||
The <filename>base.bbclass</filename> is special in that any
|
||||
new classes that a developer adds to a project are required to
|
||||
inherit <filename>base.bbclass</filename> automatically.
|
||||
This class contains definitions for standard basic tasks such
|
||||
as fetching, unpacking, configuring (empty by default),
|
||||
compiling (runs any Makefile present), installing (empty by
|
||||
default) and packaging (empty by default).
|
||||
These tasks are often overridden or extended by other classes
|
||||
added during the project development process.
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section id='obtaining-bitbake'>
|
||||
<title>Obtaining BitBake</title>
|
||||
|
||||
<para>
|
||||
You can obtain BitBake several different ways:
|
||||
<itemizedlist>
|
||||
<listitem><para><emphasis>Installation using your Distribution
|
||||
Package Management System:</emphasis>
|
||||
This method is not
|
||||
recommended because the BitBake version, in most
|
||||
cases provided by your distribution, is several
|
||||
releases behind a snapshot of the BitBake repository.
|
||||
</para></listitem>
|
||||
<listitem><para><emphasis>Taking a snapshot of BitBake:</emphasis>
|
||||
Downloading a snapshot of BitBake from the
|
||||
source code repository is the recommended method
|
||||
as you are assured of having the most recent stable
|
||||
BitBake release.</para>
|
||||
<para>The following example downloads a snapshot of
|
||||
BitBake version 1.17.0:
|
||||
<literallayout class='monospaced'>
|
||||
$ wget http://git.openembedded.org/bitbake/snapshot/bitbake-1.17.0.tar.gz
|
||||
$ tar zxpvf bitbake-1.17.0.tar.gz
|
||||
</literallayout>
|
||||
After extraction of the tarball using the tar utility,
|
||||
you have a directory entitled
|
||||
<filename>bitbake-1.17.0</filename>.
|
||||
</para></listitem>
|
||||
<listitem><para><emphasis>Cloning BitBake:</emphasis>
|
||||
Using Git to clone the BitBake source code repository
|
||||
is also a recommended method when you need the absolute latest
|
||||
BitBake source.
|
||||
Realize that using this method could expose you to areas of
|
||||
BitBake that are under development.</para>
|
||||
<para>Here is an example:
|
||||
<literallayout class='monospaced'>
|
||||
$ git clone git://git.openembedded.org/bitbake
|
||||
</literallayout>
|
||||
This command clones the BitBake Git repository into a
|
||||
directory called <filename>bitbake</filename>.
|
||||
Alternatively, you can
|
||||
designate a directory after the
|
||||
<filename>git clone</filename> command
|
||||
if you want to call the new directory something
|
||||
other than <filename>bitbake</filename>.
|
||||
Here is an example that names the directory
|
||||
<filename>bbdev</filename>:
|
||||
<literallayout class='monospaced'>
|
||||
$ git clone git://git.openembedded.org/bitbake bbdev
|
||||
</literallayout></para></listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
</section>
|
||||
</chapter>
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,978 +0,0 @@
|
||||
/*
|
||||
Generic XHTML / DocBook XHTML CSS Stylesheet.
|
||||
|
||||
Browser wrangling and typographic design by
|
||||
Oyvind Kolas / pippin@gimp.org
|
||||
|
||||
Customised for Poky by
|
||||
Matthew Allum / mallum@o-hand.com
|
||||
|
||||
Thanks to:
|
||||
Liam R. E. Quin
|
||||
William Skaggs
|
||||
Jakub Steiner
|
||||
|
||||
Structure
|
||||
---------
|
||||
|
||||
The stylesheet is divided into the following sections:
|
||||
|
||||
Positioning
|
||||
Margins, paddings, width, font-size, clearing.
|
||||
Decorations
|
||||
Borders, style
|
||||
Colors
|
||||
Colors
|
||||
Graphics
|
||||
Graphical backgrounds
|
||||
Nasty IE tweaks
|
||||
Workarounds needed to make it work in internet explorer,
|
||||
currently makes the stylesheet non validating, but up until
|
||||
this point it is validating.
|
||||
Mozilla extensions
|
||||
Transparency for footer
|
||||
Rounded corners on boxes
|
||||
|
||||
*/
|
||||
|
||||
|
||||
/*************** /
|
||||
/ Positioning /
|
||||
/ ***************/
|
||||
|
||||
body {
|
||||
font-family: Verdana, Sans, sans-serif;
|
||||
|
||||
min-width: 640px;
|
||||
width: 80%;
|
||||
margin: 0em auto;
|
||||
padding: 2em 5em 5em 5em;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
h1,h2,h3,h4,h5,h6,h7 {
|
||||
font-family: Arial, Sans;
|
||||
color: #00557D;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 2em;
|
||||
text-align: left;
|
||||
padding: 0em 0em 0em 0em;
|
||||
margin: 2em 0em 0em 0em;
|
||||
}
|
||||
|
||||
h2.subtitle {
|
||||
margin: 0.10em 0em 3.0em 0em;
|
||||
padding: 0em 0em 0em 0em;
|
||||
font-size: 1.8em;
|
||||
padding-left: 20%;
|
||||
font-weight: normal;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
h2 {
|
||||
margin: 2em 0em 0.66em 0em;
|
||||
padding: 0.5em 0em 0em 0em;
|
||||
font-size: 1.5em;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
h3.subtitle {
|
||||
margin: 0em 0em 1em 0em;
|
||||
padding: 0em 0em 0em 0em;
|
||||
font-size: 142.14%;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
h3 {
|
||||
margin: 1em 0em 0.5em 0em;
|
||||
padding: 1em 0em 0em 0em;
|
||||
font-size: 140%;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
h4 {
|
||||
margin: 1em 0em 0.5em 0em;
|
||||
padding: 1em 0em 0em 0em;
|
||||
font-size: 120%;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
h5 {
|
||||
margin: 1em 0em 0.5em 0em;
|
||||
padding: 1em 0em 0em 0em;
|
||||
font-size: 110%;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
h6 {
|
||||
margin: 1em 0em 0em 0em;
|
||||
padding: 1em 0em 0em 0em;
|
||||
font-size: 110%;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.authorgroup {
|
||||
background-color: transparent;
|
||||
background-repeat: no-repeat;
|
||||
padding-top: 256px;
|
||||
background-image: url("figures/bitbake-title.png");
|
||||
background-position: left top;
|
||||
margin-top: -256px;
|
||||
padding-right: 50px;
|
||||
margin-left: 0px;
|
||||
text-align: right;
|
||||
width: 740px;
|
||||
}
|
||||
|
||||
h3.author {
|
||||
margin: 0em 0me 0em 0em;
|
||||
padding: 0em 0em 0em 0em;
|
||||
font-weight: normal;
|
||||
font-size: 100%;
|
||||
color: #333;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.author tt.email {
|
||||
font-size: 66%;
|
||||
}
|
||||
|
||||
.titlepage hr {
|
||||
width: 0em;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.revhistory {
|
||||
padding-top: 2em;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.toc,
|
||||
.list-of-tables,
|
||||
.list-of-examples,
|
||||
.list-of-figures {
|
||||
padding: 1.33em 0em 2.5em 0em;
|
||||
color: #00557D;
|
||||
}
|
||||
|
||||
.toc p,
|
||||
.list-of-tables p,
|
||||
.list-of-figures p,
|
||||
.list-of-examples p {
|
||||
padding: 0em 0em 0em 0em;
|
||||
padding: 0em 0em 0.3em;
|
||||
margin: 1.5em 0em 0em 0em;
|
||||
}
|
||||
|
||||
.toc p b,
|
||||
.list-of-tables p b,
|
||||
.list-of-figures p b,
|
||||
.list-of-examples p b{
|
||||
font-size: 100.0%;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.toc dl,
|
||||
.list-of-tables dl,
|
||||
.list-of-figures dl,
|
||||
.list-of-examples dl {
|
||||
margin: 0em 0em 0.5em 0em;
|
||||
padding: 0em 0em 0em 0em;
|
||||
}
|
||||
|
||||
.toc dt {
|
||||
margin: 0em 0em 0em 0em;
|
||||
padding: 0em 0em 0em 0em;
|
||||
}
|
||||
|
||||
.toc dd {
|
||||
margin: 0em 0em 0em 2.6em;
|
||||
padding: 0em 0em 0em 0em;
|
||||
}
|
||||
|
||||
div.glossary dl,
|
||||
div.variablelist dl {
|
||||
}
|
||||
|
||||
.glossary dl dt,
|
||||
.variablelist dl dt,
|
||||
.variablelist dl dt span.term {
|
||||
font-weight: normal;
|
||||
width: 20em;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.variablelist dl dt {
|
||||
margin-top: 0.5em;
|
||||
}
|
||||
|
||||
.glossary dl dd,
|
||||
.variablelist dl dd {
|
||||
margin-top: -1em;
|
||||
margin-left: 25.5em;
|
||||
}
|
||||
|
||||
.glossary dd p,
|
||||
.variablelist dd p {
|
||||
margin-top: 0em;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
|
||||
div.calloutlist table td {
|
||||
padding: 0em 0em 0em 0em;
|
||||
margin: 0em 0em 0em 0em;
|
||||
}
|
||||
|
||||
div.calloutlist table td p {
|
||||
margin-top: 0em;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
div p.copyright {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
div.legalnotice p.legalnotice-title {
|
||||
margin-bottom: 0em;
|
||||
}
|
||||
|
||||
p {
|
||||
line-height: 1.5em;
|
||||
margin-top: 0em;
|
||||
|
||||
}
|
||||
|
||||
dl {
|
||||
padding-top: 0em;
|
||||
}
|
||||
|
||||
hr {
|
||||
border: solid 1px;
|
||||
}
|
||||
|
||||
|
||||
.mediaobject,
|
||||
.mediaobjectco {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
img {
|
||||
border: none;
|
||||
}
|
||||
|
||||
ul {
|
||||
padding: 0em 0em 0em 1.5em;
|
||||
}
|
||||
|
||||
ul li {
|
||||
padding: 0em 0em 0em 0em;
|
||||
}
|
||||
|
||||
ul li p {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
table {
|
||||
width :100%;
|
||||
}
|
||||
|
||||
th {
|
||||
padding: 0.25em;
|
||||
text-align: left;
|
||||
font-weight: normal;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
td {
|
||||
padding: 0.25em;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
p a[id] {
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
display: inline;
|
||||
background-image: none;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: underline;
|
||||
color: #444;
|
||||
}
|
||||
|
||||
pre {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
/*font-weight: bold;*/
|
||||
}
|
||||
|
||||
|
||||
div.informalfigure,
|
||||
div.informalexample,
|
||||
div.informaltable,
|
||||
div.figure,
|
||||
div.table,
|
||||
div.example {
|
||||
margin: 1em 0em;
|
||||
padding: 1em;
|
||||
page-break-inside: avoid;
|
||||
}
|
||||
|
||||
|
||||
div.informalfigure p.title b,
|
||||
div.informalexample p.title b,
|
||||
div.informaltable p.title b,
|
||||
div.figure p.title b,
|
||||
div.example p.title b,
|
||||
div.table p.title b{
|
||||
padding-top: 0em;
|
||||
margin-top: 0em;
|
||||
font-size: 100%;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.mediaobject .caption,
|
||||
.mediaobject .caption p {
|
||||
text-align: center;
|
||||
font-size: 80%;
|
||||
padding-top: 0.5em;
|
||||
padding-bottom: 0.5em;
|
||||
}
|
||||
|
||||
.epigraph {
|
||||
padding-left: 55%;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.epigraph p {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.epigraph .quote {
|
||||
font-style: italic;
|
||||
}
|
||||
.epigraph .attribution {
|
||||
font-style: normal;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
span.application {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.programlisting {
|
||||
font-family: monospace;
|
||||
font-size: 80%;
|
||||
white-space: pre;
|
||||
margin: 1.33em 0em;
|
||||
padding: 1.33em;
|
||||
}
|
||||
|
||||
.tip,
|
||||
.warning,
|
||||
.caution,
|
||||
.note {
|
||||
margin-top: 1em;
|
||||
margin-bottom: 1em;
|
||||
|
||||
}
|
||||
|
||||
/* force full width of table within div */
|
||||
.tip table,
|
||||
.warning table,
|
||||
.caution table,
|
||||
.note table {
|
||||
border: none;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
|
||||
.tip table th,
|
||||
.warning table th,
|
||||
.caution table th,
|
||||
.note table th {
|
||||
padding: 0.8em 0.0em 0.0em 0.0em;
|
||||
margin : 0em 0em 0em 0em;
|
||||
}
|
||||
|
||||
.tip p,
|
||||
.warning p,
|
||||
.caution p,
|
||||
.note p {
|
||||
margin-top: 0.5em;
|
||||
margin-bottom: 0.5em;
|
||||
padding-right: 1em;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.acronym {
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
b.keycap,
|
||||
.keycap {
|
||||
padding: 0.09em 0.3em;
|
||||
margin: 0em;
|
||||
}
|
||||
|
||||
.itemizedlist li {
|
||||
clear: none;
|
||||
}
|
||||
|
||||
.filename {
|
||||
font-size: medium;
|
||||
font-family: Courier, monospace;
|
||||
}
|
||||
|
||||
|
||||
div.navheader, div.heading{
|
||||
position: absolute;
|
||||
left: 0em;
|
||||
top: 0em;
|
||||
width: 100%;
|
||||
background-color: #cdf;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
div.navfooter, div.footing{
|
||||
position: fixed;
|
||||
left: 0em;
|
||||
bottom: 0em;
|
||||
background-color: #eee;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
|
||||
div.navheader td,
|
||||
div.navfooter td {
|
||||
font-size: 66%;
|
||||
}
|
||||
|
||||
div.navheader table th {
|
||||
/*font-family: Georgia, Times, serif;*/
|
||||
/*font-size: x-large;*/
|
||||
font-size: 80%;
|
||||
}
|
||||
|
||||
div.navheader table {
|
||||
border-left: 0em;
|
||||
border-right: 0em;
|
||||
border-top: 0em;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
div.navfooter table {
|
||||
border-left: 0em;
|
||||
border-right: 0em;
|
||||
border-bottom: 0em;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
div.navheader table td a,
|
||||
div.navfooter table td a {
|
||||
color: #777;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
/* normal text in the footer */
|
||||
div.navfooter table td {
|
||||
color: black;
|
||||
}
|
||||
|
||||
div.navheader table td a:visited,
|
||||
div.navfooter table td a:visited {
|
||||
color: #444;
|
||||
}
|
||||
|
||||
|
||||
/* links in header and footer */
|
||||
div.navheader table td a:hover,
|
||||
div.navfooter table td a:hover {
|
||||
text-decoration: underline;
|
||||
background-color: transparent;
|
||||
color: #33a;
|
||||
}
|
||||
|
||||
div.navheader hr,
|
||||
div.navfooter hr {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
.qandaset tr.question td p {
|
||||
margin: 0em 0em 1em 0em;
|
||||
padding: 0em 0em 0em 0em;
|
||||
}
|
||||
|
||||
.qandaset tr.answer td p {
|
||||
margin: 0em 0em 1em 0em;
|
||||
padding: 0em 0em 0em 0em;
|
||||
}
|
||||
.answer td {
|
||||
padding-bottom: 1.5em;
|
||||
}
|
||||
|
||||
.emphasis {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
|
||||
/************* /
|
||||
/ decorations /
|
||||
/ *************/
|
||||
|
||||
.titlepage {
|
||||
}
|
||||
|
||||
.part .title {
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
border: none;
|
||||
}
|
||||
|
||||
/*
|
||||
h1 {
|
||||
border: none;
|
||||
}
|
||||
|
||||
h2 {
|
||||
border-top: solid 0.2em;
|
||||
border-bottom: solid 0.06em;
|
||||
}
|
||||
|
||||
h3 {
|
||||
border-top: 0em;
|
||||
border-bottom: solid 0.06em;
|
||||
}
|
||||
|
||||
h4 {
|
||||
border: 0em;
|
||||
border-bottom: solid 0.06em;
|
||||
}
|
||||
|
||||
h5 {
|
||||
border: 0em;
|
||||
}
|
||||
*/
|
||||
|
||||
.programlisting {
|
||||
border: solid 1px;
|
||||
}
|
||||
|
||||
div.figure,
|
||||
div.table,
|
||||
div.informalfigure,
|
||||
div.informaltable,
|
||||
div.informalexample,
|
||||
div.example {
|
||||
border: 1px solid;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.tip,
|
||||
.warning,
|
||||
.caution,
|
||||
.note {
|
||||
border: 1px solid;
|
||||
}
|
||||
|
||||
.tip table th,
|
||||
.warning table th,
|
||||
.caution table th,
|
||||
.note table th {
|
||||
border-bottom: 1px solid;
|
||||
}
|
||||
|
||||
.question td {
|
||||
border-top: 1px solid black;
|
||||
}
|
||||
|
||||
.answer {
|
||||
}
|
||||
|
||||
|
||||
b.keycap,
|
||||
.keycap {
|
||||
border: 1px solid;
|
||||
}
|
||||
|
||||
|
||||
div.navheader, div.heading{
|
||||
border-bottom: 1px solid;
|
||||
}
|
||||
|
||||
|
||||
div.navfooter, div.footing{
|
||||
border-top: 1px solid;
|
||||
}
|
||||
|
||||
/********* /
|
||||
/ colors /
|
||||
/ *********/
|
||||
|
||||
body {
|
||||
color: #333;
|
||||
background: white;
|
||||
}
|
||||
|
||||
a {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
background-color: #dedede;
|
||||
}
|
||||
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6,
|
||||
h7,
|
||||
h8 {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
hr {
|
||||
border-color: #aaa;
|
||||
}
|
||||
|
||||
|
||||
.tip, .warning, .caution, .note {
|
||||
border-color: #fff;
|
||||
}
|
||||
|
||||
|
||||
.tip table th,
|
||||
.warning table th,
|
||||
.caution table th,
|
||||
.note table th {
|
||||
border-bottom-color: #fff;
|
||||
}
|
||||
|
||||
|
||||
.warning {
|
||||
background-color: #f0f0f2;
|
||||
}
|
||||
|
||||
.caution {
|
||||
background-color: #f0f0f2;
|
||||
}
|
||||
|
||||
.tip {
|
||||
background-color: #f0f0f2;
|
||||
}
|
||||
|
||||
.note {
|
||||
background-color: #f0f0f2;
|
||||
}
|
||||
|
||||
.glossary dl dt,
|
||||
.variablelist dl dt,
|
||||
.variablelist dl dt span.term {
|
||||
color: #044;
|
||||
}
|
||||
|
||||
div.figure,
|
||||
div.table,
|
||||
div.example,
|
||||
div.informalfigure,
|
||||
div.informaltable,
|
||||
div.informalexample {
|
||||
border-color: #aaa;
|
||||
}
|
||||
|
||||
pre.programlisting {
|
||||
color: black;
|
||||
background-color: #fff;
|
||||
border-color: #aaa;
|
||||
border-width: 2px;
|
||||
}
|
||||
|
||||
.guimenu,
|
||||
.guilabel,
|
||||
.guimenuitem {
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
|
||||
b.keycap,
|
||||
.keycap {
|
||||
background-color: #eee;
|
||||
border-color: #999;
|
||||
}
|
||||
|
||||
|
||||
div.navheader {
|
||||
border-color: black;
|
||||
}
|
||||
|
||||
|
||||
div.navfooter {
|
||||
border-color: black;
|
||||
}
|
||||
|
||||
|
||||
/*********** /
|
||||
/ graphics /
|
||||
/ ***********/
|
||||
|
||||
/*
|
||||
body {
|
||||
background-image: url("images/body_bg.jpg");
|
||||
background-attachment: fixed;
|
||||
}
|
||||
|
||||
.navheader,
|
||||
.note,
|
||||
.tip {
|
||||
background-image: url("images/note_bg.jpg");
|
||||
background-attachment: fixed;
|
||||
}
|
||||
|
||||
.warning,
|
||||
.caution {
|
||||
background-image: url("images/warning_bg.jpg");
|
||||
background-attachment: fixed;
|
||||
}
|
||||
|
||||
.figure,
|
||||
.informalfigure,
|
||||
.example,
|
||||
.informalexample,
|
||||
.table,
|
||||
.informaltable {
|
||||
background-image: url("images/figure_bg.jpg");
|
||||
background-attachment: fixed;
|
||||
}
|
||||
|
||||
*/
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6,
|
||||
h7{
|
||||
}
|
||||
|
||||
/*
|
||||
Example of how to stick an image as part of the title.
|
||||
|
||||
div.article .titlepage .title
|
||||
{
|
||||
background-image: url("figures/white-on-black.png");
|
||||
background-position: center;
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
*/
|
||||
|
||||
div.preface .titlepage .title,
|
||||
div.colophon .title,
|
||||
div.chapter .titlepage .title,
|
||||
div.article .titlepage .title
|
||||
{
|
||||
}
|
||||
|
||||
div.section div.section .titlepage .title,
|
||||
div.sect2 .titlepage .title {
|
||||
background: none;
|
||||
}
|
||||
|
||||
|
||||
h1.title {
|
||||
background-color: transparent;
|
||||
background-image: url("figures/yocto-project-bw.png");
|
||||
background-repeat: no-repeat;
|
||||
height: 256px;
|
||||
text-indent: -9000px;
|
||||
overflow:hidden;
|
||||
}
|
||||
|
||||
h2.subtitle {
|
||||
background-color: transparent;
|
||||
text-indent: -9000px;
|
||||
overflow:hidden;
|
||||
width: 0px;
|
||||
display: none;
|
||||
}
|
||||
|
||||
/*************************************** /
|
||||
/ pippin.gimp.org specific alterations /
|
||||
/ ***************************************/
|
||||
|
||||
/*
|
||||
div.heading, div.navheader {
|
||||
color: #777;
|
||||
font-size: 80%;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
text-align: left;
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
width: 100%;
|
||||
height: 50px;
|
||||
background: url('/gfx/heading_bg.png') transparent;
|
||||
background-repeat: repeat-x;
|
||||
background-attachment: fixed;
|
||||
border: none;
|
||||
}
|
||||
|
||||
div.heading a {
|
||||
color: #444;
|
||||
}
|
||||
|
||||
div.footing, div.navfooter {
|
||||
border: none;
|
||||
color: #ddd;
|
||||
font-size: 80%;
|
||||
text-align:right;
|
||||
|
||||
width: 100%;
|
||||
padding-top: 10px;
|
||||
position: absolute;
|
||||
bottom: 0px;
|
||||
left: 0px;
|
||||
|
||||
background: url('/gfx/footing_bg.png') transparent;
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/****************** /
|
||||
/ nasty ie tweaks /
|
||||
/ ******************/
|
||||
|
||||
/*
|
||||
div.heading, div.navheader {
|
||||
width:expression(document.body.clientWidth + "px");
|
||||
}
|
||||
|
||||
div.footing, div.navfooter {
|
||||
width:expression(document.body.clientWidth + "px");
|
||||
margin-left:expression("-5em");
|
||||
}
|
||||
body {
|
||||
padding:expression("4em 5em 0em 5em");
|
||||
}
|
||||
*/
|
||||
|
||||
/**************************************** /
|
||||
/ mozilla vendor specific css extensions /
|
||||
/ ****************************************/
|
||||
/*
|
||||
div.navfooter, div.footing{
|
||||
-moz-opacity: 0.8em;
|
||||
}
|
||||
|
||||
div.figure,
|
||||
div.table,
|
||||
div.informalfigure,
|
||||
div.informaltable,
|
||||
div.informalexample,
|
||||
div.example,
|
||||
.tip,
|
||||
.warning,
|
||||
.caution,
|
||||
.note {
|
||||
-moz-border-radius: 0.5em;
|
||||
}
|
||||
|
||||
b.keycap,
|
||||
.keycap {
|
||||
-moz-border-radius: 0.3em;
|
||||
}
|
||||
*/
|
||||
|
||||
table tr td table tr td {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
hr {
|
||||
display: none;
|
||||
}
|
||||
|
||||
table {
|
||||
border: 0em;
|
||||
}
|
||||
|
||||
.photo {
|
||||
float: right;
|
||||
margin-left: 1.5em;
|
||||
margin-bottom: 1.5em;
|
||||
margin-top: 0em;
|
||||
max-width: 17em;
|
||||
border: 1px solid gray;
|
||||
padding: 3px;
|
||||
background: white;
|
||||
}
|
||||
.seperator {
|
||||
padding-top: 2em;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
#validators {
|
||||
margin-top: 5em;
|
||||
text-align: right;
|
||||
color: #777;
|
||||
}
|
||||
@media print {
|
||||
body {
|
||||
font-size: 8pt;
|
||||
}
|
||||
.noprint {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.tip,
|
||||
.note {
|
||||
background: #f0f0f2;
|
||||
color: #333;
|
||||
padding: 20px;
|
||||
margin: 20px;
|
||||
}
|
||||
|
||||
.tip h3,
|
||||
.note h3 {
|
||||
padding: 0em;
|
||||
margin: 0em;
|
||||
font-size: 2em;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.tip a,
|
||||
.note a {
|
||||
color: #333;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.footnote {
|
||||
font-size: small;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
/* Changes the announcement text */
|
||||
.tip h3,
|
||||
.warning h3,
|
||||
.caution h3,
|
||||
.note h3 {
|
||||
font-size:large;
|
||||
color: #00557D;
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
|
||||
|
||||
<book id='bitbake-user-manual' lang='en'
|
||||
xmlns:xi="http://www.w3.org/2003/XInclude"
|
||||
xmlns="http://docbook.org/ns/docbook"
|
||||
>
|
||||
<bookinfo>
|
||||
|
||||
<mediaobject>
|
||||
<imageobject>
|
||||
<imagedata fileref='figures/bitbake-title.png'
|
||||
format='SVG'
|
||||
align='left' scalefit='1' width='100%'/>
|
||||
</imageobject>
|
||||
</mediaobject>
|
||||
|
||||
<title>
|
||||
BitBake User Manual
|
||||
</title>
|
||||
|
||||
<authorgroup>
|
||||
<author>
|
||||
<firstname>Richard Purdie, Chris Larson, and </firstname> <surname>Phil Blundell</surname>
|
||||
<affiliation>
|
||||
<orgname>BitBake Community</orgname>
|
||||
</affiliation>
|
||||
<email>bitbake-devel@lists.openembedded.org</email>
|
||||
</author>
|
||||
</authorgroup>
|
||||
|
||||
<!--
|
||||
# Add in some revision history if we want it here.
|
||||
<revhistory>
|
||||
<revision>
|
||||
<revnumber>x.x</revnumber>
|
||||
<date>dd month year</date>
|
||||
<revremark>Some relevent comment</revremark>
|
||||
</revision>
|
||||
<revision>
|
||||
<revnumber>x.x</revnumber>
|
||||
<date>dd month year</date>
|
||||
<revremark>Some relevent comment</revremark>
|
||||
</revision>
|
||||
<revision>
|
||||
<revnumber>x.x</revnumber>
|
||||
<date>dd month year</date>
|
||||
<revremark>Some relevent comment</revremark>
|
||||
</revision>
|
||||
<revision>
|
||||
<revnumber>x.x</revnumber>
|
||||
<date>dd month year</date>
|
||||
<revremark>Some relevent comment</revremark>
|
||||
</revision>
|
||||
</revhistory>
|
||||
-->
|
||||
|
||||
<copyright>
|
||||
<year>2004-2014</year>
|
||||
<holder>Richard Purdie</holder>
|
||||
<holder>Chris Larson</holder>
|
||||
<holder>and Phil Blundell</holder>
|
||||
</copyright>
|
||||
|
||||
<legalnotice>
|
||||
<para>
|
||||
This work is licensed under the Creative Commons Attribution License.
|
||||
To view a copy of this license, visit
|
||||
<ulink url="http://creativecommons.org/licenses/by/2.5/">http://creativecommons.org/licenses/by/2.5/</ulink>
|
||||
or send a letter to Creative Commons, 444 Castro Street,
|
||||
Suite 900, Mountain View, California 94041, USA.
|
||||
</para>
|
||||
</legalnotice>
|
||||
</bookinfo>
|
||||
|
||||
<xi:include href="user-manual-intro.xml"/>
|
||||
|
||||
<xi:include href="user-manual-metadata.xml"/>
|
||||
|
||||
<xi:include href="user-manual-fetching.xml"/>
|
||||
|
||||
<xi:include href="user-manual-bitbakecommand.xml"/>
|
||||
|
||||
<xi:include href="user-manual-ref-variables.xml"/>
|
||||
|
||||
</book>
|
||||
@@ -21,7 +21,7 @@
|
||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
__version__ = "1.21.1"
|
||||
__version__ = "1.20.0"
|
||||
|
||||
import sys
|
||||
if sys.version_info < (2, 7, 3):
|
||||
@@ -141,3 +141,6 @@ def deprecate_import(current, modulename, fromlist, renames = None):
|
||||
|
||||
setattr(sys.modules[current], newname, newobj)
|
||||
|
||||
deprecate_import(__name__, "bb.fetch", ("MalformedUrl", "encodeurl", "decodeurl"))
|
||||
deprecate_import(__name__, "bb.utils", ("mkdirhier", "movefile", "copyfile", "which"))
|
||||
deprecate_import(__name__, "bb.utils", ["vercmp_string"], ["vercmp"])
|
||||
|
||||
@@ -154,7 +154,6 @@ def exec_func(func, d, dirs = None):
|
||||
if cleandirs:
|
||||
for cdir in d.expand(cleandirs).split():
|
||||
bb.utils.remove(cdir, True)
|
||||
bb.utils.mkdirhier(cdir)
|
||||
|
||||
if dirs is None:
|
||||
dirs = flags.get('dirs')
|
||||
@@ -254,8 +253,19 @@ def exec_func_python(func, d, runfile, cwd=None):
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
def shell_trap_code():
|
||||
return '''#!/bin/sh\n
|
||||
def exec_func_shell(func, d, runfile, cwd=None):
|
||||
"""Execute a shell function from the metadata
|
||||
|
||||
Note on directory behavior. The 'dirs' varflag should contain a list
|
||||
of the directories you need created prior to execution. The last
|
||||
item in the list is where we will chdir/cd to.
|
||||
"""
|
||||
|
||||
# Don't let the emitted shell script override PWD
|
||||
d.delVarFlag('PWD', 'export')
|
||||
|
||||
with open(runfile, 'w') as script:
|
||||
script.write('''#!/bin/sh\n
|
||||
# Emit a useful diagnostic if something fails:
|
||||
bb_exit_handler() {
|
||||
ret=$?
|
||||
@@ -271,28 +281,14 @@ bb_exit_handler() {
|
||||
}
|
||||
trap 'bb_exit_handler' 0
|
||||
set -e
|
||||
'''
|
||||
|
||||
def exec_func_shell(func, d, runfile, cwd=None):
|
||||
"""Execute a shell function from the metadata
|
||||
|
||||
Note on directory behavior. The 'dirs' varflag should contain a list
|
||||
of the directories you need created prior to execution. The last
|
||||
item in the list is where we will chdir/cd to.
|
||||
"""
|
||||
|
||||
# Don't let the emitted shell script override PWD
|
||||
d.delVarFlag('PWD', 'export')
|
||||
|
||||
with open(runfile, 'w') as script:
|
||||
script.write(shell_trap_code())
|
||||
''')
|
||||
|
||||
bb.data.emit_func(func, script, d)
|
||||
|
||||
if bb.msg.loggerVerboseLogs:
|
||||
script.write("set -x\n")
|
||||
if cwd:
|
||||
script.write("cd '%s'\n" % cwd)
|
||||
script.write("cd %s\n" % cwd)
|
||||
script.write("%s\n" % func)
|
||||
script.write('''
|
||||
# cleanup
|
||||
@@ -330,7 +326,7 @@ def _task_data(fn, task, d):
|
||||
localdata.setVar('BB_FILENAME', fn)
|
||||
localdata.setVar('BB_CURRENTTASK', task[3:])
|
||||
localdata.setVar('OVERRIDES', 'task-%s:%s' %
|
||||
(task[3:].replace('_', '-'), d.getVar('OVERRIDES', False)))
|
||||
(task[3:], d.getVar('OVERRIDES', False)))
|
||||
localdata.finalize()
|
||||
bb.data.expandKeys(localdata)
|
||||
return localdata
|
||||
@@ -476,12 +472,12 @@ def _exec_task(fn, task, d, quieterr):
|
||||
return 0
|
||||
|
||||
def exec_task(fn, task, d, profile = False):
|
||||
try:
|
||||
try:
|
||||
quieterr = False
|
||||
if d.getVarFlag(task, "quieterrors") is not None:
|
||||
quieterr = True
|
||||
|
||||
if profile:
|
||||
if profile:
|
||||
profname = "profile-%s.log" % (d.getVar("PN", True) + "-" + task)
|
||||
try:
|
||||
import cProfile as profile
|
||||
@@ -579,7 +575,7 @@ def make_stamp(task, d, file_name = None):
|
||||
if name.endswith('.taint'):
|
||||
continue
|
||||
os.unlink(name)
|
||||
|
||||
|
||||
stamp = stamp_internal(task, d, file_name)
|
||||
# Remove the file and recreate to force timestamp
|
||||
# change on broken NFS filesystems
|
||||
@@ -626,7 +622,7 @@ def stampfile(taskname, d, file_name = None):
|
||||
"""
|
||||
return stamp_internal(taskname, d, file_name)
|
||||
|
||||
def add_tasks(tasklist, deltasklist, d):
|
||||
def add_tasks(tasklist, d):
|
||||
task_deps = d.getVar('_task_deps')
|
||||
if not task_deps:
|
||||
task_deps = {}
|
||||
@@ -637,10 +633,6 @@ def add_tasks(tasklist, deltasklist, d):
|
||||
|
||||
for task in tasklist:
|
||||
task = d.expand(task)
|
||||
|
||||
if task in deltasklist:
|
||||
continue
|
||||
|
||||
d.setVarFlag(task, 'task', 1)
|
||||
|
||||
if not task in task_deps['tasks']:
|
||||
@@ -672,36 +664,9 @@ def add_tasks(tasklist, deltasklist, d):
|
||||
# don't assume holding a reference
|
||||
d.setVar('_task_deps', task_deps)
|
||||
|
||||
def addtask(task, before, after, d):
|
||||
if task[:3] != "do_":
|
||||
task = "do_" + task
|
||||
def remove_task(task, kill, d):
|
||||
"""Remove an BB 'task'.
|
||||
|
||||
d.setVarFlag(task, "task", 1)
|
||||
bbtasks = d.getVar('__BBTASKS') or []
|
||||
if not task in bbtasks:
|
||||
bbtasks.append(task)
|
||||
d.setVar('__BBTASKS', bbtasks)
|
||||
|
||||
existing = d.getVarFlag(task, "deps") or []
|
||||
if after is not None:
|
||||
# set up deps for function
|
||||
for entry in after.split():
|
||||
if entry not in existing:
|
||||
existing.append(entry)
|
||||
d.setVarFlag(task, "deps", existing)
|
||||
if before is not None:
|
||||
# set up things that depend on this func
|
||||
for entry in before.split():
|
||||
existing = d.getVarFlag(entry, "deps") or []
|
||||
if task not in existing:
|
||||
d.setVarFlag(entry, "deps", [task] + existing)
|
||||
|
||||
def deltask(task, d):
|
||||
if task[:3] != "do_":
|
||||
task = "do_" + task
|
||||
|
||||
bbtasks = d.getVar('__BBDELTASKS') or []
|
||||
if not task in bbtasks:
|
||||
bbtasks.append(task)
|
||||
d.setVar('__BBDELTASKS', bbtasks)
|
||||
If kill is 1, also remove tasks that depend on this task."""
|
||||
|
||||
d.delVarFlag(task, 'task')
|
||||
|
||||
@@ -35,7 +35,7 @@ def check_indent(codestr):
|
||||
|
||||
class CodeParserCache(MultiProcessCache):
|
||||
cache_file_name = "bb_codeparser.dat"
|
||||
CACHE_VERSION = 4
|
||||
CACHE_VERSION = 3
|
||||
|
||||
def __init__(self):
|
||||
MultiProcessCache.__init__(self)
|
||||
@@ -64,8 +64,6 @@ class CodeParserCache(MultiProcessCache):
|
||||
for h in data[0]:
|
||||
data[0][h]["refs"] = self.internSet(data[0][h]["refs"])
|
||||
data[0][h]["execs"] = self.internSet(data[0][h]["execs"])
|
||||
for k in data[0][h]["contains"]:
|
||||
data[0][h]["contains"][k] = self.internSet(data[0][h]["contains"][k])
|
||||
for h in data[1]:
|
||||
data[1][h]["execs"] = self.internSet(data[1][h]["execs"])
|
||||
return
|
||||
@@ -124,13 +122,7 @@ class PythonParser():
|
||||
name = self.called_node_name(node.func)
|
||||
if name in self.getvars or name in self.containsfuncs:
|
||||
if isinstance(node.args[0], ast.Str):
|
||||
varname = node.args[0].s
|
||||
if name in self.containsfuncs and isinstance(node.args[1], ast.Str):
|
||||
if varname not in self.contains:
|
||||
self.contains[varname] = set()
|
||||
self.contains[varname].add(node.args[1].s)
|
||||
else:
|
||||
self.references.add(node.args[0].s)
|
||||
self.var_references.add(node.args[0].s)
|
||||
else:
|
||||
self.warn(node.func, node.args[0])
|
||||
elif name in self.execfuncs:
|
||||
@@ -155,11 +147,11 @@ class PythonParser():
|
||||
break
|
||||
|
||||
def __init__(self, name, log):
|
||||
self.var_references = set()
|
||||
self.var_execs = set()
|
||||
self.contains = {}
|
||||
self.execs = set()
|
||||
self.references = set()
|
||||
self.log = BufferedLogger('BitBake.Data.PythonParser', logging.DEBUG, log)
|
||||
self.log = BufferedLogger('BitBake.Data.%s' % name, logging.DEBUG, log)
|
||||
|
||||
self.unhandled_message = "in call of %s, argument '%s' is not a string literal"
|
||||
self.unhandled_message = "while parsing %s, %s" % (name, self.unhandled_message)
|
||||
@@ -170,15 +162,14 @@ class PythonParser():
|
||||
if h in codeparsercache.pythoncache:
|
||||
self.references = codeparsercache.pythoncache[h]["refs"]
|
||||
self.execs = codeparsercache.pythoncache[h]["execs"]
|
||||
self.contains = codeparsercache.pythoncache[h]["contains"]
|
||||
return
|
||||
|
||||
if h in codeparsercache.pythoncacheextras:
|
||||
self.references = codeparsercache.pythoncacheextras[h]["refs"]
|
||||
self.execs = codeparsercache.pythoncacheextras[h]["execs"]
|
||||
self.contains = codeparsercache.pythoncacheextras[h]["contains"]
|
||||
return
|
||||
|
||||
|
||||
code = compile(check_indent(str(node)), "<string>", "exec",
|
||||
ast.PyCF_ONLY_AST)
|
||||
|
||||
@@ -186,12 +177,12 @@ class PythonParser():
|
||||
if n.__class__.__name__ == "Call":
|
||||
self.visit_Call(n)
|
||||
|
||||
self.references.update(self.var_references)
|
||||
self.references.update(self.var_execs)
|
||||
|
||||
codeparsercache.pythoncacheextras[h] = {}
|
||||
codeparsercache.pythoncacheextras[h]["refs"] = self.references
|
||||
codeparsercache.pythoncacheextras[h]["execs"] = self.execs
|
||||
codeparsercache.pythoncacheextras[h]["contains"] = self.contains
|
||||
|
||||
class ShellParser():
|
||||
def __init__(self, name, log):
|
||||
|
||||
@@ -86,8 +86,6 @@ class Command:
|
||||
|
||||
def runAsyncCommand(self):
|
||||
try:
|
||||
if self.cooker.state == bb.cooker.state.error:
|
||||
return False
|
||||
if self.currentAsyncCommand is not None:
|
||||
(command, options) = self.currentAsyncCommand
|
||||
commandmethod = getattr(CommandsAsync, command)
|
||||
@@ -196,11 +194,18 @@ class CommandsSync:
|
||||
"""
|
||||
command.cooker.disableDataTracking()
|
||||
|
||||
def setPrePostConfFiles(self, command, params):
|
||||
prefiles = params[0].split()
|
||||
postfiles = params[1].split()
|
||||
command.cooker.configuration.prefile = prefiles
|
||||
command.cooker.configuration.postfile = postfiles
|
||||
def initCooker(self, command, params):
|
||||
"""
|
||||
Init the cooker to initial state with nothing parsed
|
||||
"""
|
||||
command.cooker.initialize()
|
||||
|
||||
def resetCooker(self, command, params):
|
||||
"""
|
||||
Reset the cooker to its initial state, thus forcing a reparse for
|
||||
any async command that has the needcache property set to True
|
||||
"""
|
||||
command.cooker.reset()
|
||||
|
||||
def getCpuCount(self, command, params):
|
||||
"""
|
||||
@@ -413,6 +418,18 @@ class CommandsAsync:
|
||||
command.finishAsyncCommand()
|
||||
compareRevisions.needcache = True
|
||||
|
||||
def parseConfigurationFiles(self, command, params):
|
||||
"""
|
||||
Parse the configuration files
|
||||
"""
|
||||
prefiles = params[0].split()
|
||||
postfiles = params[1].split()
|
||||
command.cooker.configuration.prefile = prefiles
|
||||
command.cooker.configuration.postfile = postfiles
|
||||
command.cooker.loadConfigurationData()
|
||||
command.finishAsyncCommand()
|
||||
parseConfigurationFiles.needcache = False
|
||||
|
||||
def triggerEvent(self, command, params):
|
||||
"""
|
||||
Trigger a certain event
|
||||
@@ -422,12 +439,3 @@ class CommandsAsync:
|
||||
command.currentAsyncCommand = None
|
||||
triggerEvent.needcache = False
|
||||
|
||||
def resetCooker(self, command, params):
|
||||
"""
|
||||
Reset the cooker to its initial state, thus forcing a reparse for
|
||||
any async command that has the needcache property set to True
|
||||
"""
|
||||
command.cooker.reset()
|
||||
command.finishAsyncCommand()
|
||||
resetCooker.needcache = False
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@ class CollectionError(bb.BBHandledException):
|
||||
"""
|
||||
|
||||
class state:
|
||||
initial, parsing, running, shutdown, forceshutdown, stopped, error = range(7)
|
||||
initial, parsing, running, shutdown, forceshutdown, stopped = range(6)
|
||||
|
||||
|
||||
class SkippedPackage:
|
||||
@@ -117,7 +117,7 @@ class BBCooker:
|
||||
|
||||
self.configuration = configuration
|
||||
|
||||
self.initConfigurationData()
|
||||
self.loadConfigurationData()
|
||||
|
||||
# Take a lock so only one copy of bitbake can run against a given build
|
||||
# directory at a time
|
||||
@@ -125,14 +125,6 @@ class BBCooker:
|
||||
self.lock = bb.utils.lockfile(lockfile, False, False)
|
||||
if not self.lock:
|
||||
bb.fatal("Only one copy of bitbake should be run against a build directory")
|
||||
try:
|
||||
self.lock.seek(0)
|
||||
self.lock.truncate()
|
||||
if len(configuration.interface) >= 2:
|
||||
self.lock.write("%s:%s\n" % (configuration.interface[0], configuration.interface[1]));
|
||||
self.lock.flush()
|
||||
except:
|
||||
pass
|
||||
|
||||
# TOSTOP must not be set or our children will hang when they output
|
||||
fd = sys.stdout.fileno()
|
||||
@@ -152,10 +144,8 @@ class BBCooker:
|
||||
def initConfigurationData(self):
|
||||
|
||||
self.state = state.initial
|
||||
self.caches_array = []
|
||||
|
||||
if CookerFeatures.BASEDATASTORE_TRACKING in self.featureset:
|
||||
self.enableDataTracking()
|
||||
self.caches_array = []
|
||||
|
||||
all_extra_cache_names = []
|
||||
# We hardcode all known cache types in a single place, here.
|
||||
@@ -176,6 +166,21 @@ class BBCooker:
|
||||
sys.exit("FATAL: Failed to import extra cache class '%s'." % cache_name)
|
||||
|
||||
self.databuilder = bb.cookerdata.CookerDataBuilder(self.configuration, False)
|
||||
self.data = self.databuilder.data
|
||||
|
||||
def enableDataTracking(self):
|
||||
self.configuration.tracking = True
|
||||
self.data.enableTracking()
|
||||
|
||||
def disableDataTracking(self):
|
||||
self.configuration.tracking = False
|
||||
self.data.disableTracking()
|
||||
|
||||
def loadConfigurationData(self):
|
||||
if CookerFeatures.BASEDATASTORE_TRACKING in self.featureset:
|
||||
self.enableDataTracking()
|
||||
|
||||
self.initConfigurationData()
|
||||
self.databuilder.parseBaseConfiguration()
|
||||
self.data = self.databuilder.data
|
||||
self.data_hash = self.databuilder.data_hash
|
||||
@@ -190,13 +195,6 @@ class BBCooker:
|
||||
if CookerFeatures.BASEDATASTORE_TRACKING in self.featureset:
|
||||
self.disableDataTracking()
|
||||
|
||||
def enableDataTracking(self):
|
||||
self.configuration.tracking = True
|
||||
self.data.enableTracking()
|
||||
|
||||
def disableDataTracking(self):
|
||||
self.configuration.tracking = False
|
||||
self.data.disableTracking()
|
||||
|
||||
def modifyConfigurationVar(self, var, val, default_file, op):
|
||||
if op == "append":
|
||||
@@ -211,11 +209,20 @@ class BBCooker:
|
||||
#add append var operation to the end of default_file
|
||||
default_file = bb.cookerdata.findConfigFile(default_file, self.data)
|
||||
|
||||
total = "#added by hob"
|
||||
with open(default_file, 'r') as f:
|
||||
contents = f.readlines()
|
||||
f.close()
|
||||
|
||||
total = ""
|
||||
for c in contents:
|
||||
total += c
|
||||
|
||||
total += "#added by hob"
|
||||
total += "\n%s += \"%s\"\n" % (var, val)
|
||||
|
||||
with open(default_file, 'a') as f:
|
||||
with open(default_file, 'w') as f:
|
||||
f.write(total)
|
||||
f.close()
|
||||
|
||||
#add to history
|
||||
loginfo = {"op":append, "file":default_file, "line":total.count("\n")}
|
||||
@@ -244,6 +251,7 @@ class BBCooker:
|
||||
if topdir in conf_file:
|
||||
with open(conf_file, 'r') as f:
|
||||
contents = f.readlines()
|
||||
f.close()
|
||||
|
||||
lines = self.data.varhistory.get_variable_lines(var, conf_file)
|
||||
for line in lines:
|
||||
@@ -269,8 +277,12 @@ class BBCooker:
|
||||
for ii in range(begin_line, end_line):
|
||||
contents[ii] = "#" + contents[ii]
|
||||
|
||||
total = ""
|
||||
for c in contents:
|
||||
total += c
|
||||
with open(conf_file, 'w') as f:
|
||||
f.writelines(contents)
|
||||
f.write(total)
|
||||
f.close()
|
||||
|
||||
if replaced == False:
|
||||
#remove var from history
|
||||
@@ -279,12 +291,21 @@ class BBCooker:
|
||||
#add var to the end of default_file
|
||||
default_file = bb.cookerdata.findConfigFile(default_file, self.data)
|
||||
|
||||
with open(default_file, 'r') as f:
|
||||
contents = f.readlines()
|
||||
f.close()
|
||||
|
||||
total = ""
|
||||
for c in contents:
|
||||
total += c
|
||||
|
||||
#add the variable on a single line, to be easy to replace the second time
|
||||
total = "\n#added by hob"
|
||||
total += "\n#added by hob"
|
||||
total += "\n%s %s \"%s\"\n" % (var, op, val)
|
||||
|
||||
with open(default_file, 'a') as f:
|
||||
with open(default_file, 'w') as f:
|
||||
f.write(total)
|
||||
f.close()
|
||||
|
||||
#add to history
|
||||
loginfo = {"op":set, "file":default_file, "line":total.count("\n")}
|
||||
@@ -298,6 +319,7 @@ class BBCooker:
|
||||
if topdir in conf_file:
|
||||
with open(conf_file, 'r') as f:
|
||||
contents = f.readlines()
|
||||
f.close()
|
||||
|
||||
lines = self.data.varhistory.get_variable_lines(var, conf_file)
|
||||
for line in lines:
|
||||
@@ -320,8 +342,12 @@ class BBCooker:
|
||||
#remove var from history
|
||||
self.data.varhistory.del_var_history(var, conf_file, line)
|
||||
|
||||
total = ""
|
||||
for c in contents:
|
||||
total += c
|
||||
with open(conf_file, 'w') as f:
|
||||
f.writelines(contents)
|
||||
f.write(total)
|
||||
f.close()
|
||||
|
||||
def createConfigFile(self, name):
|
||||
path = os.getcwd()
|
||||
@@ -449,14 +475,9 @@ class BBCooker:
|
||||
current = 0
|
||||
runlist = []
|
||||
for k in fulltargetlist:
|
||||
ktask = task
|
||||
if ":do_" in k:
|
||||
k2 = k.split(":do_")
|
||||
k = k2[0]
|
||||
ktask = k2[1]
|
||||
taskdata.add_provider(localdata, self.recipecache, k)
|
||||
current += 1
|
||||
runlist.append([k, "do_%s" % ktask])
|
||||
runlist.append([k, "do_%s" % task])
|
||||
bb.event.fire(bb.event.TreeDataPreparationProgress(current, len(fulltargetlist)), self.data)
|
||||
taskdata.add_unresolved(localdata, self.recipecache)
|
||||
bb.event.fire(bb.event.TreeDataPreparationCompleted(len(fulltargetlist)), self.data)
|
||||
@@ -713,9 +734,14 @@ class BBCooker:
|
||||
logger.info("Task dependencies saved to 'task-depends.dot'")
|
||||
|
||||
def show_appends_with_no_recipes( self ):
|
||||
recipes = set(os.path.basename(f)
|
||||
for f in self.recipecache.pkg_fn.iterkeys())
|
||||
recipes |= set(os.path.basename(f)
|
||||
for f in self.skiplist.iterkeys())
|
||||
appended_recipes = self.collection.appendlist.iterkeys()
|
||||
appends_without_recipes = [self.collection.appendlist[recipe]
|
||||
for recipe in self.collection.appendlist
|
||||
if recipe not in self.collection.appliedappendlist]
|
||||
for recipe in appended_recipes
|
||||
if recipe not in recipes]
|
||||
if appends_without_recipes:
|
||||
appendlines = (' %s' % append
|
||||
for appends in appends_without_recipes
|
||||
@@ -1111,13 +1137,10 @@ class BBCooker:
|
||||
|
||||
def buildFileIdle(server, rq, abort):
|
||||
|
||||
msg = None
|
||||
if abort or self.state == state.forceshutdown:
|
||||
rq.finish_runqueue(True)
|
||||
msg = "Forced shutdown"
|
||||
elif self.state == state.shutdown:
|
||||
rq.finish_runqueue(False)
|
||||
msg = "Stopped build"
|
||||
failures = 0
|
||||
try:
|
||||
retval = rq.execute_runqueue()
|
||||
@@ -1130,7 +1153,7 @@ class BBCooker:
|
||||
|
||||
if not retval:
|
||||
bb.event.fire(bb.event.BuildCompleted(len(rq.rqdata.runq_fnid), buildname, item, failures), self.event_data)
|
||||
self.command.finishAsyncCommand(msg)
|
||||
self.command.finishAsyncCommand()
|
||||
return False
|
||||
if retval is True:
|
||||
return True
|
||||
@@ -1144,13 +1167,10 @@ class BBCooker:
|
||||
"""
|
||||
|
||||
def buildTargetsIdle(server, rq, abort):
|
||||
msg = None
|
||||
if abort or self.state == state.forceshutdown:
|
||||
rq.finish_runqueue(True)
|
||||
msg = "Forced shutdown"
|
||||
elif self.state == state.shutdown:
|
||||
rq.finish_runqueue(False)
|
||||
msg = "Stopped build"
|
||||
failures = 0
|
||||
try:
|
||||
retval = rq.execute_runqueue()
|
||||
@@ -1163,7 +1183,7 @@ class BBCooker:
|
||||
|
||||
if not retval:
|
||||
bb.event.fire(bb.event.BuildCompleted(len(rq.rqdata.runq_fnid), buildname, targets, failures), self.data)
|
||||
self.command.finishAsyncCommand(msg)
|
||||
self.command.finishAsyncCommand()
|
||||
return False
|
||||
if retval is True:
|
||||
return True
|
||||
@@ -1245,8 +1265,7 @@ class BBCooker:
|
||||
return
|
||||
|
||||
if self.state in (state.shutdown, state.forceshutdown):
|
||||
if hasattr(self.parser, 'shutdown'):
|
||||
self.parser.shutdown(clean=False, force = True)
|
||||
self.parser.shutdown(clean=False, force = True)
|
||||
raise bb.BBHandledException()
|
||||
|
||||
if self.state != state.parsing:
|
||||
@@ -1286,11 +1305,6 @@ class BBCooker:
|
||||
if len(pkgs_to_build) == 0:
|
||||
raise NothingToBuild
|
||||
|
||||
ignore = (self.data.getVar("ASSUME_PROVIDED", True) or "").split()
|
||||
for pkg in pkgs_to_build:
|
||||
if pkg in ignore:
|
||||
parselog.warn("Explicit target \"%s\" is in ASSUME_PROVIDED, ignoring" % pkg)
|
||||
|
||||
if 'world' in pkgs_to_build:
|
||||
self.buildWorldTargetList()
|
||||
pkgs_to_build.remove('world')
|
||||
@@ -1317,7 +1331,6 @@ class BBCooker:
|
||||
self.prhost = prserv.serv.auto_start(self.data)
|
||||
except prserv.serv.PRServiceConfigError:
|
||||
bb.event.fire(CookerExit(), self.event_data)
|
||||
self.state = state.error
|
||||
return
|
||||
|
||||
def post_serve(self):
|
||||
@@ -1333,9 +1346,12 @@ class BBCooker:
|
||||
def finishcommand(self):
|
||||
self.state = state.initial
|
||||
|
||||
def reset(self):
|
||||
def initialize(self):
|
||||
self.initConfigurationData()
|
||||
|
||||
def reset(self):
|
||||
self.loadConfigurationData()
|
||||
|
||||
def server_main(cooker, func, *args):
|
||||
cooker.pre_serve()
|
||||
|
||||
@@ -1371,7 +1387,6 @@ class CookerExit(bb.event.Event):
|
||||
class CookerCollectFiles(object):
|
||||
def __init__(self, priorities):
|
||||
self.appendlist = {}
|
||||
self.appliedappendlist = []
|
||||
self.bbfile_config_priorities = priorities
|
||||
|
||||
def calc_bbfile_priority( self, filename, matched = None ):
|
||||
@@ -1488,14 +1503,10 @@ class CookerCollectFiles(object):
|
||||
"""
|
||||
Returns a list of .bbappend files to apply to fn
|
||||
"""
|
||||
filelist = []
|
||||
f = os.path.basename(fn)
|
||||
for bbappend in self.appendlist:
|
||||
if (bbappend == f) or ('%' in bbappend and bbappend.startswith(f[:bbappend.index('%')])):
|
||||
self.appliedappendlist.append(bbappend)
|
||||
for filename in self.appendlist[bbappend]:
|
||||
filelist.append(filename)
|
||||
return filelist
|
||||
if f in self.appendlist:
|
||||
return self.appendlist[f]
|
||||
return []
|
||||
|
||||
def collection_priorities(self, pkgfns):
|
||||
|
||||
|
||||
@@ -127,7 +127,6 @@ class CookerConfiguration(object):
|
||||
self.dump_signatures = False
|
||||
self.dry_run = False
|
||||
self.tracking = False
|
||||
self.interface = []
|
||||
|
||||
self.env = {}
|
||||
|
||||
|
||||
@@ -214,7 +214,7 @@ def emit_var(var, o=sys.__stdout__, d = init(), all=False):
|
||||
o.write('unset %s\n' % varExpanded)
|
||||
return 0
|
||||
|
||||
if val is None:
|
||||
if not val:
|
||||
return 0
|
||||
|
||||
val = str(val)
|
||||
@@ -229,7 +229,7 @@ def emit_var(var, o=sys.__stdout__, d = init(), all=False):
|
||||
|
||||
# if we're going to output this within doublequotes,
|
||||
# to a shell, we need to escape the quotes in the var
|
||||
alter = re.sub('"', '\\"', val)
|
||||
alter = re.sub('"', '\\"', val.strip())
|
||||
alter = re.sub('\n', ' \\\n', alter)
|
||||
o.write('%s="%s"\n' % (varExpanded, alter))
|
||||
return 0
|
||||
@@ -275,7 +275,7 @@ def emit_func(func, o=sys.__stdout__, d = init()):
|
||||
seen |= deps
|
||||
newdeps = set()
|
||||
for dep in deps:
|
||||
if d.getVarFlag(dep, "func") and not d.getVarFlag(dep, "python"):
|
||||
if d.getVarFlag(dep, "func"):
|
||||
emit_var(dep, o, d, False) and o.write('\n')
|
||||
newdeps |= bb.codeparser.ShellParser(dep, logger).parse_shell(d.getVar(dep, True))
|
||||
newdeps |= set((d.getVarFlag(dep, "vardeps", True) or "").split())
|
||||
@@ -295,25 +295,10 @@ def build_dependencies(key, keys, shelldeps, varflagsexcl, d):
|
||||
deps |= parser.references
|
||||
deps = deps | (keys & parser.execs)
|
||||
return deps, value
|
||||
varflags = d.getVarFlags(key, ["vardeps", "vardepvalue", "vardepsexclude", "postfuncs", "prefuncs"]) or {}
|
||||
varflags = d.getVarFlags(key, ["vardeps", "vardepvalue", "vardepsexclude"]) or {}
|
||||
vardeps = varflags.get("vardeps")
|
||||
value = d.getVar(key, False)
|
||||
|
||||
def handle_contains(value, contains, d):
|
||||
newvalue = ""
|
||||
for k in sorted(contains):
|
||||
l = (d.getVar(k, True) or "").split()
|
||||
for word in sorted(contains[k]):
|
||||
if word in l:
|
||||
newvalue += "\n%s{%s} = Set" % (k, word)
|
||||
else:
|
||||
newvalue += "\n%s{%s} = Unset" % (k, word)
|
||||
if not newvalue:
|
||||
return value
|
||||
if not value:
|
||||
return newvalue
|
||||
return value + newvalue
|
||||
|
||||
if "vardepvalue" in varflags:
|
||||
value = varflags.get("vardepvalue")
|
||||
elif varflags.get("func"):
|
||||
@@ -324,7 +309,6 @@ def build_dependencies(key, keys, shelldeps, varflagsexcl, d):
|
||||
logger.warn("Variable %s contains tabs, please remove these (%s)" % (key, d.getVar("FILE", True)))
|
||||
parser.parse_python(parsedvar.value)
|
||||
deps = deps | parser.references
|
||||
value = handle_contains(value, parser.contains, d)
|
||||
else:
|
||||
parsedvar = d.expandWithRefs(value, key)
|
||||
parser = bb.codeparser.ShellParser(key, logger)
|
||||
@@ -332,18 +316,12 @@ def build_dependencies(key, keys, shelldeps, varflagsexcl, d):
|
||||
deps = deps | shelldeps
|
||||
if vardeps is None:
|
||||
parser.log.flush()
|
||||
if "prefuncs" in varflags:
|
||||
deps = deps | set(varflags["prefuncs"].split())
|
||||
if "postfuncs" in varflags:
|
||||
deps = deps | set(varflags["postfuncs"].split())
|
||||
deps = deps | parsedvar.references
|
||||
deps = deps | (keys & parser.execs) | (keys & parsedvar.execs)
|
||||
value = handle_contains(value, parsedvar.contains, d)
|
||||
else:
|
||||
parser = d.expandWithRefs(value, key)
|
||||
deps |= parser.references
|
||||
deps = deps | (keys & parser.execs)
|
||||
value = handle_contains(value, parser.contains, d)
|
||||
|
||||
# Add varflags, assuming an exclusion list is set
|
||||
if varflagsexcl:
|
||||
|
||||
@@ -88,7 +88,6 @@ class VariableParse:
|
||||
|
||||
self.references = set()
|
||||
self.execs = set()
|
||||
self.contains = {}
|
||||
|
||||
def var_sub(self, match):
|
||||
key = match.group()[2:-1]
|
||||
@@ -99,7 +98,7 @@ class VariableParse:
|
||||
varparse = self.d.expand_cache[key]
|
||||
var = varparse.value
|
||||
else:
|
||||
var = self.d.getVarFlag(key, "_content", True)
|
||||
var = self.d.getVar(key, True)
|
||||
self.references.add(key)
|
||||
if var is not None:
|
||||
return var
|
||||
@@ -121,11 +120,6 @@ class VariableParse:
|
||||
self.references |= parser.references
|
||||
self.execs |= parser.execs
|
||||
|
||||
for k in parser.contains:
|
||||
if k not in self.contains:
|
||||
self.contains[k] = parser.contains[k].copy()
|
||||
else:
|
||||
self.contains[k].update(parser.contains[k])
|
||||
value = utils.better_eval(codeobj, DataContext(self.d))
|
||||
return str(value)
|
||||
|
||||
|
||||
@@ -329,7 +329,7 @@ def decodeurl(url):
|
||||
user, password, parameters).
|
||||
"""
|
||||
|
||||
m = re.compile('(?P<type>[^:]*)://((?P<user>[^/]+)@)?(?P<location>[^;]+)(;(?P<parm>.*))?').match(url)
|
||||
m = re.compile('(?P<type>[^:]*)://((?P<user>.+)@)?(?P<location>[^;]+)(;(?P<parm>.*))?').match(url)
|
||||
if not m:
|
||||
raise MalformedUrl(url)
|
||||
|
||||
@@ -507,7 +507,7 @@ def fetcher_compare_revisions(d):
|
||||
def mirror_from_string(data):
|
||||
return [ i.split() for i in (data or "").replace('\\n','\n').split('\n') if i ]
|
||||
|
||||
def verify_checksum(ud, d):
|
||||
def verify_checksum(u, ud, d):
|
||||
"""
|
||||
verify the MD5 and SHA256 checksum for downloaded src
|
||||
|
||||
@@ -526,20 +526,19 @@ def verify_checksum(ud, d):
|
||||
if ud.method.recommends_checksum(ud):
|
||||
# If strict checking enabled and neither sum defined, raise error
|
||||
strict = d.getVar("BB_STRICT_CHECKSUM", True) or None
|
||||
if strict and not (ud.md5_expected or ud.sha256_expected):
|
||||
logger.error('No checksum specified for %s, please add at least one to the recipe:\n'
|
||||
if (strict and ud.md5_expected == None and ud.sha256_expected == None):
|
||||
raise NoChecksumError('No checksum specified for %s, please add at least one to the recipe:\n'
|
||||
'SRC_URI[%s] = "%s"\nSRC_URI[%s] = "%s"' %
|
||||
(ud.localpath, ud.md5_name, md5data,
|
||||
ud.sha256_name, sha256data))
|
||||
raise NoChecksumError('Missing SRC_URI checksum', ud.url)
|
||||
ud.sha256_name, sha256data), u)
|
||||
|
||||
# Log missing sums so user can more easily add them
|
||||
if not ud.md5_expected:
|
||||
if ud.md5_expected == None:
|
||||
logger.warn('Missing md5 SRC_URI checksum for %s, consider adding to the recipe:\n'
|
||||
'SRC_URI[%s] = "%s"',
|
||||
ud.localpath, ud.md5_name, md5data)
|
||||
|
||||
if not ud.sha256_expected:
|
||||
if ud.sha256_expected == None:
|
||||
logger.warn('Missing sha256 SRC_URI checksum for %s, consider adding to the recipe:\n'
|
||||
'SRC_URI[%s] = "%s"',
|
||||
ud.localpath, ud.sha256_name, sha256data)
|
||||
@@ -569,10 +568,10 @@ def verify_checksum(ud, d):
|
||||
msg = msg + '\nIf this change is expected (e.g. you have upgraded to a new version without updating the checksums) then you can use these lines within the recipe:\nSRC_URI[%s] = "%s"\nSRC_URI[%s] = "%s"\nOtherwise you should retry the download and/or check with upstream to determine if the file has become corrupted or otherwise unexpectedly modified.\n' % (ud.md5_name, md5data, ud.sha256_name, sha256data)
|
||||
|
||||
if len(msg):
|
||||
raise ChecksumError('Checksum mismatch!%s' % msg, ud.url, md5data)
|
||||
raise ChecksumError('Checksum mismatch!%s' % msg, u, md5data)
|
||||
|
||||
|
||||
def update_stamp(ud, d):
|
||||
def update_stamp(u, ud, d):
|
||||
"""
|
||||
donestamp is file stamp indicating the whole fetching is done
|
||||
this function update the stamp after verifying the checksum
|
||||
@@ -585,7 +584,7 @@ def update_stamp(ud, d):
|
||||
# Errors aren't fatal here
|
||||
pass
|
||||
else:
|
||||
verify_checksum(ud, d)
|
||||
verify_checksum(u, ud, d)
|
||||
open(ud.donestamp, 'w').close()
|
||||
|
||||
def subprocess_setup():
|
||||
@@ -620,7 +619,7 @@ def get_srcrev(d):
|
||||
raise FetchError("SRCREV was used yet no valid SCM was found in SRC_URI")
|
||||
|
||||
if len(scms) == 1 and len(urldata[scms[0]].names) == 1:
|
||||
autoinc, rev = urldata[scms[0]].method.sortable_revision(urldata[scms[0]], d, urldata[scms[0]].names[0])
|
||||
autoinc, rev = urldata[scms[0]].method.sortable_revision(scms[0], urldata[scms[0]], d, urldata[scms[0]].names[0])
|
||||
if len(rev) > 10:
|
||||
rev = rev[:10]
|
||||
if autoinc:
|
||||
@@ -638,7 +637,7 @@ def get_srcrev(d):
|
||||
for scm in scms:
|
||||
ud = urldata[scm]
|
||||
for name in ud.names:
|
||||
autoinc, rev = ud.method.sortable_revision(ud, d, name)
|
||||
autoinc, rev = ud.method.sortable_revision(scm, ud, d, name)
|
||||
seenautoinc = seenautoinc or autoinc
|
||||
if len(rev) > 10:
|
||||
rev = rev[:10]
|
||||
@@ -731,7 +730,7 @@ def build_mirroruris(origud, mirrors, ld):
|
||||
replacements["BASENAME"] = origud.path.split("/")[-1]
|
||||
replacements["MIRRORNAME"] = origud.host.replace(':','.') + origud.path.replace('/', '.').replace('*', '.')
|
||||
|
||||
def adduri(ud, uris, uds):
|
||||
def adduri(uri, ud, uris, uds):
|
||||
for line in mirrors:
|
||||
try:
|
||||
(find, replace) = line
|
||||
@@ -754,9 +753,9 @@ def build_mirroruris(origud, mirrors, ld):
|
||||
uris.append(newuri)
|
||||
uds.append(newud)
|
||||
|
||||
adduri(newud, uris, uds)
|
||||
adduri(newuri, newud, uris, uds)
|
||||
|
||||
adduri(origud, uris, uds)
|
||||
adduri(None, origud, uris, uds)
|
||||
|
||||
return uris, uds
|
||||
|
||||
@@ -773,22 +772,22 @@ def rename_bad_checksum(ud, suffix):
|
||||
bb.utils.movefile(ud.localpath, new_localpath)
|
||||
|
||||
|
||||
def try_mirror_url(origud, ud, ld, check = False):
|
||||
def try_mirror_url(newuri, origud, ud, ld, check = False):
|
||||
# Return of None or a value means we're finished
|
||||
# False means try another url
|
||||
try:
|
||||
if check:
|
||||
found = ud.method.checkstatus(ud, ld)
|
||||
found = ud.method.checkstatus(newuri, ud, ld)
|
||||
if found:
|
||||
return found
|
||||
return False
|
||||
|
||||
os.chdir(ld.getVar("DL_DIR", True))
|
||||
|
||||
if not os.path.exists(ud.donestamp) or ud.method.need_update(ud, ld):
|
||||
ud.method.download(ud, ld)
|
||||
if not os.path.exists(ud.donestamp) or ud.method.need_update(newuri, ud, ld):
|
||||
ud.method.download(newuri, ud, ld)
|
||||
if hasattr(ud.method,"build_mirror_data"):
|
||||
ud.method.build_mirror_data(ud, ld)
|
||||
ud.method.build_mirror_data(newuri, ud, ld)
|
||||
|
||||
if not ud.localpath or not os.path.exists(ud.localpath):
|
||||
return False
|
||||
@@ -806,11 +805,7 @@ def try_mirror_url(origud, ud, ld, check = False):
|
||||
dest = os.path.join(dldir, os.path.basename(ud.localpath))
|
||||
if not os.path.exists(dest):
|
||||
os.symlink(ud.localpath, dest)
|
||||
if not os.path.exists(origud.donestamp) or origud.method.need_update(origud, ld):
|
||||
origud.method.download(origud, ld)
|
||||
if hasattr(ud.method,"build_mirror_data"):
|
||||
origud.method.build_mirror_data(origud, ld)
|
||||
return ud.localpath
|
||||
return None
|
||||
# Otherwise the result is a local file:// and we symlink to it
|
||||
if not os.path.exists(origud.localpath):
|
||||
if os.path.islink(origud.localpath):
|
||||
@@ -818,7 +813,7 @@ def try_mirror_url(origud, ud, ld, check = False):
|
||||
os.unlink(origud.localpath)
|
||||
|
||||
os.symlink(ud.localpath, origud.localpath)
|
||||
update_stamp(origud, ld)
|
||||
update_stamp(newuri, origud, ld)
|
||||
return ud.localpath
|
||||
|
||||
except bb.fetch2.NetworkAccess:
|
||||
@@ -826,13 +821,13 @@ def try_mirror_url(origud, ud, ld, check = False):
|
||||
|
||||
except bb.fetch2.BBFetchException as e:
|
||||
if isinstance(e, ChecksumError):
|
||||
logger.warn("Mirror checksum failure for url %s (original url: %s)\nCleaning and trying again." % (ud.url, origud.url))
|
||||
logger.warn("Mirror checksum failure for url %s (original url: %s)\nCleaning and trying again." % (newuri, origud.url))
|
||||
logger.warn(str(e))
|
||||
rename_bad_checksum(ud, e.checksum)
|
||||
elif isinstance(e, NoChecksumError):
|
||||
raise
|
||||
else:
|
||||
logger.debug(1, "Mirror fetch failure for url %s (original url: %s)" % (ud.url, origud.url))
|
||||
logger.debug(1, "Mirror fetch failure for url %s (original url: %s)" % (newuri, origud.url))
|
||||
logger.debug(1, str(e))
|
||||
try:
|
||||
ud.method.clean(ud, ld)
|
||||
@@ -854,7 +849,7 @@ def try_mirrors(d, origud, mirrors, check = False):
|
||||
uris, uds = build_mirroruris(origud, mirrors, ld)
|
||||
|
||||
for index, uri in enumerate(uris):
|
||||
ret = try_mirror_url(origud, uds[index], ld, check)
|
||||
ret = try_mirror_url(uri, origud, uds[index], ld, check)
|
||||
if ret != False:
|
||||
return ret
|
||||
return None
|
||||
@@ -867,42 +862,32 @@ def srcrev_internal_helper(ud, d, name):
|
||||
c) None if not specified
|
||||
"""
|
||||
|
||||
srcrev = None
|
||||
if 'rev' in ud.parm:
|
||||
return ud.parm['rev']
|
||||
|
||||
if 'tag' in ud.parm:
|
||||
return ud.parm['tag']
|
||||
|
||||
rev = None
|
||||
pn = d.getVar("PN", True)
|
||||
attempts = []
|
||||
if name != '' and pn:
|
||||
attempts.append("SRCREV_%s_pn-%s" % (name, pn))
|
||||
if name != '':
|
||||
attempts.append("SRCREV_%s" % name)
|
||||
if pn:
|
||||
attempts.append("SRCREV_pn-%s" % pn)
|
||||
attempts.append("SRCREV")
|
||||
rev = d.getVar("SRCREV_%s_pn-%s" % (name, pn), True)
|
||||
if not rev:
|
||||
rev = d.getVar("SRCREV_%s" % name, True)
|
||||
if not rev:
|
||||
rev = d.getVar("SRCREV_pn-%s" % pn, True)
|
||||
if not rev:
|
||||
rev = d.getVar("SRCREV", True)
|
||||
if rev == "INVALID":
|
||||
var = "SRCREV_pn-%s" % pn
|
||||
if name != '':
|
||||
var = "SRCREV_%s_pn-%s" % (name, pn)
|
||||
raise FetchError("Please set %s to a valid value" % var, ud.url)
|
||||
if rev == "AUTOINC":
|
||||
rev = ud.method.latest_revision(ud.url, ud, d, name)
|
||||
|
||||
for a in attempts:
|
||||
srcrev = d.getVar(a, True)
|
||||
if srcrev and srcrev != "INVALID":
|
||||
break
|
||||
return rev
|
||||
|
||||
if 'rev' in ud.parm and 'tag' in ud.parm:
|
||||
raise FetchError("Please specify a ;rev= parameter or a ;tag= parameter in the url %s but not both." % (ud.url))
|
||||
|
||||
if 'rev' in ud.parm or 'tag' in ud.parm:
|
||||
if 'rev' in ud.parm:
|
||||
parmrev = ud.parm['rev']
|
||||
else:
|
||||
parmrev = ud.parm['tag']
|
||||
if srcrev == "INVALID" or not srcrev:
|
||||
return parmrev
|
||||
if srcrev != parmrev:
|
||||
raise FetchError("Conflicting revisions (%s from SRCREV and %s from the url) found, please spcify one valid value" % (srcrev, parmrev))
|
||||
return parmrev
|
||||
|
||||
if srcrev == "INVALID" or not srcrev:
|
||||
raise FetchError("Please set a valid SRCREV for url %s (possible key names are %s, or use a ;rev=X URL parameter)" % (str(attempts), ud.url), ud.url)
|
||||
if srcrev == "AUTOINC":
|
||||
srcrev = ud.method.latest_revision(ud, d, name)
|
||||
|
||||
return srcrev
|
||||
|
||||
def get_checksum_file_list(d):
|
||||
""" Get a list of files checksum in SRC_URI
|
||||
@@ -1020,7 +1005,7 @@ class FetchData(object):
|
||||
|
||||
self.method = None
|
||||
for m in methods:
|
||||
if m.supports(self, d):
|
||||
if m.supports(url, self, d):
|
||||
self.method = m
|
||||
break
|
||||
|
||||
@@ -1042,7 +1027,7 @@ class FetchData(object):
|
||||
self.localpath = self.parm["localpath"]
|
||||
self.basename = os.path.basename(self.localpath)
|
||||
elif self.localfile:
|
||||
self.localpath = self.method.localpath(self, d)
|
||||
self.localpath = self.method.localpath(self.url, self, d)
|
||||
|
||||
dldir = d.getVar("DL_DIR", True)
|
||||
# Note: .done and .lock files should always be in DL_DIR whereas localpath may not be.
|
||||
@@ -1066,7 +1051,7 @@ class FetchData(object):
|
||||
|
||||
def setup_localpath(self, d):
|
||||
if not self.localpath:
|
||||
self.localpath = self.method.localpath(self, d)
|
||||
self.localpath = self.method.localpath(self.url, self, d)
|
||||
|
||||
def getSRCDate(self, d):
|
||||
"""
|
||||
@@ -1090,13 +1075,13 @@ class FetchMethod(object):
|
||||
def __init__(self, urls = []):
|
||||
self.urls = []
|
||||
|
||||
def supports(self, urldata, d):
|
||||
def supports(self, url, urldata, d):
|
||||
"""
|
||||
Check to see if this fetch class supports a given url.
|
||||
"""
|
||||
return 0
|
||||
|
||||
def localpath(self, urldata, d):
|
||||
def localpath(self, url, urldata, d):
|
||||
"""
|
||||
Return the local filename of a given url assuming a successful fetch.
|
||||
Can also setup variables in urldata for use in go (saving code duplication
|
||||
@@ -1140,7 +1125,7 @@ class FetchMethod(object):
|
||||
|
||||
urls = property(getUrls, setUrls, None, "Urls property")
|
||||
|
||||
def need_update(self, ud, d):
|
||||
def need_update(self, url, ud, d):
|
||||
"""
|
||||
Force a fetch, even if localpath exists?
|
||||
"""
|
||||
@@ -1154,7 +1139,7 @@ class FetchMethod(object):
|
||||
"""
|
||||
return False
|
||||
|
||||
def download(self, urldata, d):
|
||||
def download(self, url, urldata, d):
|
||||
"""
|
||||
Fetch urls
|
||||
Assumes localpath was called first
|
||||
@@ -1273,18 +1258,18 @@ class FetchMethod(object):
|
||||
return
|
||||
|
||||
def clean(self, urldata, d):
|
||||
"""
|
||||
Clean any existing full or partial download
|
||||
"""
|
||||
bb.utils.remove(urldata.localpath)
|
||||
"""
|
||||
Clean any existing full or partial download
|
||||
"""
|
||||
bb.utils.remove(urldata.localpath)
|
||||
|
||||
def try_premirror(self, urldata, d):
|
||||
def try_premirror(self, url, urldata, d):
|
||||
"""
|
||||
Should premirrors be used?
|
||||
"""
|
||||
return True
|
||||
|
||||
def checkstatus(self, urldata, d):
|
||||
def checkstatus(self, url, urldata, d):
|
||||
"""
|
||||
Check the status of a URL
|
||||
Assumes localpath was called first
|
||||
@@ -1292,7 +1277,7 @@ class FetchMethod(object):
|
||||
logger.info("URL %s could not be checked for status since no method exists.", url)
|
||||
return True
|
||||
|
||||
def latest_revision(self, ud, d, name):
|
||||
def latest_revision(self, url, ud, d, name):
|
||||
"""
|
||||
Look in the cache for the latest revision, if not present ask the SCM.
|
||||
"""
|
||||
@@ -1300,19 +1285,19 @@ class FetchMethod(object):
|
||||
raise ParameterError("The fetcher for this URL does not support _latest_revision", url)
|
||||
|
||||
revs = bb.persist_data.persist('BB_URI_HEADREVS', d)
|
||||
key = self.generate_revision_key(ud, d, name)
|
||||
key = self.generate_revision_key(url, ud, d, name)
|
||||
try:
|
||||
return revs[key]
|
||||
except KeyError:
|
||||
revs[key] = rev = self._latest_revision(ud, d, name)
|
||||
revs[key] = rev = self._latest_revision(url, ud, d, name)
|
||||
return rev
|
||||
|
||||
def sortable_revision(self, ud, d, name):
|
||||
latest_rev = self._build_revision(ud, d, name)
|
||||
def sortable_revision(self, url, ud, d, name):
|
||||
latest_rev = self._build_revision(url, ud, d, name)
|
||||
return True, str(latest_rev)
|
||||
|
||||
def generate_revision_key(self, ud, d, name):
|
||||
key = self._revision_key(ud, d, name)
|
||||
def generate_revision_key(self, url, ud, d, name):
|
||||
key = self._revision_key(url, ud, d, name)
|
||||
return "%s-%s" % (key, d.getVar("PN", True) or "")
|
||||
|
||||
class Fetch(object):
|
||||
@@ -1383,9 +1368,9 @@ class Fetch(object):
|
||||
try:
|
||||
self.d.setVar("BB_NO_NETWORK", network)
|
||||
|
||||
if os.path.exists(ud.donestamp) and not m.need_update(ud, self.d):
|
||||
if os.path.exists(ud.donestamp) and not m.need_update(u, ud, self.d):
|
||||
localpath = ud.localpath
|
||||
elif m.try_premirror(ud, self.d):
|
||||
elif m.try_premirror(u, ud, self.d):
|
||||
logger.debug(1, "Trying PREMIRRORS")
|
||||
mirrors = mirror_from_string(self.d.getVar('PREMIRRORS', True))
|
||||
localpath = try_mirrors(self.d, ud, mirrors, False)
|
||||
@@ -1396,16 +1381,16 @@ class Fetch(object):
|
||||
os.chdir(self.d.getVar("DL_DIR", True))
|
||||
|
||||
firsterr = None
|
||||
if not localpath and ((not os.path.exists(ud.donestamp)) or m.need_update(ud, self.d)):
|
||||
if not localpath and ((not os.path.exists(ud.donestamp)) or m.need_update(u, ud, self.d)):
|
||||
try:
|
||||
logger.debug(1, "Trying Upstream")
|
||||
m.download(ud, self.d)
|
||||
m.download(u, ud, self.d)
|
||||
if hasattr(m, "build_mirror_data"):
|
||||
m.build_mirror_data(ud, self.d)
|
||||
m.build_mirror_data(u, ud, self.d)
|
||||
localpath = ud.localpath
|
||||
# early checksum verify, so that if checksum mismatched,
|
||||
# fetcher still have chance to fetch from mirror
|
||||
update_stamp(ud, self.d)
|
||||
update_stamp(u, ud, self.d)
|
||||
|
||||
except bb.fetch2.NetworkAccess:
|
||||
raise
|
||||
@@ -1432,10 +1417,12 @@ class Fetch(object):
|
||||
logger.error(str(firsterr))
|
||||
raise FetchError("Unable to fetch URL from any source.", u)
|
||||
|
||||
update_stamp(ud, self.d)
|
||||
update_stamp(u, ud, self.d)
|
||||
|
||||
except BBFetchException as e:
|
||||
if isinstance(e, ChecksumError):
|
||||
if isinstance(e, NoChecksumError):
|
||||
logger.error("%s" % str(e))
|
||||
elif isinstance(e, ChecksumError):
|
||||
logger.error("Checksum failure fetching %s" % u)
|
||||
raise
|
||||
|
||||
@@ -1461,7 +1448,7 @@ class Fetch(object):
|
||||
if not ret:
|
||||
# Next try checking from the original uri, u
|
||||
try:
|
||||
ret = m.checkstatus(ud, self.d)
|
||||
ret = m.checkstatus(u, ud, self.d)
|
||||
except:
|
||||
# Finally, try checking uri, u, from MIRRORS
|
||||
mirrors = mirror_from_string(self.d.getVar('MIRRORS', True))
|
||||
@@ -1507,7 +1494,7 @@ class Fetch(object):
|
||||
ud = self.ud[url]
|
||||
ud.setup_localpath(self.d)
|
||||
|
||||
if not ud.localfile and ud.localpath is None:
|
||||
if not ud.localfile or self.localpath is None:
|
||||
continue
|
||||
|
||||
if ud.lockfile:
|
||||
@@ -1523,7 +1510,6 @@ class Fetch(object):
|
||||
from . import cvs
|
||||
from . import git
|
||||
from . import gitsm
|
||||
from . import gitannex
|
||||
from . import local
|
||||
from . import svn
|
||||
from . import wget
|
||||
@@ -1541,7 +1527,6 @@ methods.append(wget.Wget())
|
||||
methods.append(svn.Svn())
|
||||
methods.append(git.Git())
|
||||
methods.append(gitsm.GitSM())
|
||||
methods.append(gitannex.GitANNEX())
|
||||
methods.append(cvs.Cvs())
|
||||
methods.append(svk.Svk())
|
||||
methods.append(ssh.SSH())
|
||||
|
||||
@@ -34,7 +34,7 @@ from bb.fetch2 import runfetchcmd
|
||||
from bb.fetch2 import logger
|
||||
|
||||
class Bzr(FetchMethod):
|
||||
def supports(self, ud, d):
|
||||
def supports(self, url, ud, d):
|
||||
return ud.type in ['bzr']
|
||||
|
||||
def urldata_init(self, ud, d):
|
||||
@@ -48,7 +48,7 @@ class Bzr(FetchMethod):
|
||||
ud.setup_revisons(d)
|
||||
|
||||
if not ud.revision:
|
||||
ud.revision = self.latest_revision(ud, d)
|
||||
ud.revision = self.latest_revision(ud.url, ud, d)
|
||||
|
||||
ud.localfile = data.expand('bzr_%s_%s_%s.tar.gz' % (ud.host, ud.path.replace('/', '.'), ud.revision), d)
|
||||
|
||||
@@ -81,12 +81,12 @@ class Bzr(FetchMethod):
|
||||
|
||||
return bzrcmd
|
||||
|
||||
def download(self, ud, d):
|
||||
def download(self, loc, ud, d):
|
||||
"""Fetch url"""
|
||||
|
||||
if os.access(os.path.join(ud.pkgdir, os.path.basename(ud.pkgdir), '.bzr'), os.R_OK):
|
||||
bzrcmd = self._buildbzrcommand(ud, d, "update")
|
||||
logger.debug(1, "BZR Update %s", ud.url)
|
||||
logger.debug(1, "BZR Update %s", loc)
|
||||
bb.fetch2.check_network_access(d, bzrcmd, ud.url)
|
||||
os.chdir(os.path.join (ud.pkgdir, os.path.basename(ud.path)))
|
||||
runfetchcmd(bzrcmd, d)
|
||||
@@ -94,7 +94,7 @@ class Bzr(FetchMethod):
|
||||
bb.utils.remove(os.path.join(ud.pkgdir, os.path.basename(ud.pkgdir)), True)
|
||||
bzrcmd = self._buildbzrcommand(ud, d, "fetch")
|
||||
bb.fetch2.check_network_access(d, bzrcmd, ud.url)
|
||||
logger.debug(1, "BZR Checkout %s", ud.url)
|
||||
logger.debug(1, "BZR Checkout %s", loc)
|
||||
bb.utils.mkdirhier(ud.pkgdir)
|
||||
os.chdir(ud.pkgdir)
|
||||
logger.debug(1, "Running %s", bzrcmd)
|
||||
@@ -114,17 +114,17 @@ class Bzr(FetchMethod):
|
||||
def supports_srcrev(self):
|
||||
return True
|
||||
|
||||
def _revision_key(self, ud, d, name):
|
||||
def _revision_key(self, url, ud, d, name):
|
||||
"""
|
||||
Return a unique key for the url
|
||||
"""
|
||||
return "bzr:" + ud.pkgdir
|
||||
|
||||
def _latest_revision(self, ud, d, name):
|
||||
def _latest_revision(self, url, ud, d, name):
|
||||
"""
|
||||
Return the latest upstream revision number
|
||||
"""
|
||||
logger.debug(2, "BZR fetcher hitting network for %s", ud.url)
|
||||
logger.debug(2, "BZR fetcher hitting network for %s", url)
|
||||
|
||||
bb.fetch2.check_network_access(d, self._buildbzrcommand(ud, d, "revno"), ud.url)
|
||||
|
||||
@@ -132,12 +132,12 @@ class Bzr(FetchMethod):
|
||||
|
||||
return output.strip()
|
||||
|
||||
def sortable_revision(self, ud, d, name):
|
||||
def sortable_revision(self, url, ud, d, name):
|
||||
"""
|
||||
Return a sortable revision number which in our case is the revision number
|
||||
"""
|
||||
|
||||
return False, self._build_revision(ud, d)
|
||||
return False, self._build_revision(url, ud, d)
|
||||
|
||||
def _build_revision(self, ud, d):
|
||||
def _build_revision(self, url, ud, d):
|
||||
return ud.revision
|
||||
|
||||
@@ -36,7 +36,7 @@ class Cvs(FetchMethod):
|
||||
"""
|
||||
Class to fetch a module or modules from cvs repositories
|
||||
"""
|
||||
def supports(self, ud, d):
|
||||
def supports(self, url, ud, d):
|
||||
"""
|
||||
Check to see if a given url can be fetched with cvs.
|
||||
"""
|
||||
@@ -65,14 +65,14 @@ class Cvs(FetchMethod):
|
||||
|
||||
ud.localfile = bb.data.expand('%s_%s_%s_%s%s%s.tar.gz' % (ud.module.replace('/', '.'), ud.host, ud.tag, ud.date, norecurse, fullpath), d)
|
||||
|
||||
def need_update(self, ud, d):
|
||||
def need_update(self, url, ud, d):
|
||||
if (ud.date == "now"):
|
||||
return True
|
||||
if not os.path.exists(ud.localpath):
|
||||
return True
|
||||
return False
|
||||
|
||||
def download(self, ud, d):
|
||||
def download(self, loc, ud, d):
|
||||
|
||||
method = ud.parm.get('method', 'pserver')
|
||||
localdir = ud.parm.get('localdir', ud.module)
|
||||
@@ -124,13 +124,13 @@ class Cvs(FetchMethod):
|
||||
pkgdir = os.path.join(d.getVar('CVSDIR', True), pkg)
|
||||
moddir = os.path.join(pkgdir, localdir)
|
||||
if os.access(os.path.join(moddir, 'CVS'), os.R_OK):
|
||||
logger.info("Update " + ud.url)
|
||||
logger.info("Update " + loc)
|
||||
bb.fetch2.check_network_access(d, cvsupdatecmd, ud.url)
|
||||
# update sources there
|
||||
os.chdir(moddir)
|
||||
cmd = cvsupdatecmd
|
||||
else:
|
||||
logger.info("Fetch " + ud.url)
|
||||
logger.info("Fetch " + loc)
|
||||
# check out sources there
|
||||
bb.utils.mkdirhier(pkgdir)
|
||||
os.chdir(pkgdir)
|
||||
|
||||
@@ -44,11 +44,6 @@ Supported SRC_URI options are:
|
||||
checkout code and tracking branch requirements.
|
||||
The default is "0", set bareclone=1 if needed.
|
||||
|
||||
- nobranch
|
||||
Don't check the SHA validation for branch. set this option for the recipe
|
||||
referring to commit which is valid in tag instead of branch.
|
||||
The default is "0", set nobranch=1 if needed.
|
||||
|
||||
"""
|
||||
|
||||
#Copyright (C) 2005 Richard Purdie
|
||||
@@ -78,7 +73,7 @@ class Git(FetchMethod):
|
||||
def init(self, d):
|
||||
pass
|
||||
|
||||
def supports(self, ud, d):
|
||||
def supports(self, url, ud, d):
|
||||
"""
|
||||
Check to see if a given url can be fetched with git.
|
||||
"""
|
||||
@@ -106,14 +101,11 @@ class Git(FetchMethod):
|
||||
|
||||
ud.rebaseable = ud.parm.get("rebaseable","0") == "1"
|
||||
|
||||
ud.nobranch = ud.parm.get("nobranch","0") == "1"
|
||||
|
||||
# bareclone implies nocheckout
|
||||
ud.bareclone = ud.parm.get("bareclone","0") == "1"
|
||||
if ud.bareclone:
|
||||
ud.nocheckout = 1
|
||||
|
||||
ud.unresolvedrev = {}
|
||||
branches = ud.parm.get("branch", "master").split(',')
|
||||
if len(branches) != len(ud.names):
|
||||
raise bb.fetch2.ParameterError("The number of name and branch parameters is not balanced", ud.url)
|
||||
@@ -121,7 +113,6 @@ class Git(FetchMethod):
|
||||
for name in ud.names:
|
||||
branch = branches[ud.names.index(name)]
|
||||
ud.branches[name] = branch
|
||||
ud.unresolvedrev[name] = branch
|
||||
|
||||
ud.basecmd = data.getVar("FETCHCMD_git", d, True) or "git"
|
||||
|
||||
@@ -133,8 +124,8 @@ class Git(FetchMethod):
|
||||
# Ensure anything that doesn't look like a sha256 checksum/revision is translated into one
|
||||
if not ud.revisions[name] or len(ud.revisions[name]) != 40 or (False in [c in "abcdef0123456789" for c in ud.revisions[name]]):
|
||||
if ud.revisions[name]:
|
||||
ud.unresolvedrev[name] = ud.revisions[name]
|
||||
ud.revisions[name] = self.latest_revision(ud, d, name)
|
||||
ud.branches[name] = ud.revisions[name]
|
||||
ud.revisions[name] = self.latest_revision(ud.url, ud, d, name)
|
||||
|
||||
gitsrcname = '%s%s' % (ud.host.replace(':','.'), ud.path.replace('/', '.').replace('*', '.'))
|
||||
# for rebaseable git repo, it is necessary to keep mirror tar ball
|
||||
@@ -151,21 +142,21 @@ class Git(FetchMethod):
|
||||
|
||||
ud.localfile = ud.clonedir
|
||||
|
||||
def localpath(self, ud, d):
|
||||
def localpath(self, url, ud, d):
|
||||
return ud.clonedir
|
||||
|
||||
def need_update(self, ud, d):
|
||||
def need_update(self, u, ud, d):
|
||||
if not os.path.exists(ud.clonedir):
|
||||
return True
|
||||
os.chdir(ud.clonedir)
|
||||
for name in ud.names:
|
||||
if not self._contains_ref(ud, d, name):
|
||||
if not self._contains_ref(ud.revisions[name], d):
|
||||
return True
|
||||
if ud.write_tarballs and not os.path.exists(ud.fullmirror):
|
||||
return True
|
||||
return False
|
||||
|
||||
def try_premirror(self, ud, d):
|
||||
def try_premirror(self, u, ud, d):
|
||||
# If we don't do this, updating an existing checkout with only premirrors
|
||||
# is not possible
|
||||
if d.getVar("BB_FETCH_PREMIRRORONLY", True) is not None:
|
||||
@@ -174,7 +165,7 @@ class Git(FetchMethod):
|
||||
return False
|
||||
return True
|
||||
|
||||
def download(self, ud, d):
|
||||
def download(self, loc, ud, d):
|
||||
"""Fetch url"""
|
||||
|
||||
if ud.user:
|
||||
@@ -206,7 +197,7 @@ class Git(FetchMethod):
|
||||
# Update the checkout if needed
|
||||
needupdate = False
|
||||
for name in ud.names:
|
||||
if not self._contains_ref(ud, d, name):
|
||||
if not self._contains_ref(ud.revisions[name], d):
|
||||
needupdate = True
|
||||
if needupdate:
|
||||
try:
|
||||
@@ -222,12 +213,8 @@ class Git(FetchMethod):
|
||||
runfetchcmd("%s prune-packed" % ud.basecmd, d)
|
||||
runfetchcmd("%s pack-redundant --all | xargs -r rm" % ud.basecmd, d)
|
||||
ud.repochanged = True
|
||||
os.chdir(ud.clonedir)
|
||||
for name in ud.names:
|
||||
if not self._contains_ref(ud, d, name):
|
||||
raise bb.fetch2.FetchError("Unable to find revision %s in branch %s even from upstream" % (ud.revisions[name], ud.branches[name]))
|
||||
|
||||
def build_mirror_data(self, ud, d):
|
||||
def build_mirror_data(self, url, ud, d):
|
||||
# Generate a mirror tarball if needed
|
||||
if ud.write_tarballs and (ud.repochanged or not os.path.exists(ud.fullmirror)):
|
||||
# it's possible that this symlink points to read-only filesystem with PREMIRROR
|
||||
@@ -290,34 +277,25 @@ class Git(FetchMethod):
|
||||
|
||||
bb.utils.remove(ud.localpath, True)
|
||||
bb.utils.remove(ud.fullmirror)
|
||||
bb.utils.remove(ud.fullmirror + ".done")
|
||||
|
||||
def supports_srcrev(self):
|
||||
return True
|
||||
|
||||
def _contains_ref(self, ud, d, name):
|
||||
cmd = ""
|
||||
if ud.nobranch:
|
||||
cmd = "%s log --pretty=oneline -n 1 %s -- 2> /dev/null | wc -l" % (
|
||||
ud.basecmd, ud.revisions[name])
|
||||
else:
|
||||
cmd = "%s branch --contains %s --list %s 2> /dev/null | wc -l" % (
|
||||
ud.basecmd, ud.revisions[name], ud.branches[name])
|
||||
try:
|
||||
output = runfetchcmd(cmd, d, quiet=True)
|
||||
except bb.fetch2.FetchError:
|
||||
return False
|
||||
def _contains_ref(self, tag, d):
|
||||
basecmd = data.getVar("FETCHCMD_git", d, True) or "git"
|
||||
cmd = "%s log --pretty=oneline -n 1 %s -- 2> /dev/null | wc -l" % (basecmd, tag)
|
||||
output = runfetchcmd(cmd, d, quiet=True)
|
||||
if len(output.split()) > 1:
|
||||
raise bb.fetch2.FetchError("The command '%s' gave output with more then 1 line unexpectedly, output: '%s'" % (cmd, output))
|
||||
return output.split()[0] != "0"
|
||||
|
||||
def _revision_key(self, ud, d, name):
|
||||
def _revision_key(self, url, ud, d, name):
|
||||
"""
|
||||
Return a unique key for the url
|
||||
"""
|
||||
return "git:" + ud.host + ud.path.replace('/', '.') + ud.unresolvedrev[name]
|
||||
return "git:" + ud.host + ud.path.replace('/', '.') + ud.branches[name]
|
||||
|
||||
def _latest_revision(self, ud, d, name):
|
||||
def _latest_revision(self, url, ud, d, name):
|
||||
"""
|
||||
Compute the HEAD revision for the url
|
||||
"""
|
||||
@@ -326,20 +304,21 @@ class Git(FetchMethod):
|
||||
else:
|
||||
username = ""
|
||||
|
||||
cmd = "%s ls-remote %s://%s%s%s refs/heads/%s refs/tags/%s^{}" % \
|
||||
(ud.basecmd, ud.proto, username, ud.host, ud.path, ud.unresolvedrev[name], ud.unresolvedrev[name])
|
||||
basecmd = data.getVar("FETCHCMD_git", d, True) or "git"
|
||||
cmd = "%s ls-remote %s://%s%s%s %s" % \
|
||||
(basecmd, ud.proto, username, ud.host, ud.path, ud.branches[name])
|
||||
if ud.proto.lower() != 'file':
|
||||
bb.fetch2.check_network_access(d, cmd)
|
||||
output = runfetchcmd(cmd, d, True)
|
||||
if not output:
|
||||
raise bb.fetch2.FetchError("The command %s gave empty output unexpectedly" % cmd, ud.url)
|
||||
raise bb.fetch2.FetchError("The command %s gave empty output unexpectedly" % cmd, url)
|
||||
return output.split()[0]
|
||||
|
||||
def _build_revision(self, ud, d, name):
|
||||
def _build_revision(self, url, ud, d, name):
|
||||
return ud.revisions[name]
|
||||
|
||||
def checkstatus(self, ud, d):
|
||||
fetchcmd = "%s ls-remote %s" % (ud.basecmd, ud.url)
|
||||
def checkstatus(self, uri, ud, d):
|
||||
fetchcmd = "%s ls-remote %s" % (ud.basecmd, uri)
|
||||
try:
|
||||
runfetchcmd(fetchcmd, d, quiet=True)
|
||||
return True
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
# ex:ts=4:sw=4:sts=4:et
|
||||
# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
|
||||
"""
|
||||
BitBake 'Fetch' git annex implementation
|
||||
"""
|
||||
|
||||
# Copyright (C) 2014 Otavio Salvador
|
||||
# Copyright (C) 2014 O.S. Systems Software LTDA.
|
||||
#
|
||||
# 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 data
|
||||
from bb.fetch2.git import Git
|
||||
from bb.fetch2 import runfetchcmd
|
||||
from bb.fetch2 import logger
|
||||
|
||||
class GitANNEX(Git):
|
||||
def supports(self, ud, d):
|
||||
"""
|
||||
Check to see if a given url can be fetched with git.
|
||||
"""
|
||||
return ud.type in ['gitannex']
|
||||
|
||||
def uses_annex(self, ud, d):
|
||||
for name in ud.names:
|
||||
try:
|
||||
runfetchcmd("%s rev-list git-annex" % (ud.basecmd), d, quiet=True)
|
||||
return True
|
||||
except bb.fetch.FetchError:
|
||||
pass
|
||||
|
||||
return False
|
||||
|
||||
def update_annex(self, ud, d):
|
||||
try:
|
||||
runfetchcmd("%s annex get --all" % (ud.basecmd), d, quiet=True)
|
||||
except bb.fetch.FetchError:
|
||||
return False
|
||||
runfetchcmd("chmod u+w -R %s/annex" % (ud.clonedir), d, quiet=True)
|
||||
|
||||
return True
|
||||
|
||||
def download(self, ud, d):
|
||||
Git.download(self, ud, d)
|
||||
|
||||
os.chdir(ud.clonedir)
|
||||
annex = self.uses_annex(ud, d)
|
||||
if annex:
|
||||
self.update_annex(ud, d)
|
||||
|
||||
def unpack(self, ud, destdir, d):
|
||||
Git.unpack(self, ud, destdir, d)
|
||||
|
||||
os.chdir(ud.destdir)
|
||||
try:
|
||||
runfetchcmd("%s annex sync" % (ud.basecmd), d)
|
||||
except bb.fetch.FetchError:
|
||||
pass
|
||||
|
||||
annex = self.uses_annex(ud, d)
|
||||
if annex:
|
||||
runfetchcmd("%s annex get" % (ud.basecmd), d)
|
||||
runfetchcmd("chmod u+w -R %s/.git/annex" % (ud.destdir), d, quiet=True)
|
||||
@@ -27,7 +27,7 @@ from bb.fetch2 import runfetchcmd
|
||||
from bb.fetch2 import logger
|
||||
|
||||
class GitSM(Git):
|
||||
def supports(self, ud, d):
|
||||
def supports(self, url, ud, d):
|
||||
"""
|
||||
Check to see if a given url can be fetched with git.
|
||||
"""
|
||||
@@ -42,7 +42,7 @@ class GitSM(Git):
|
||||
pass
|
||||
return False
|
||||
|
||||
def update_submodules(self, ud, d):
|
||||
def update_submodules(self, u, ud, d):
|
||||
# We have to convert bare -> full repo, do the submodule bit, then convert back
|
||||
tmpclonedir = ud.clonedir + ".tmp"
|
||||
gitdir = tmpclonedir + os.sep + ".git"
|
||||
@@ -51,20 +51,20 @@ class GitSM(Git):
|
||||
os.rename(ud.clonedir, gitdir)
|
||||
runfetchcmd("sed " + gitdir + "/config -i -e 's/bare.*=.*true/bare = false/'", d)
|
||||
os.chdir(tmpclonedir)
|
||||
runfetchcmd(ud.basecmd + " reset --hard", d)
|
||||
runfetchcmd(ud.basecmd + " submodule init", d)
|
||||
runfetchcmd(ud.basecmd + " submodule update", d)
|
||||
runfetchcmd("git reset --hard", d)
|
||||
runfetchcmd("git submodule init", d)
|
||||
runfetchcmd("git submodule update", d)
|
||||
runfetchcmd("sed " + gitdir + "/config -i -e 's/bare.*=.*false/bare = true/'", d)
|
||||
os.rename(gitdir, ud.clonedir,)
|
||||
bb.utils.remove(tmpclonedir, True)
|
||||
|
||||
def download(self, ud, d):
|
||||
Git.download(self, ud, d)
|
||||
def download(self, loc, ud, d):
|
||||
Git.download(self, loc, ud, d)
|
||||
|
||||
os.chdir(ud.clonedir)
|
||||
submodules = self.uses_submodules(ud, d)
|
||||
if submodules:
|
||||
self.update_submodules(ud, d)
|
||||
self.update_submodules(loc, ud, d)
|
||||
|
||||
def unpack(self, ud, destdir, d):
|
||||
Git.unpack(self, ud, destdir, d)
|
||||
@@ -73,6 +73,6 @@ class GitSM(Git):
|
||||
submodules = self.uses_submodules(ud, d)
|
||||
if submodules:
|
||||
runfetchcmd("cp -r " + ud.clonedir + "/modules " + ud.destdir + "/.git/", d)
|
||||
runfetchcmd(ud.basecmd + " submodule init", d)
|
||||
runfetchcmd(ud.basecmd + " submodule update", d)
|
||||
runfetchcmd("git submodule init", d)
|
||||
runfetchcmd("git submodule update", d)
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ from bb.fetch2 import logger
|
||||
|
||||
class Hg(FetchMethod):
|
||||
"""Class to fetch from mercurial repositories"""
|
||||
def supports(self, ud, d):
|
||||
def supports(self, url, ud, d):
|
||||
"""
|
||||
Check to see if a given url can be fetched with mercurial.
|
||||
"""
|
||||
@@ -62,11 +62,11 @@ class Hg(FetchMethod):
|
||||
if 'rev' in ud.parm:
|
||||
ud.revision = ud.parm['rev']
|
||||
elif not ud.revision:
|
||||
ud.revision = self.latest_revision(ud, d)
|
||||
ud.revision = self.latest_revision(ud.url, ud, d)
|
||||
|
||||
ud.localfile = data.expand('%s_%s_%s_%s.tar.gz' % (ud.module.replace('/', '.'), ud.host, ud.path.replace('/', '.'), ud.revision), d)
|
||||
|
||||
def need_update(self, ud, d):
|
||||
def need_update(self, url, ud, d):
|
||||
revTag = ud.parm.get('rev', 'tip')
|
||||
if revTag == "tip":
|
||||
return True
|
||||
@@ -92,10 +92,7 @@ class Hg(FetchMethod):
|
||||
if not ud.user:
|
||||
hgroot = host + ud.path
|
||||
else:
|
||||
if ud.pswd:
|
||||
hgroot = ud.user + ":" + ud.pswd + "@" + host + ud.path
|
||||
else:
|
||||
hgroot = ud.user + "@" + host + ud.path
|
||||
hgroot = ud.user + "@" + host + ud.path
|
||||
|
||||
if command == "info":
|
||||
return "%s identify -i %s://%s/%s" % (basecmd, proto, hgroot, ud.module)
|
||||
@@ -115,10 +112,7 @@ class Hg(FetchMethod):
|
||||
# do not pass options list; limiting pull to rev causes the local
|
||||
# repo not to contain it and immediately following "update" command
|
||||
# will crash
|
||||
if ud.user and ud.pswd:
|
||||
cmd = "%s --config auth.default.prefix=* --config auth.default.username=%s --config auth.default.password=%s --config \"auth.default.schemes=%s\" pull" % (basecmd, ud.user, ud.pswd, proto)
|
||||
else:
|
||||
cmd = "%s pull" % (basecmd)
|
||||
cmd = "%s pull" % (basecmd)
|
||||
elif command == "update":
|
||||
cmd = "%s update -C %s" % (basecmd, " ".join(options))
|
||||
else:
|
||||
@@ -126,14 +120,14 @@ class Hg(FetchMethod):
|
||||
|
||||
return cmd
|
||||
|
||||
def download(self, ud, d):
|
||||
def download(self, loc, ud, d):
|
||||
"""Fetch url"""
|
||||
|
||||
logger.debug(2, "Fetch: checking for module directory '" + ud.moddir + "'")
|
||||
|
||||
if os.access(os.path.join(ud.moddir, '.hg'), os.R_OK):
|
||||
updatecmd = self._buildhgcommand(ud, d, "pull")
|
||||
logger.info("Update " + ud.url)
|
||||
logger.info("Update " + loc)
|
||||
# update sources there
|
||||
os.chdir(ud.moddir)
|
||||
logger.debug(1, "Running %s", updatecmd)
|
||||
@@ -142,7 +136,7 @@ class Hg(FetchMethod):
|
||||
|
||||
else:
|
||||
fetchcmd = self._buildhgcommand(ud, d, "fetch")
|
||||
logger.info("Fetch " + ud.url)
|
||||
logger.info("Fetch " + loc)
|
||||
# check out sources there
|
||||
bb.utils.mkdirhier(ud.pkgdir)
|
||||
os.chdir(ud.pkgdir)
|
||||
@@ -169,7 +163,7 @@ class Hg(FetchMethod):
|
||||
def supports_srcrev(self):
|
||||
return True
|
||||
|
||||
def _latest_revision(self, ud, d, name):
|
||||
def _latest_revision(self, url, ud, d, name):
|
||||
"""
|
||||
Compute tip revision for the url
|
||||
"""
|
||||
@@ -177,10 +171,10 @@ class Hg(FetchMethod):
|
||||
output = runfetchcmd(self._buildhgcommand(ud, d, "info"), d)
|
||||
return output.strip()
|
||||
|
||||
def _build_revision(self, ud, d, name):
|
||||
def _build_revision(self, url, ud, d, name):
|
||||
return ud.revision
|
||||
|
||||
def _revision_key(self, ud, d, name):
|
||||
def _revision_key(self, url, ud, d, name):
|
||||
"""
|
||||
Return a unique key for the url
|
||||
"""
|
||||
|
||||
@@ -34,7 +34,7 @@ from bb.fetch2 import FetchMethod, FetchError
|
||||
from bb.fetch2 import logger
|
||||
|
||||
class Local(FetchMethod):
|
||||
def supports(self, urldata, d):
|
||||
def supports(self, url, urldata, d):
|
||||
"""
|
||||
Check to see if a given url represents a local fetch.
|
||||
"""
|
||||
@@ -47,7 +47,7 @@ class Local(FetchMethod):
|
||||
ud.basepath = ud.decodedurl
|
||||
return
|
||||
|
||||
def localpath(self, urldata, d):
|
||||
def localpath(self, url, urldata, d):
|
||||
"""
|
||||
Return the local filename of a given url assuming a successful fetch.
|
||||
"""
|
||||
@@ -75,14 +75,14 @@ class Local(FetchMethod):
|
||||
return dldirfile
|
||||
return newpath
|
||||
|
||||
def need_update(self, ud, d):
|
||||
if ud.url.find("*") != -1:
|
||||
def need_update(self, url, ud, d):
|
||||
if url.find("*") != -1:
|
||||
return False
|
||||
if os.path.exists(ud.localpath):
|
||||
return False
|
||||
return True
|
||||
|
||||
def download(self, urldata, d):
|
||||
def download(self, url, urldata, d):
|
||||
"""Fetch urls (no-op for Local method)"""
|
||||
# no need to fetch local files, we'll deal with them in place.
|
||||
if self.supports_checksum(urldata) and not os.path.exists(urldata.localpath):
|
||||
@@ -95,17 +95,17 @@ class Local(FetchMethod):
|
||||
locations.append(filesdir)
|
||||
locations.append(d.getVar("DL_DIR", True))
|
||||
|
||||
msg = "Unable to find file " + urldata.url + " anywhere. The paths that were searched were:\n " + "\n ".join(locations)
|
||||
msg = "Unable to find file " + url + " anywhere. The paths that were searched were:\n " + "\n ".join(locations)
|
||||
raise FetchError(msg)
|
||||
|
||||
return True
|
||||
|
||||
def checkstatus(self, urldata, d):
|
||||
def checkstatus(self, url, urldata, d):
|
||||
"""
|
||||
Check the status of the url
|
||||
"""
|
||||
if urldata.localpath.find("*") != -1:
|
||||
logger.info("URL %s looks like a glob and was therefore not checked.", urldata.url)
|
||||
logger.info("URL %s looks like a glob and was therefore not checked.", url)
|
||||
return True
|
||||
if os.path.exists(urldata.localpath):
|
||||
return True
|
||||
|
||||
@@ -20,7 +20,7 @@ class Osc(FetchMethod):
|
||||
"""Class to fetch a module or modules from Opensuse build server
|
||||
repositories."""
|
||||
|
||||
def supports(self, ud, d):
|
||||
def supports(self, url, ud, d):
|
||||
"""
|
||||
Check to see if a given url can be fetched with osc.
|
||||
"""
|
||||
@@ -77,7 +77,7 @@ class Osc(FetchMethod):
|
||||
|
||||
return osccmd
|
||||
|
||||
def download(self, ud, d):
|
||||
def download(self, loc, ud, d):
|
||||
"""
|
||||
Fetch url
|
||||
"""
|
||||
@@ -86,7 +86,7 @@ class Osc(FetchMethod):
|
||||
|
||||
if os.access(os.path.join(data.expand('${OSCDIR}', d), ud.path, ud.module), os.R_OK):
|
||||
oscupdatecmd = self._buildosccommand(ud, d, "update")
|
||||
logger.info("Update "+ ud.url)
|
||||
logger.info("Update "+ loc)
|
||||
# update sources there
|
||||
os.chdir(ud.moddir)
|
||||
logger.debug(1, "Running %s", oscupdatecmd)
|
||||
@@ -94,7 +94,7 @@ class Osc(FetchMethod):
|
||||
runfetchcmd(oscupdatecmd, d)
|
||||
else:
|
||||
oscfetchcmd = self._buildosccommand(ud, d, "fetch")
|
||||
logger.info("Fetch " + ud.url)
|
||||
logger.info("Fetch " + loc)
|
||||
# check out sources there
|
||||
bb.utils.mkdirhier(ud.pkgdir)
|
||||
os.chdir(ud.pkgdir)
|
||||
|
||||
@@ -37,7 +37,7 @@ from bb.fetch2 import logger
|
||||
from bb.fetch2 import runfetchcmd
|
||||
|
||||
class Perforce(FetchMethod):
|
||||
def supports(self, ud, d):
|
||||
def supports(self, url, ud, d):
|
||||
return ud.type in ['p4']
|
||||
|
||||
def doparse(url, d):
|
||||
@@ -112,7 +112,7 @@ class Perforce(FetchMethod):
|
||||
base = path
|
||||
which = path.find('/...')
|
||||
if which != -1:
|
||||
base = path[:which-1]
|
||||
base = path[:which]
|
||||
|
||||
base = self._strip_leading_slashes(base)
|
||||
|
||||
@@ -120,12 +120,12 @@ class Perforce(FetchMethod):
|
||||
|
||||
ud.localfile = data.expand('%s+%s+%s.tar.gz' % (host, base.replace('/', '.'), cset), d)
|
||||
|
||||
def download(self, ud, d):
|
||||
def download(self, loc, ud, d):
|
||||
"""
|
||||
Fetch urls
|
||||
"""
|
||||
|
||||
(host, depot, user, pswd, parm) = Perforce.doparse(ud.url, d)
|
||||
(host, depot, user, pswd, parm) = Perforce.doparse(loc, d)
|
||||
|
||||
if depot.find('/...') != -1:
|
||||
path = depot[:depot.find('/...')]
|
||||
@@ -158,7 +158,7 @@ class Perforce(FetchMethod):
|
||||
tmpfile, errors = bb.process.run(data.getVar('MKTEMPDIRCMD', localdata, True) or "false")
|
||||
tmpfile = tmpfile.strip()
|
||||
if not tmpfile:
|
||||
raise FetchError("Fetch: unable to create temporary directory.. make sure 'mktemp' is in the PATH.", ud.url)
|
||||
raise FetchError("Fetch: unable to create temporary directory.. make sure 'mktemp' is in the PATH.", loc)
|
||||
|
||||
if "label" in parm:
|
||||
depot = "%s@%s" % (depot, parm["label"])
|
||||
@@ -167,13 +167,13 @@ class Perforce(FetchMethod):
|
||||
depot = "%s@%s" % (depot, cset)
|
||||
|
||||
os.chdir(tmpfile)
|
||||
logger.info("Fetch " + ud.url)
|
||||
logger.info("Fetch " + loc)
|
||||
logger.info("%s%s files %s", p4cmd, p4opt, depot)
|
||||
p4file, errors = bb.process.run("%s%s files %s" % (p4cmd, p4opt, depot))
|
||||
p4file = [f.rstrip() for f in p4file.splitlines()]
|
||||
|
||||
if not p4file:
|
||||
raise FetchError("Fetch: unable to get the P4 files from %s" % depot, ud.url)
|
||||
raise FetchError("Fetch: unable to get the P4 files from %s" % depot, loc)
|
||||
|
||||
count = 0
|
||||
|
||||
@@ -191,7 +191,7 @@ class Perforce(FetchMethod):
|
||||
|
||||
if count == 0:
|
||||
logger.error()
|
||||
raise FetchError("Fetch: No files gathered from the P4 fetch", ud.url)
|
||||
raise FetchError("Fetch: No files gathered from the P4 fetch", loc)
|
||||
|
||||
runfetchcmd("tar -czf %s %s" % (ud.localpath, module), d, cleanup = [ud.localpath])
|
||||
# cleanup
|
||||
|
||||
@@ -31,7 +31,7 @@ from bb.fetch2 import runfetchcmd
|
||||
|
||||
class Repo(FetchMethod):
|
||||
"""Class to fetch a module or modules from repo (git) repositories"""
|
||||
def supports(self, ud, d):
|
||||
def supports(self, url, ud, d):
|
||||
"""
|
||||
Check to see if a given url can be fetched with repo.
|
||||
"""
|
||||
@@ -53,7 +53,7 @@ class Repo(FetchMethod):
|
||||
|
||||
ud.localfile = data.expand("repo_%s%s_%s_%s.tar.gz" % (ud.host, ud.path.replace("/", "."), ud.manifest, ud.branch), d)
|
||||
|
||||
def download(self, ud, d):
|
||||
def download(self, loc, ud, d):
|
||||
"""Fetch url"""
|
||||
|
||||
if os.access(os.path.join(data.getVar("DL_DIR", d, True), ud.localfile), os.R_OK):
|
||||
@@ -91,8 +91,8 @@ class Repo(FetchMethod):
|
||||
def supports_srcrev(self):
|
||||
return False
|
||||
|
||||
def _build_revision(self, ud, d):
|
||||
def _build_revision(self, url, ud, d):
|
||||
return ud.manifest
|
||||
|
||||
def _want_sortable_revision(self, ud, d):
|
||||
def _want_sortable_revision(self, url, ud, d):
|
||||
return False
|
||||
|
||||
@@ -72,7 +72,7 @@ from bb.fetch2 import runfetchcmd
|
||||
class SFTP(FetchMethod):
|
||||
"""Class to fetch urls via 'sftp'"""
|
||||
|
||||
def supports(self, ud, d):
|
||||
def supports(self, url, ud, d):
|
||||
"""
|
||||
Check to see if a given url can be fetched with sftp.
|
||||
"""
|
||||
@@ -95,10 +95,10 @@ class SFTP(FetchMethod):
|
||||
|
||||
ud.localfile = data.expand(urllib.unquote(ud.basename), d)
|
||||
|
||||
def download(self, ud, d):
|
||||
def download(self, uri, ud, d):
|
||||
"""Fetch urls"""
|
||||
|
||||
urlo = URI(ud.url)
|
||||
urlo = URI(uri)
|
||||
basecmd = 'sftp -oPasswordAuthentication=no'
|
||||
port = ''
|
||||
if urlo.port:
|
||||
@@ -124,6 +124,6 @@ class SFTP(FetchMethod):
|
||||
cmd = '%s %s %s %s' % (basecmd, port, commands.mkarg(remote),
|
||||
commands.mkarg(lpath))
|
||||
|
||||
bb.fetch2.check_network_access(d, cmd, ud.url)
|
||||
bb.fetch2.check_network_access(d, cmd, uri)
|
||||
runfetchcmd(cmd, d)
|
||||
return True
|
||||
|
||||
@@ -72,8 +72,8 @@ __pattern__ = re.compile(r'''
|
||||
class SSH(FetchMethod):
|
||||
'''Class to fetch a module or modules via Secure Shell'''
|
||||
|
||||
def supports(self, urldata, d):
|
||||
return __pattern__.match(urldata.url) != None
|
||||
def supports(self, url, urldata, d):
|
||||
return __pattern__.match(url) != None
|
||||
|
||||
def supports_checksum(self, urldata):
|
||||
return False
|
||||
@@ -89,10 +89,10 @@ class SSH(FetchMethod):
|
||||
host = m.group('host')
|
||||
urldata.localpath = os.path.join(d.getVar('DL_DIR', True), os.path.basename(path))
|
||||
|
||||
def download(self, urldata, d):
|
||||
def download(self, url, urldata, d):
|
||||
dldir = d.getVar('DL_DIR', True)
|
||||
|
||||
m = __pattern__.match(urldata.url)
|
||||
m = __pattern__.match(url)
|
||||
path = m.group('path')
|
||||
host = m.group('host')
|
||||
port = m.group('port')
|
||||
|
||||
@@ -37,7 +37,7 @@ from bb.fetch2 import runfetchcmd
|
||||
|
||||
class Svk(FetchMethod):
|
||||
"""Class to fetch a module or modules from svk repositories"""
|
||||
def supports(self, ud, d):
|
||||
def supports(self, url, ud, d):
|
||||
"""
|
||||
Check to see if a given url can be fetched with svk.
|
||||
"""
|
||||
@@ -54,14 +54,14 @@ class Svk(FetchMethod):
|
||||
|
||||
ud.localfile = data.expand('%s_%s_%s_%s_%s.tar.gz' % (ud.module.replace('/', '.'), ud.host, ud.path.replace('/', '.'), ud.revision, ud.date), d)
|
||||
|
||||
def need_update(self, ud, d):
|
||||
def need_update(self, url, ud, d):
|
||||
if ud.date == "now":
|
||||
return True
|
||||
if not os.path.exists(ud.localpath):
|
||||
return True
|
||||
return False
|
||||
|
||||
def download(self, ud, d):
|
||||
def download(self, loc, ud, d):
|
||||
"""Fetch urls"""
|
||||
|
||||
svkroot = ud.host + ud.path
|
||||
@@ -81,11 +81,11 @@ class Svk(FetchMethod):
|
||||
tmpfile = tmpfile.strip()
|
||||
if not tmpfile:
|
||||
logger.error()
|
||||
raise FetchError("Fetch: unable to create temporary directory.. make sure 'mktemp' is in the PATH.", ud.url)
|
||||
raise FetchError("Fetch: unable to create temporary directory.. make sure 'mktemp' is in the PATH.", loc)
|
||||
|
||||
# check out sources there
|
||||
os.chdir(tmpfile)
|
||||
logger.info("Fetch " + ud.url)
|
||||
logger.info("Fetch " + loc)
|
||||
logger.debug(1, "Running %s", svkcmd)
|
||||
runfetchcmd(svkcmd, d, cleanup = [tmpfile])
|
||||
|
||||
|
||||
@@ -27,7 +27,6 @@ import os
|
||||
import sys
|
||||
import logging
|
||||
import bb
|
||||
import re
|
||||
from bb import data
|
||||
from bb.fetch2 import FetchMethod
|
||||
from bb.fetch2 import FetchError
|
||||
@@ -37,7 +36,7 @@ from bb.fetch2 import logger
|
||||
|
||||
class Svn(FetchMethod):
|
||||
"""Class to fetch a module or modules from svn repositories"""
|
||||
def supports(self, ud, d):
|
||||
def supports(self, url, ud, d):
|
||||
"""
|
||||
Check to see if a given url can be fetched with svn.
|
||||
"""
|
||||
@@ -92,8 +91,6 @@ class Svn(FetchMethod):
|
||||
|
||||
if command == "info":
|
||||
svncmd = "%s info %s %s://%s/%s/" % (ud.basecmd, " ".join(options), proto, svnroot, ud.module)
|
||||
elif command == "log1":
|
||||
svncmd = "%s log --limit 1 %s %s://%s/%s/" % (ud.basecmd, " ".join(options), proto, svnroot, ud.module)
|
||||
else:
|
||||
suffix = ""
|
||||
if ud.revision:
|
||||
@@ -112,14 +109,14 @@ class Svn(FetchMethod):
|
||||
|
||||
return svncmd
|
||||
|
||||
def download(self, ud, d):
|
||||
def download(self, loc, ud, d):
|
||||
"""Fetch url"""
|
||||
|
||||
logger.debug(2, "Fetch: checking for module directory '" + ud.moddir + "'")
|
||||
|
||||
if os.access(os.path.join(ud.moddir, '.svn'), os.R_OK):
|
||||
svnupdatecmd = self._buildsvncommand(ud, d, "update")
|
||||
logger.info("Update " + ud.url)
|
||||
logger.info("Update " + loc)
|
||||
# update sources there
|
||||
os.chdir(ud.moddir)
|
||||
# We need to attempt to run svn upgrade first in case its an older working format
|
||||
@@ -132,7 +129,7 @@ class Svn(FetchMethod):
|
||||
runfetchcmd(svnupdatecmd, d)
|
||||
else:
|
||||
svnfetchcmd = self._buildsvncommand(ud, d, "fetch")
|
||||
logger.info("Fetch " + ud.url)
|
||||
logger.info("Fetch " + loc)
|
||||
# check out sources there
|
||||
bb.utils.mkdirhier(ud.pkgdir)
|
||||
os.chdir(ud.pkgdir)
|
||||
@@ -160,32 +157,33 @@ class Svn(FetchMethod):
|
||||
def supports_srcrev(self):
|
||||
return True
|
||||
|
||||
def _revision_key(self, ud, d, name):
|
||||
def _revision_key(self, url, ud, d, name):
|
||||
"""
|
||||
Return a unique key for the url
|
||||
"""
|
||||
return "svn:" + ud.moddir
|
||||
|
||||
def _latest_revision(self, ud, d, name):
|
||||
def _latest_revision(self, url, ud, d, name):
|
||||
"""
|
||||
Return the latest upstream revision number
|
||||
"""
|
||||
bb.fetch2.check_network_access(d, self._buildsvncommand(ud, d, "log1"))
|
||||
bb.fetch2.check_network_access(d, self._buildsvncommand(ud, d, "info"))
|
||||
|
||||
output = runfetchcmd("LANG=C LC_ALL=C " + self._buildsvncommand(ud, d, "log1"), d, True)
|
||||
output = runfetchcmd("LANG=C LC_ALL=C " + self._buildsvncommand(ud, d, "info"), d, True)
|
||||
|
||||
# skip the first line, as per output of svn log
|
||||
# then we expect the revision on the 2nd line
|
||||
revision = re.search('^r([0-9]*)', output.splitlines()[1]).group(1)
|
||||
revision = None
|
||||
for line in output.splitlines():
|
||||
if "Last Changed Rev" in line:
|
||||
revision = line.split(":")[1].strip()
|
||||
|
||||
return revision
|
||||
|
||||
def sortable_revision(self, ud, d, name):
|
||||
def sortable_revision(self, url, ud, d, name):
|
||||
"""
|
||||
Return a sortable revision number which in our case is the revision number
|
||||
"""
|
||||
|
||||
return False, self._build_revision(ud, d)
|
||||
return False, self._build_revision(url, ud, d)
|
||||
|
||||
def _build_revision(self, ud, d):
|
||||
def _build_revision(self, url, ud, d):
|
||||
return ud.revision
|
||||
|
||||
@@ -37,7 +37,7 @@ from bb.fetch2 import runfetchcmd
|
||||
|
||||
class Wget(FetchMethod):
|
||||
"""Class to fetch urls via 'wget'"""
|
||||
def supports(self, ud, d):
|
||||
def supports(self, url, ud, d):
|
||||
"""
|
||||
Check to see if a given url can be fetched with wget.
|
||||
"""
|
||||
@@ -58,7 +58,7 @@ class Wget(FetchMethod):
|
||||
|
||||
ud.localfile = data.expand(urllib.unquote(ud.basename), d)
|
||||
|
||||
def download(self, ud, d, checkonly = False):
|
||||
def download(self, uri, ud, d, checkonly = False):
|
||||
"""Fetch urls"""
|
||||
|
||||
basecmd = d.getVar("FETCHCMD_wget", True) or "/usr/bin/env wget -t 2 -T 30 -nv --passive-ftp --no-check-certificate"
|
||||
@@ -76,7 +76,7 @@ class Wget(FetchMethod):
|
||||
else:
|
||||
fetchcmd = d.getVar("FETCHCOMMAND_wget", True) or d.expand(basecmd + " -P ${DL_DIR} '${URI}'")
|
||||
|
||||
uri = ud.url.split(";")[0]
|
||||
uri = uri.split(";")[0]
|
||||
|
||||
fetchcmd = fetchcmd.replace("${URI}", uri.split(";")[0])
|
||||
fetchcmd = fetchcmd.replace("${FILE}", ud.basename)
|
||||
@@ -91,11 +91,7 @@ class Wget(FetchMethod):
|
||||
if not os.path.exists(ud.localpath) and not checkonly:
|
||||
raise FetchError("The fetch command returned success for url %s but %s doesn't exist?!" % (uri, ud.localpath), uri)
|
||||
|
||||
if not checkonly and os.path.getsize(ud.localpath) == 0:
|
||||
os.remove(ud.localpath)
|
||||
raise FetchError("The fetch of %s resulted in a zero size file?! Deleting and failing since this isn't right." % (uri), uri)
|
||||
|
||||
return True
|
||||
|
||||
def checkstatus(self, ud, d):
|
||||
return self.download(ud, d, True)
|
||||
def checkstatus(self, uri, ud, d):
|
||||
return self.download(uri, ud, d, True)
|
||||
|
||||
@@ -243,7 +243,7 @@ class diskMonitor:
|
||||
# zero, this is a feature of the fs, we disable the inode
|
||||
# checking for such a fs.
|
||||
if st.f_files == 0:
|
||||
logger.info("Inode check for %s is unavaliable, will remove it from disk monitor" % path)
|
||||
logger.warn("Inode check for %s is unavaliable, will remove it from disk monitor" % path)
|
||||
self.devDict[k][2] = None
|
||||
continue
|
||||
# Always show warning, the self.checked would always be False if the action is WARN
|
||||
|
||||
@@ -73,17 +73,9 @@ def update_mtime(f):
|
||||
def mark_dependency(d, f):
|
||||
if f.startswith('./'):
|
||||
f = "%s/%s" % (os.getcwd(), f[2:])
|
||||
deps = (d.getVar('__depends') or [])
|
||||
s = (f, cached_mtime_noerror(f))
|
||||
if s not in deps:
|
||||
deps.append(s)
|
||||
d.setVar('__depends', deps)
|
||||
deps = (d.getVar('__depends') or []) + [(f, cached_mtime(f))]
|
||||
d.setVar('__depends', deps)
|
||||
|
||||
def check_dependency(d, f):
|
||||
s = (f, cached_mtime_noerror(f))
|
||||
deps = (d.getVar('__depends') or [])
|
||||
return s in deps
|
||||
|
||||
def supports(fn, data):
|
||||
"""Returns true if we have a handler for this file, false otherwise"""
|
||||
for h in handlers:
|
||||
@@ -110,14 +102,11 @@ def init_parser(d):
|
||||
def resolve_file(fn, d):
|
||||
if not os.path.isabs(fn):
|
||||
bbpath = d.getVar("BBPATH", True)
|
||||
newfn, attempts = bb.utils.which(bbpath, fn, history=True)
|
||||
for af in attempts:
|
||||
mark_dependency(d, af)
|
||||
newfn = bb.utils.which(bbpath, fn)
|
||||
if not newfn:
|
||||
raise IOError("file %s not found in %s" % (fn, bbpath))
|
||||
fn = newfn
|
||||
|
||||
mark_dependency(d, fn)
|
||||
if not os.path.isfile(fn):
|
||||
raise IOError("file %s not found" % fn)
|
||||
|
||||
@@ -127,7 +116,7 @@ def resolve_file(fn, d):
|
||||
# Used by OpenEmbedded metadata
|
||||
__pkgsplit_cache__={}
|
||||
def vars_from_file(mypkg, d):
|
||||
if not mypkg or not mypkg.endswith((".bb", ".bbappend")):
|
||||
if not mypkg:
|
||||
return (None, None, None)
|
||||
if mypkg in __pkgsplit_cache__:
|
||||
return __pkgsplit_cache__[mypkg]
|
||||
|
||||
@@ -235,15 +235,29 @@ class AddTaskNode(AstNode):
|
||||
self.after = after
|
||||
|
||||
def eval(self, data):
|
||||
bb.build.addtask(self.func, self.before, self.after, data)
|
||||
var = self.func
|
||||
if self.func[:3] != "do_":
|
||||
var = "do_" + self.func
|
||||
|
||||
class DelTaskNode(AstNode):
|
||||
def __init__(self, filename, lineno, func):
|
||||
AstNode.__init__(self, filename, lineno)
|
||||
self.func = func
|
||||
data.setVarFlag(var, "task", 1)
|
||||
bbtasks = data.getVar('__BBTASKS') or []
|
||||
if not var in bbtasks:
|
||||
bbtasks.append(var)
|
||||
data.setVar('__BBTASKS', bbtasks)
|
||||
|
||||
def eval(self, data):
|
||||
bb.build.deltask(self.func, data)
|
||||
existing = data.getVarFlag(var, "deps") or []
|
||||
if self.after is not None:
|
||||
# set up deps for function
|
||||
for entry in self.after.split():
|
||||
if entry not in existing:
|
||||
existing.append(entry)
|
||||
data.setVarFlag(var, "deps", existing)
|
||||
if self.before is not None:
|
||||
# set up things that depend on this func
|
||||
for entry in self.before.split():
|
||||
existing = data.getVarFlag(entry, "deps") or []
|
||||
if var not in existing:
|
||||
data.setVarFlag(entry, "deps", [var] + existing)
|
||||
|
||||
class BBHandlerNode(AstNode):
|
||||
def __init__(self, filename, lineno, fns):
|
||||
@@ -295,13 +309,6 @@ def handleAddTask(statements, filename, lineno, m):
|
||||
|
||||
statements.append(AddTaskNode(filename, lineno, func, before, after))
|
||||
|
||||
def handleDelTask(statements, filename, lineno, m):
|
||||
func = m.group("func")
|
||||
if func is None:
|
||||
return
|
||||
|
||||
statements.append(DelTaskNode(filename, lineno, func))
|
||||
|
||||
def handleBBHandlers(statements, filename, lineno, m):
|
||||
statements.append(BBHandlerNode(filename, lineno, m.group(1)))
|
||||
|
||||
@@ -326,8 +333,7 @@ def finalize(fn, d, variant = None):
|
||||
bb.data.update_data(d)
|
||||
|
||||
tasklist = d.getVar('__BBTASKS') or []
|
||||
deltasklist = d.getVar('__BBDELTASKS') or []
|
||||
bb.build.add_tasks(tasklist, deltasklist, d)
|
||||
bb.build.add_tasks(tasklist, d)
|
||||
|
||||
bb.parse.siggen.finalise(fn, d, variant)
|
||||
|
||||
|
||||
@@ -42,7 +42,6 @@ __func_start_regexp__ = re.compile( r"(((?P<py>python)|(?P<fr>fakeroot))\s*)*
|
||||
__inherit_regexp__ = re.compile( r"inherit\s+(.+)" )
|
||||
__export_func_regexp__ = re.compile( r"EXPORT_FUNCTIONS\s+(.+)" )
|
||||
__addtask_regexp__ = re.compile("addtask\s+(?P<func>\w+)\s*((before\s*(?P<before>((.*(?=after))|(.*))))|(after\s*(?P<after>((.*(?=before))|(.*)))))*")
|
||||
__deltask_regexp__ = re.compile("deltask\s+(?P<func>\w+)")
|
||||
__addhandler_regexp__ = re.compile( r"addhandler\s+(.+)" )
|
||||
__def_regexp__ = re.compile( r"def\s+(\w+).*:" )
|
||||
__python_func_regexp__ = re.compile( r"(\s+.*)|(^$)" )
|
||||
@@ -78,10 +77,7 @@ def inherit(files, fn, lineno, d):
|
||||
if not os.path.isabs(file):
|
||||
dname = os.path.dirname(fn)
|
||||
bbpath = "%s:%s" % (dname, d.getVar("BBPATH", True))
|
||||
abs_fn, attempts = bb.utils.which(bbpath, file, history=True)
|
||||
for af in attempts:
|
||||
if af != abs_fn:
|
||||
bb.parse.mark_dependency(d, af)
|
||||
abs_fn = bb.utils.which(bbpath, file)
|
||||
if abs_fn:
|
||||
file = abs_fn
|
||||
|
||||
@@ -244,11 +240,6 @@ def feeder(lineno, s, fn, root, statements):
|
||||
ast.handleAddTask(statements, fn, lineno, m)
|
||||
return
|
||||
|
||||
m = __deltask_regexp__.match(s)
|
||||
if m:
|
||||
ast.handleDelTask(statements, fn, lineno, m)
|
||||
return
|
||||
|
||||
m = __addhandler_regexp__.match(s)
|
||||
if m:
|
||||
ast.handleBBHandlers(statements, fn, lineno, m)
|
||||
|
||||
@@ -82,15 +82,9 @@ def include(oldfn, fn, lineno, data, error_out):
|
||||
if not os.path.isabs(fn):
|
||||
dname = os.path.dirname(oldfn)
|
||||
bbpath = "%s:%s" % (dname, data.getVar("BBPATH", True))
|
||||
abs_fn, attempts = bb.utils.which(bbpath, fn, history=True)
|
||||
if abs_fn and bb.parse.check_dependency(data, abs_fn):
|
||||
bb.warn("Duplicate inclusion for %s in %s" % (abs_fn, data.getVar('FILE', True)))
|
||||
for af in attempts:
|
||||
bb.parse.mark_dependency(data, af)
|
||||
abs_fn = bb.utils.which(bbpath, fn)
|
||||
if abs_fn:
|
||||
fn = abs_fn
|
||||
elif bb.parse.check_dependency(data, fn):
|
||||
bb.warn("Duplicate inclusion for %s in %s" % (fn, data.getVar('FILE', True)))
|
||||
|
||||
from bb.parse import handle
|
||||
try:
|
||||
@@ -99,7 +93,6 @@ def include(oldfn, fn, lineno, data, error_out):
|
||||
if error_out:
|
||||
raise ParseError("Could not %(error_out)s file %(fn)s" % vars(), oldfn, lineno)
|
||||
logger.debug(2, "CONF file '%s' not found", fn)
|
||||
bb.parse.mark_dependency(data, fn)
|
||||
|
||||
# We have an issue where a UI might want to enforce particular settings such as
|
||||
# an empty DISTRO variable. If configuration files do something like assigning
|
||||
|
||||
@@ -84,7 +84,7 @@ def _logged_communicate(pipe, log, input):
|
||||
while pipe.poll() is None:
|
||||
rlist = rin
|
||||
try:
|
||||
r,w,e = select.select (rlist, [], [], 1)
|
||||
r,w,e = select.select (rlist, [], [])
|
||||
except OSError as e:
|
||||
if e.errno != errno.EINTR:
|
||||
raise
|
||||
|
||||
@@ -30,7 +30,6 @@ import stat
|
||||
import fcntl
|
||||
import errno
|
||||
import logging
|
||||
import re
|
||||
import bb
|
||||
from bb import msg, data, event
|
||||
from bb import monitordisk
|
||||
@@ -44,8 +43,6 @@ except ImportError:
|
||||
bblogger = logging.getLogger("BitBake")
|
||||
logger = logging.getLogger("BitBake.RunQueue")
|
||||
|
||||
__find_md5__ = re.compile( r'(?i)(?<![a-z0-9])[a-f0-9]{32}(?![a-z0-9])' )
|
||||
|
||||
class RunQueueStats:
|
||||
"""
|
||||
Holds statistics on the tasks handled by the associated runQueue
|
||||
@@ -101,52 +98,26 @@ class RunQueueScheduler(object):
|
||||
"""
|
||||
self.rq = runqueue
|
||||
self.rqdata = rqdata
|
||||
self.numTasks = len(self.rqdata.runq_fnid)
|
||||
numTasks = len(self.rqdata.runq_fnid)
|
||||
|
||||
self.prio_map = []
|
||||
self.prio_map.extend(range(self.numTasks))
|
||||
|
||||
self.buildable = []
|
||||
self.stamps = {}
|
||||
for taskid in xrange(self.numTasks):
|
||||
fn = self.rqdata.taskData.fn_index[self.rqdata.runq_fnid[taskid]]
|
||||
taskname = self.rqdata.runq_task[taskid]
|
||||
self.stamps[taskid] = bb.build.stampfile(taskname, self.rqdata.dataCache, fn)
|
||||
if self.rq.runq_buildable[taskid] == 1:
|
||||
self.buildable.append(taskid)
|
||||
|
||||
self.rev_prio_map = None
|
||||
self.prio_map.extend(range(numTasks))
|
||||
|
||||
def next_buildable_task(self):
|
||||
"""
|
||||
Return the id of the first task we find that is buildable
|
||||
"""
|
||||
self.buildable = [x for x in self.buildable if not self.rq.runq_running[x] == 1]
|
||||
if not self.buildable:
|
||||
return None
|
||||
if len(self.buildable) == 1:
|
||||
taskid = self.buildable[0]
|
||||
stamp = self.stamps[taskid]
|
||||
if stamp not in self.rq.build_stamps.itervalues():
|
||||
return taskid
|
||||
|
||||
if not self.rev_prio_map:
|
||||
self.rev_prio_map = range(self.numTasks)
|
||||
for taskid in xrange(self.numTasks):
|
||||
self.rev_prio_map[self.prio_map[taskid]] = taskid
|
||||
|
||||
best = None
|
||||
bestprio = None
|
||||
for taskid in self.buildable:
|
||||
prio = self.rev_prio_map[taskid]
|
||||
if not bestprio or bestprio > prio:
|
||||
stamp = self.stamps[taskid]
|
||||
if stamp in self.rq.build_stamps.itervalues():
|
||||
for tasknum in xrange(len(self.rqdata.runq_fnid)):
|
||||
taskid = self.prio_map[tasknum]
|
||||
if self.rq.runq_running[taskid] == 1:
|
||||
continue
|
||||
if self.rq.runq_buildable[taskid] == 1:
|
||||
fn = self.rqdata.taskData.fn_index[self.rqdata.runq_fnid[taskid]]
|
||||
taskname = self.rqdata.runq_task[taskid]
|
||||
stamp = bb.build.stampfile(taskname, self.rqdata.dataCache, fn)
|
||||
if stamp in self.rq.build_stamps.values():
|
||||
continue
|
||||
bestprio = prio
|
||||
best = taskid
|
||||
|
||||
return best
|
||||
return taskid
|
||||
|
||||
def next(self):
|
||||
"""
|
||||
@@ -155,9 +126,6 @@ class RunQueueScheduler(object):
|
||||
if self.rq.stats.active < self.rq.number_tasks:
|
||||
return self.next_buildable_task()
|
||||
|
||||
def newbuilable(self, task):
|
||||
self.buildable.append(task)
|
||||
|
||||
class RunQueueSchedulerSpeed(RunQueueScheduler):
|
||||
"""
|
||||
A scheduler optimised for speed. The priority map is sorted by task weight,
|
||||
@@ -169,7 +137,9 @@ class RunQueueSchedulerSpeed(RunQueueScheduler):
|
||||
"""
|
||||
The priority map is sorted by task weight.
|
||||
"""
|
||||
RunQueueScheduler.__init__(self, runqueue, rqdata)
|
||||
|
||||
self.rq = runqueue
|
||||
self.rqdata = rqdata
|
||||
|
||||
sortweight = sorted(copy.deepcopy(self.rqdata.runq_weight))
|
||||
copyweight = copy.deepcopy(self.rqdata.runq_weight)
|
||||
@@ -808,6 +778,19 @@ class RunQueueData:
|
||||
procdep.append(self.taskData.fn_index[self.runq_fnid[dep]] + "." + self.runq_task[dep])
|
||||
self.runq_hash[task] = bb.parse.siggen.get_taskhash(self.taskData.fn_index[self.runq_fnid[task]], self.runq_task[task], procdep, self.dataCache)
|
||||
|
||||
self.hashes = {}
|
||||
self.hash_deps = {}
|
||||
for task in xrange(len(self.runq_fnid)):
|
||||
identifier = '%s.%s' % (self.taskData.fn_index[self.runq_fnid[task]],
|
||||
self.runq_task[task])
|
||||
self.hashes[identifier] = self.runq_hash[task]
|
||||
deps = []
|
||||
for dep in self.runq_depends[task]:
|
||||
depidentifier = '%s.%s' % (self.taskData.fn_index[self.runq_fnid[dep]],
|
||||
self.runq_task[dep])
|
||||
deps.append(depidentifier)
|
||||
self.hash_deps[identifier] = deps
|
||||
|
||||
return len(self.runq_fnid)
|
||||
|
||||
def dump_data(self, taskQueue):
|
||||
@@ -876,8 +859,8 @@ class RunQueue:
|
||||
"fakerootenv" : self.rqdata.dataCache.fakerootenv,
|
||||
"fakerootdirs" : self.rqdata.dataCache.fakerootdirs,
|
||||
"fakerootnoenv" : self.rqdata.dataCache.fakerootnoenv,
|
||||
"hashes" : bb.parse.siggen.taskhash,
|
||||
"hash_deps" : bb.parse.siggen.runtaskdeps,
|
||||
"hashes" : self.rqdata.hashes,
|
||||
"hash_deps" : self.rqdata.hash_deps,
|
||||
"sigchecksums" : bb.parse.siggen.file_checksum_values,
|
||||
"runq_hash" : self.rqdata.runq_hash,
|
||||
"logdefaultdebug" : bb.msg.loggerDefaultDebugLevel,
|
||||
@@ -1032,10 +1015,7 @@ class RunQueue:
|
||||
|
||||
if self.state is runQueueSceneInit:
|
||||
if self.cooker.configuration.dump_signatures:
|
||||
invalidtasks = self.print_diffscenetasks()
|
||||
self.dump_signatures()
|
||||
self.write_diffscenetasks(invalidtasks)
|
||||
self.state = runQueueComplete
|
||||
else:
|
||||
self.start_worker()
|
||||
self.rqexe = RunQueueExecuteScenequeue(self)
|
||||
@@ -1106,6 +1086,7 @@ class RunQueue:
|
||||
self.rqexe.finish()
|
||||
|
||||
def dump_signatures(self):
|
||||
self.state = runQueueComplete
|
||||
done = set()
|
||||
bb.note("Reparsing files to collect dependency data")
|
||||
for task in range(len(self.rqdata.runq_fnid)):
|
||||
@@ -1118,120 +1099,6 @@ class RunQueue:
|
||||
|
||||
return
|
||||
|
||||
def print_diffscenetasks(self):
|
||||
|
||||
valid = []
|
||||
sq_hash = []
|
||||
sq_hashfn = []
|
||||
sq_fn = []
|
||||
sq_taskname = []
|
||||
sq_task = []
|
||||
noexec = []
|
||||
stamppresent = []
|
||||
valid_new = set()
|
||||
|
||||
for task in xrange(len(self.rqdata.runq_fnid)):
|
||||
fn = self.rqdata.taskData.fn_index[self.rqdata.runq_fnid[task]]
|
||||
taskname = self.rqdata.runq_task[task]
|
||||
taskdep = self.rqdata.dataCache.task_deps[fn]
|
||||
|
||||
if 'noexec' in taskdep and taskname in taskdep['noexec']:
|
||||
noexec.append(task)
|
||||
continue
|
||||
|
||||
sq_fn.append(fn)
|
||||
sq_hashfn.append(self.rqdata.dataCache.hashfn[fn])
|
||||
sq_hash.append(self.rqdata.runq_hash[task])
|
||||
sq_taskname.append(taskname)
|
||||
sq_task.append(task)
|
||||
call = self.hashvalidate + "(sq_fn, sq_task, sq_hash, sq_hashfn, d)"
|
||||
locs = { "sq_fn" : sq_fn, "sq_task" : sq_taskname, "sq_hash" : sq_hash, "sq_hashfn" : sq_hashfn, "d" : self.cooker.data }
|
||||
valid = bb.utils.better_eval(call, locs)
|
||||
for v in valid:
|
||||
valid_new.add(sq_task[v])
|
||||
|
||||
# Tasks which are both setscene and noexec never care about dependencies
|
||||
# We therefore find tasks which are setscene and noexec and mark their
|
||||
# unique dependencies as valid.
|
||||
for task in noexec:
|
||||
if task not in self.rqdata.runq_setscene:
|
||||
continue
|
||||
for dep in self.rqdata.runq_depends[task]:
|
||||
hasnoexecparents = True
|
||||
for dep2 in self.rqdata.runq_revdeps[dep]:
|
||||
if dep2 in self.rqdata.runq_setscene and dep2 in noexec:
|
||||
continue
|
||||
hasnoexecparents = False
|
||||
break
|
||||
if hasnoexecparents:
|
||||
valid_new.add(dep)
|
||||
|
||||
invalidtasks = set()
|
||||
for task in xrange(len(self.rqdata.runq_fnid)):
|
||||
if task not in valid_new and task not in noexec:
|
||||
invalidtasks.add(task)
|
||||
|
||||
found = set()
|
||||
processed = set()
|
||||
for task in invalidtasks:
|
||||
toprocess = set([task])
|
||||
while toprocess:
|
||||
next = set()
|
||||
for t in toprocess:
|
||||
for dep in self.rqdata.runq_depends[t]:
|
||||
if dep in invalidtasks:
|
||||
found.add(task)
|
||||
if dep not in processed:
|
||||
processed.add(dep)
|
||||
next.add(dep)
|
||||
toprocess = next
|
||||
if task in found:
|
||||
toprocess = set()
|
||||
|
||||
tasklist = []
|
||||
for task in invalidtasks.difference(found):
|
||||
tasklist.append(self.rqdata.get_user_idstring(task))
|
||||
|
||||
if tasklist:
|
||||
bb.plain("The differences between the current build and any cached tasks start at the following tasks:\n" + "\n".join(tasklist))
|
||||
|
||||
return invalidtasks.difference(found)
|
||||
|
||||
def write_diffscenetasks(self, invalidtasks):
|
||||
|
||||
# Define recursion callback
|
||||
def recursecb(key, hash1, hash2):
|
||||
hashes = [hash1, hash2]
|
||||
hashfiles = bb.siggen.find_siginfo(key, None, hashes, self.cfgData)
|
||||
|
||||
recout = []
|
||||
if len(hashfiles) == 2:
|
||||
out2 = bb.siggen.compare_sigfiles(hashfiles[hash1], hashfiles[hash2], recursecb)
|
||||
recout.extend(list(' ' + l for l in out2))
|
||||
else:
|
||||
recout.append("Unable to find matching sigdata for %s with hashes %s or %s" % (key, hash1, hash2))
|
||||
|
||||
return recout
|
||||
|
||||
|
||||
for task in invalidtasks:
|
||||
fn = self.rqdata.taskData.fn_index[self.rqdata.runq_fnid[task]]
|
||||
pn = self.rqdata.dataCache.pkg_fn[fn]
|
||||
taskname = self.rqdata.runq_task[task]
|
||||
h = self.rqdata.runq_hash[task]
|
||||
matches = bb.siggen.find_siginfo(pn, taskname, [], self.cfgData)
|
||||
match = None
|
||||
for m in matches:
|
||||
if h in m:
|
||||
match = m
|
||||
if match is None:
|
||||
bb.fatal("Can't find a task we're supposed to have written out? (hash: %s)?" % h)
|
||||
matches = {k : v for k, v in matches.iteritems() if h not in k}
|
||||
if matches:
|
||||
latestmatch = sorted(matches.keys(), key=lambda f: matches[f])[-1]
|
||||
prevh = __find_md5__.search(latestmatch).group(0)
|
||||
output = bb.siggen.compare_sigfiles(latestmatch, match, recursecb)
|
||||
bb.plain("\nTask %s:%s couldn't be used from the cache because:\n We need hash %s, closest matching task was %s\n " % (pn, taskname, h, prevh) + '\n '.join(output))
|
||||
|
||||
class RunQueueExecute:
|
||||
|
||||
@@ -1249,7 +1116,6 @@ class RunQueueExecute:
|
||||
self.runq_complete = []
|
||||
|
||||
self.build_stamps = {}
|
||||
self.build_stamps2 = []
|
||||
self.failed_fnids = []
|
||||
|
||||
self.stampcache = {}
|
||||
@@ -1262,7 +1128,6 @@ class RunQueueExecute:
|
||||
|
||||
# self.build_stamps[pid] may not exist when use shared work directory.
|
||||
if task in self.build_stamps:
|
||||
self.build_stamps2.remove(self.build_stamps[task])
|
||||
del self.build_stamps[task]
|
||||
|
||||
if status != 0:
|
||||
@@ -1339,8 +1204,6 @@ class RunQueueExecuteTasks(RunQueueExecute):
|
||||
|
||||
self.stampcache = {}
|
||||
|
||||
initial_covered = self.rq.scenequeue_covered.copy()
|
||||
|
||||
# Mark initial buildable tasks
|
||||
for task in xrange(self.stats.total):
|
||||
self.runq_running.append(0)
|
||||
@@ -1394,27 +1257,12 @@ class RunQueueExecuteTasks(RunQueueExecute):
|
||||
except TypeError:
|
||||
covered_remove = bb.utils.better_eval(call2, locs)
|
||||
|
||||
def removecoveredtask(task):
|
||||
for task in covered_remove:
|
||||
fn = self.rqdata.taskData.fn_index[self.rqdata.runq_fnid[task]]
|
||||
taskname = self.rqdata.runq_task[task] + '_setscene'
|
||||
bb.build.del_stamp(taskname, self.rqdata.dataCache, fn)
|
||||
self.rq.scenequeue_covered.remove(task)
|
||||
|
||||
toremove = covered_remove
|
||||
for task in toremove:
|
||||
logger.debug(1, 'Not skipping task %s due to setsceneverify', task)
|
||||
while toremove:
|
||||
covered_remove = []
|
||||
for task in toremove:
|
||||
removecoveredtask(task)
|
||||
for deptask in self.rqdata.runq_depends[task]:
|
||||
if deptask not in self.rq.scenequeue_covered:
|
||||
continue
|
||||
if deptask in toremove or deptask in covered_remove or deptask in initial_covered:
|
||||
continue
|
||||
logger.debug(1, 'Task %s depends on task %s so not skipping' % (task, deptask))
|
||||
covered_remove.append(deptask)
|
||||
toremove = covered_remove
|
||||
self.rq.scenequeue_covered.remove(task)
|
||||
|
||||
logger.debug(1, 'Full skip list %s', self.rq.scenequeue_covered)
|
||||
|
||||
@@ -1452,10 +1300,6 @@ class RunQueueExecuteTasks(RunQueueExecute):
|
||||
schedulers.add(getattr(module, name))
|
||||
return schedulers
|
||||
|
||||
def setbuildable(self, task):
|
||||
self.runq_buildable[task] = 1
|
||||
self.sched.newbuilable(task)
|
||||
|
||||
def task_completeoutright(self, task):
|
||||
"""
|
||||
Mark a task as completed
|
||||
@@ -1473,7 +1317,7 @@ class RunQueueExecuteTasks(RunQueueExecute):
|
||||
if self.runq_complete[dep] != 1:
|
||||
alldeps = 0
|
||||
if alldeps == 1:
|
||||
self.setbuildable(revdep)
|
||||
self.runq_buildable[revdep] = 1
|
||||
fn = self.rqdata.taskData.fn_index[self.rqdata.runq_fnid[revdep]]
|
||||
taskname = self.rqdata.runq_task[revdep]
|
||||
logger.debug(1, "Marking task %s (%s, %s) as buildable", revdep, fn, taskname)
|
||||
@@ -1497,7 +1341,7 @@ class RunQueueExecuteTasks(RunQueueExecute):
|
||||
|
||||
def task_skip(self, task, reason):
|
||||
self.runq_running[task] = 1
|
||||
self.setbuildable(task)
|
||||
self.runq_buildable[task] = 1
|
||||
bb.event.fire(runQueueTaskSkipped(task, self.stats, self.rq, reason), self.cfgData)
|
||||
self.task_completeoutright(task)
|
||||
self.stats.taskCompleted()
|
||||
@@ -1546,20 +1390,17 @@ class RunQueueExecuteTasks(RunQueueExecute):
|
||||
startevent = runQueueTaskStarted(task, self.stats, self.rq)
|
||||
bb.event.fire(startevent, self.cfgData)
|
||||
|
||||
taskdepdata = self.build_taskdepdata(task)
|
||||
|
||||
taskdep = self.rqdata.dataCache.task_deps[fn]
|
||||
if 'fakeroot' in taskdep and taskname in taskdep['fakeroot'] and not self.cooker.configuration.dry_run:
|
||||
if 'fakeroot' in taskdep and taskname in taskdep['fakeroot']:
|
||||
if not self.rq.fakeworker:
|
||||
self.rq.start_fakeworker(self)
|
||||
self.rq.fakeworker.stdin.write("<runtask>" + pickle.dumps((fn, task, taskname, False, self.cooker.collection.get_file_appends(fn), taskdepdata)) + "</runtask>")
|
||||
self.rq.fakeworker.stdin.write("<runtask>" + pickle.dumps((fn, task, taskname, False, self.cooker.collection.get_file_appends(fn))) + "</runtask>")
|
||||
self.rq.fakeworker.stdin.flush()
|
||||
else:
|
||||
self.rq.worker.stdin.write("<runtask>" + pickle.dumps((fn, task, taskname, False, self.cooker.collection.get_file_appends(fn), taskdepdata)) + "</runtask>")
|
||||
self.rq.worker.stdin.write("<runtask>" + pickle.dumps((fn, task, taskname, False, self.cooker.collection.get_file_appends(fn))) + "</runtask>")
|
||||
self.rq.worker.stdin.flush()
|
||||
|
||||
self.build_stamps[task] = bb.build.stampfile(taskname, self.rqdata.dataCache, fn)
|
||||
self.build_stamps2.append(self.build_stamps[task])
|
||||
self.runq_running[task] = 1
|
||||
self.stats.taskActive()
|
||||
if self.stats.active < self.number_tasks:
|
||||
@@ -1585,26 +1426,6 @@ class RunQueueExecuteTasks(RunQueueExecute):
|
||||
|
||||
return True
|
||||
|
||||
def build_taskdepdata(self, task):
|
||||
taskdepdata = {}
|
||||
next = self.rqdata.runq_depends[task]
|
||||
next.add(task)
|
||||
while next:
|
||||
additional = []
|
||||
for revdep in next:
|
||||
fn = self.rqdata.taskData.fn_index[self.rqdata.runq_fnid[revdep]]
|
||||
pn = self.rqdata.dataCache.pkg_fn[fn]
|
||||
taskname = self.rqdata.runq_task[revdep]
|
||||
deps = self.rqdata.runq_depends[revdep]
|
||||
taskdepdata[revdep] = [pn, taskname, fn, deps]
|
||||
for revdep2 in deps:
|
||||
if revdep2 not in taskdepdata:
|
||||
additional.append(revdep2)
|
||||
next = additional
|
||||
|
||||
#bb.note("Task %s: " % task + str(taskdepdata).replace("], ", "],\n"))
|
||||
return taskdepdata
|
||||
|
||||
class RunQueueExecuteScenequeue(RunQueueExecute):
|
||||
def __init__(self, rq):
|
||||
RunQueueExecute.__init__(self, rq)
|
||||
@@ -1624,7 +1445,7 @@ class RunQueueExecuteScenequeue(RunQueueExecute):
|
||||
sq_revdeps = []
|
||||
sq_revdeps_new = []
|
||||
sq_revdeps_squash = []
|
||||
self.sq_harddeps = {}
|
||||
self.sq_harddeps = []
|
||||
|
||||
# We need to construct a dependency graph for the setscene functions. Intermediate
|
||||
# dependencies between the setscene tasks only complicate the code. This code
|
||||
@@ -1735,19 +1556,15 @@ class RunQueueExecuteScenequeue(RunQueueExecute):
|
||||
dep = self.rqdata.taskData.fn_index[depdata]
|
||||
taskid = self.rqdata.get_task_id(self.rqdata.taskData.getfn_id(dep), idependtask.replace("_setscene", ""))
|
||||
if taskid is None:
|
||||
bb.msg.fatal("RunQueue", "Task %s_setscene depends upon non-existent task %s:%s" % (self.self.rqdata.get_user_idstring(task), dep, idependtask))
|
||||
|
||||
if not self.rqdata.runq_setscene.index(taskid) in self.sq_harddeps:
|
||||
self.sq_harddeps[self.rqdata.runq_setscene.index(taskid)] = set()
|
||||
self.sq_harddeps[self.rqdata.runq_setscene.index(taskid)].add(self.rqdata.runq_setscene.index(task))
|
||||
bb.msg.fatal("RunQueue", "Task %s:%s depends upon non-existent task %s:%s" % (self.rqdata.taskData.fn_index[self.rqdata.runq_fnid[realid]], self.rqdata.taskData.tasks_name[realid], dep, idependtask))
|
||||
|
||||
self.sq_harddeps.append(self.rqdata.runq_setscene.index(taskid))
|
||||
sq_revdeps_squash[self.rqdata.runq_setscene.index(task)].add(self.rqdata.runq_setscene.index(taskid))
|
||||
# Have to zero this to avoid circular dependencies
|
||||
sq_revdeps_squash[self.rqdata.runq_setscene.index(taskid)] = set()
|
||||
|
||||
#for task in xrange(len(sq_revdeps_squash)):
|
||||
# realtask = self.rqdata.runq_setscene[task]
|
||||
# bb.warn("Task %s: %s_setscene is %s " % (task, self.rqdata.get_user_idstring(realtask) , sq_revdeps_squash[task]))
|
||||
# print "Task %s: %s.%s is %s " % (task, self.rqdata.taskData.fn_index[self.rqdata.runq_fnid[self.rqdata.runq_setscene[task]]], self.rqdata.runq_task[self.rqdata.runq_setscene[task]] + "_setscene", sq_revdeps_squash[task])
|
||||
|
||||
self.sq_deps = []
|
||||
self.sq_revdeps = sq_revdeps_squash
|
||||
@@ -1821,10 +1638,7 @@ class RunQueueExecuteScenequeue(RunQueueExecute):
|
||||
|
||||
def scenequeue_updatecounters(self, task, fail = False):
|
||||
for dep in self.sq_deps[task]:
|
||||
if fail and task in self.sq_harddeps and dep in self.sq_harddeps[task]:
|
||||
realtask = self.rqdata.runq_setscene[task]
|
||||
realdep = self.rqdata.runq_setscene[dep]
|
||||
logger.debug(2, "%s was unavailable and is a hard dependency of %s so skipping" % (self.rqdata.get_user_idstring(realtask), self.rqdata.get_user_idstring(realdep)))
|
||||
if fail and task in self.sq_harddeps:
|
||||
continue
|
||||
self.sq_revdeps2[dep].remove(task)
|
||||
if len(self.sq_revdeps2[dep]) == 0:
|
||||
@@ -1886,18 +1700,10 @@ class RunQueueExecuteScenequeue(RunQueueExecute):
|
||||
if nexttask in self.unskippable:
|
||||
logger.debug(2, "Setscene task %s is unskippable" % self.rqdata.get_user_idstring(self.rqdata.runq_setscene[nexttask]))
|
||||
if nexttask not in self.unskippable and len(self.sq_revdeps[nexttask]) > 0 and self.sq_revdeps[nexttask].issubset(self.scenequeue_covered) and self.check_dependencies(nexttask, self.sq_revdeps[nexttask], True):
|
||||
realtask = self.rqdata.runq_setscene[nexttask]
|
||||
fn = self.rqdata.taskData.fn_index[self.rqdata.runq_fnid[realtask]]
|
||||
foundtarget = False
|
||||
for target in self.rqdata.target_pairs:
|
||||
if target[0] == fn and target[1] == self.rqdata.runq_task[realtask]:
|
||||
foundtarget = True
|
||||
break
|
||||
if not foundtarget:
|
||||
logger.debug(2, "Skipping setscene for task %s" % self.rqdata.get_user_idstring(self.rqdata.runq_setscene[nexttask]))
|
||||
self.task_skip(nexttask)
|
||||
self.scenequeue_notneeded.add(nexttask)
|
||||
return True
|
||||
logger.debug(2, "Skipping setscene for task %s" % self.rqdata.get_user_idstring(self.rqdata.runq_setscene[nexttask]))
|
||||
self.task_skip(nexttask)
|
||||
self.scenequeue_notneeded.add(nexttask)
|
||||
return True
|
||||
task = nexttask
|
||||
break
|
||||
if task is not None:
|
||||
@@ -1930,10 +1736,10 @@ class RunQueueExecuteScenequeue(RunQueueExecute):
|
||||
if 'fakeroot' in taskdep and taskname in taskdep['fakeroot']:
|
||||
if not self.rq.fakeworker:
|
||||
self.rq.start_fakeworker(self)
|
||||
self.rq.fakeworker.stdin.write("<runtask>" + pickle.dumps((fn, realtask, taskname, True, self.cooker.collection.get_file_appends(fn), None)) + "</runtask>")
|
||||
self.rq.fakeworker.stdin.write("<runtask>" + pickle.dumps((fn, realtask, taskname, True, self.cooker.collection.get_file_appends(fn))) + "</runtask>")
|
||||
self.rq.fakeworker.stdin.flush()
|
||||
else:
|
||||
self.rq.worker.stdin.write("<runtask>" + pickle.dumps((fn, realtask, taskname, True, self.cooker.collection.get_file_appends(fn), None)) + "</runtask>")
|
||||
self.rq.worker.stdin.write("<runtask>" + pickle.dumps((fn, realtask, taskname, True, self.cooker.collection.get_file_appends(fn))) + "</runtask>")
|
||||
self.rq.worker.stdin.flush()
|
||||
|
||||
self.runq_running[task] = 1
|
||||
@@ -1945,12 +1751,6 @@ class RunQueueExecuteScenequeue(RunQueueExecute):
|
||||
self.rq.read_workers()
|
||||
return self.rq.active_fds()
|
||||
|
||||
#for task in xrange(self.stats.total):
|
||||
# if self.runq_running[task] != 1:
|
||||
# buildable = self.runq_buildable[task]
|
||||
# revdeps = self.sq_revdeps[task]
|
||||
# bb.warn("Found we didn't run %s %s %s %s" % (task, buildable, str(revdeps), self.rqdata.get_user_idstring(self.rqdata.runq_setscene[task])))
|
||||
|
||||
# Convert scenequeue_covered task numbers into full taskgraph ids
|
||||
oldcovered = self.scenequeue_covered
|
||||
self.rq.scenequeue_covered = set()
|
||||
|
||||
@@ -198,11 +198,6 @@ class XMLRPCServer(SimpleXMLRPCServer, BaseImplServer):
|
||||
Constructor
|
||||
"""
|
||||
BaseImplServer.__init__(self)
|
||||
if (interface[1] == 0): # anonymous port, not getting reused
|
||||
self.single_use = True
|
||||
# Use auto port configuration
|
||||
if (interface[1] == -1):
|
||||
interface = (interface[0], 0)
|
||||
SimpleXMLRPCServer.__init__(self, interface,
|
||||
requestHandler=BitBakeXMLRPCRequestHandler,
|
||||
logRequests=False, allow_none=True)
|
||||
@@ -213,6 +208,8 @@ class XMLRPCServer(SimpleXMLRPCServer, BaseImplServer):
|
||||
self.autoregister_all_functions(self.commands, "")
|
||||
self.interface = interface
|
||||
self.single_use = False
|
||||
if (interface[1] == 0): # anonymous port, not getting reused
|
||||
self.single_use = True
|
||||
|
||||
def addcooker(self, cooker):
|
||||
BaseImplServer.addcooker(self, cooker)
|
||||
@@ -341,38 +338,13 @@ class BitBakeXMLRPCClient(BitBakeBaseServer):
|
||||
def saveConnectionDetails(self, remote):
|
||||
self.remote = remote
|
||||
|
||||
def saveConnectionConfigParams(self, configParams):
|
||||
self.configParams = configParams
|
||||
|
||||
def establishConnection(self, featureset):
|
||||
# The format of "remote" must be "server:port"
|
||||
try:
|
||||
[host, port] = self.remote.split(":")
|
||||
port = int(port)
|
||||
except Exception as e:
|
||||
bb.fatal("Failed to read remote definition (%s)" % str(e))
|
||||
|
||||
# use automatic port if port set to -1, meaning read it from
|
||||
# the bitbake.lock file
|
||||
if port == -1:
|
||||
lock_location = "%s/bitbake.lock" % self.configParams.environment.get('BUILDDIR')
|
||||
lock = bb.utils.lockfile(lock_location, False, False)
|
||||
if lock:
|
||||
# This means there is no server running which we can
|
||||
# connect to on the local system.
|
||||
bb.utils.unlockfile(lock)
|
||||
return None
|
||||
|
||||
try:
|
||||
lf = open(lock_location, 'r')
|
||||
remotedef = lf.readline()
|
||||
[host, port] = remotedef.split(":")
|
||||
port = int(port)
|
||||
lf.close()
|
||||
self.remote = remotedef
|
||||
except Exception as e:
|
||||
bb.fatal("Failed to read bitbake.lock (%s)" % str(e))
|
||||
|
||||
except:
|
||||
return None
|
||||
# We need our IP for the server connection. We get the IP
|
||||
# by trying to connect with the server
|
||||
try:
|
||||
@@ -380,8 +352,8 @@ class BitBakeXMLRPCClient(BitBakeBaseServer):
|
||||
s.connect((host, port))
|
||||
ip = s.getsockname()[0]
|
||||
s.close()
|
||||
except Exception as e:
|
||||
bb.fatal("Could not create socket for %s:%s (%s)" % (host, port, str(e)))
|
||||
except:
|
||||
return None
|
||||
try:
|
||||
self.serverImpl = XMLRPCProxyServer(host, port)
|
||||
self.connection = BitBakeXMLRPCServerConnection(self.serverImpl, (ip, 0), self.observer_only, featureset)
|
||||
|
||||
@@ -34,9 +34,7 @@ class SignatureGenerator(object):
|
||||
name = "noop"
|
||||
|
||||
def __init__(self, data):
|
||||
self.taskhash = {}
|
||||
self.runtaskdeps = {}
|
||||
self.file_checksum_values = {}
|
||||
return
|
||||
|
||||
def finalise(self, fn, d, varient):
|
||||
return
|
||||
@@ -44,7 +42,7 @@ class SignatureGenerator(object):
|
||||
def get_taskhash(self, fn, task, deps, dataCache):
|
||||
return "0"
|
||||
|
||||
def set_taskdata(self, hashes, deps, checksum):
|
||||
def set_taskdata(self, hashes, deps):
|
||||
return
|
||||
|
||||
def stampfile(self, stampbase, file_name, taskname, extrainfo):
|
||||
@@ -59,8 +57,6 @@ class SignatureGenerator(object):
|
||||
def invalidate_task(self, task, d, fn):
|
||||
bb.build.del_stamp(task, d, fn)
|
||||
|
||||
def dump_sigs(self, dataCache):
|
||||
return
|
||||
|
||||
class SignatureGeneratorBasic(SignatureGenerator):
|
||||
"""
|
||||
@@ -228,7 +224,7 @@ class SignatureGeneratorBasic(SignatureGenerator):
|
||||
|
||||
if runtime and k in self.taskhash:
|
||||
data['runtaskdeps'] = self.runtaskdeps[k]
|
||||
data['file_checksum_values'] = [(os.path.basename(f), cs) for f,cs in self.file_checksum_values[k].items()]
|
||||
data['file_checksum_values'] = self.file_checksum_values[k]
|
||||
data['runtaskhashes'] = {}
|
||||
for dep in data['runtaskdeps']:
|
||||
data['runtaskhashes'][dep] = self.taskhash[dep]
|
||||
@@ -242,6 +238,7 @@ class SignatureGeneratorBasic(SignatureGenerator):
|
||||
with os.fdopen(fd, "wb") as stream:
|
||||
p = pickle.dump(data, stream, -1)
|
||||
stream.flush()
|
||||
os.fsync(fd)
|
||||
os.chmod(tmpfile, 0664)
|
||||
os.rename(tmpfile, sigfile)
|
||||
except (OSError, IOError) as err:
|
||||
@@ -321,41 +318,8 @@ def compare_sigfiles(a, b, recursecb = None):
|
||||
for i in common:
|
||||
if a[i] != b[i] and i not in whitelist:
|
||||
changed.add(i)
|
||||
added = sb - sa
|
||||
removed = sa - sb
|
||||
return changed, added, removed
|
||||
|
||||
def file_checksums_diff(a, b):
|
||||
from collections import Counter
|
||||
# Handle old siginfo format
|
||||
if isinstance(a, dict):
|
||||
a = [(os.path.basename(f), cs) for f, cs in a.items()]
|
||||
if isinstance(b, dict):
|
||||
b = [(os.path.basename(f), cs) for f, cs in b.items()]
|
||||
# Compare lists, ensuring we can handle duplicate filenames if they exist
|
||||
removedcount = Counter(a)
|
||||
removedcount.subtract(b)
|
||||
addedcount = Counter(b)
|
||||
addedcount.subtract(a)
|
||||
added = []
|
||||
for x in b:
|
||||
if addedcount[x] > 0:
|
||||
addedcount[x] -= 1
|
||||
added.append(x)
|
||||
removed = []
|
||||
changed = []
|
||||
for x in a:
|
||||
if removedcount[x] > 0:
|
||||
removedcount[x] -= 1
|
||||
for y in added:
|
||||
if y[0] == x[0]:
|
||||
changed.append((x[0], x[1], y[1]))
|
||||
added.remove(y)
|
||||
break
|
||||
else:
|
||||
removed.append(x)
|
||||
added = [x[0] for x in added]
|
||||
removed = [x[0] for x in removed]
|
||||
added = sa - sb
|
||||
removed = sb - sa
|
||||
return changed, added, removed
|
||||
|
||||
if 'basewhitelist' in a_data and a_data['basewhitelist'] != b_data['basewhitelist']:
|
||||
@@ -393,10 +357,10 @@ def compare_sigfiles(a, b, recursecb = None):
|
||||
for dep in changed:
|
||||
output.append("Variable %s value changed from '%s' to '%s'" % (dep, a_data['varvals'][dep], b_data['varvals'][dep]))
|
||||
|
||||
changed, added, removed = file_checksums_diff(a_data['file_checksum_values'], b_data['file_checksum_values'])
|
||||
changed, added, removed = dict_diff(a_data['file_checksum_values'], b_data['file_checksum_values'])
|
||||
if changed:
|
||||
for f, old, new in changed:
|
||||
output.append("Checksum for file %s changed from %s to %s" % (f, old, new))
|
||||
for f in changed:
|
||||
output.append("Checksum for file %s changed from %s to %s" % (f, a_data['file_checksum_values'][f], b_data['file_checksum_values'][f]))
|
||||
if added:
|
||||
for f in added:
|
||||
output.append("Dependency on checksum of file %s was added" % (f))
|
||||
@@ -414,30 +378,28 @@ def compare_sigfiles(a, b, recursecb = None):
|
||||
bdep_found = False
|
||||
if removed:
|
||||
for bdep in removed:
|
||||
if b[dep] == a[bdep]:
|
||||
if a[dep] == b[bdep]:
|
||||
#output.append("Dependency on task %s was replaced by %s with same hash" % (dep, bdep))
|
||||
bdep_found = True
|
||||
if not bdep_found:
|
||||
output.append("Dependency on task %s was added with hash %s" % (clean_basepath(dep), b[dep]))
|
||||
output.append("Dependency on task %s was added with hash %s" % (clean_basepath(dep), a[dep]))
|
||||
if removed:
|
||||
for dep in removed:
|
||||
adep_found = False
|
||||
if added:
|
||||
for adep in added:
|
||||
if b[adep] == a[dep]:
|
||||
if a[adep] == b[dep]:
|
||||
#output.append("Dependency on task %s was replaced by %s with same hash" % (adep, dep))
|
||||
adep_found = True
|
||||
if not adep_found:
|
||||
output.append("Dependency on task %s was removed with hash %s" % (clean_basepath(dep), a[dep]))
|
||||
output.append("Dependency on task %s was removed with hash %s" % (clean_basepath(dep), b[dep]))
|
||||
if changed:
|
||||
for dep in changed:
|
||||
output.append("Hash for dependent task %s changed from %s to %s" % (clean_basepath(dep), a[dep], b[dep]))
|
||||
if callable(recursecb):
|
||||
# If a dependent hash changed, might as well print the line above and then defer to the changes in
|
||||
# that hash since in all likelyhood, they're the same changes this task also saw.
|
||||
recout = recursecb(dep, a[dep], b[dep])
|
||||
if recout:
|
||||
output = [output[-1]] + recout
|
||||
output.extend(recout)
|
||||
|
||||
a_taint = a_data.get('taint', None)
|
||||
b_taint = b_data.get('taint', None)
|
||||
|
||||
@@ -382,21 +382,6 @@ class FetcherNetworkTest(FetcherTest):
|
||||
url1 = url2 = "git://git.openembedded.org/bitbake"
|
||||
self.gitfetcher(url1, url2)
|
||||
|
||||
def test_gitfetch_goodsrcrev(self):
|
||||
# SRCREV is set but matches rev= parameter
|
||||
url1 = url2 = "git://git.openembedded.org/bitbake;rev=270a05b0b4ba0959fe0624d2a4885d7b70426da5"
|
||||
self.gitfetcher(url1, url2)
|
||||
|
||||
def test_gitfetch_badsrcrev(self):
|
||||
# SRCREV is set but does not match rev= parameter
|
||||
url1 = url2 = "git://git.openembedded.org/bitbake;rev=dead05b0b4ba0959fe0624d2a4885d7b70426da5"
|
||||
self.assertRaises(bb.fetch.FetchError, self.gitfetcher, url1, url2)
|
||||
|
||||
def test_gitfetch_tagandrev(self):
|
||||
# SRCREV is set but does not match rev= parameter
|
||||
url1 = url2 = "git://git.openembedded.org/bitbake;rev=270a05b0b4ba0959fe0624d2a4885d7b70426da5;tag=270a05b0b4ba0959fe0624d2a4885d7b70426da5"
|
||||
self.assertRaises(bb.fetch.FetchError, self.gitfetcher, url1, url2)
|
||||
|
||||
def test_gitfetch_premirror(self):
|
||||
url1 = "git://git.openembedded.org/bitbake"
|
||||
url2 = "git://someserver.org/bitbake"
|
||||
@@ -422,8 +407,7 @@ class URLHandle(unittest.TestCase):
|
||||
datatable = {
|
||||
"http://www.google.com/index.html" : ('http', 'www.google.com', '/index.html', '', '', {}),
|
||||
"cvs://anoncvs@cvs.handhelds.org/cvs;module=familiar/dist/ipkg" : ('cvs', 'cvs.handhelds.org', '/cvs', 'anoncvs', '', {'module': 'familiar/dist/ipkg'}),
|
||||
"cvs://anoncvs:anonymous@cvs.handhelds.org/cvs;tag=V0-99-81;module=familiar/dist/ipkg" : ('cvs', 'cvs.handhelds.org', '/cvs', 'anoncvs', 'anonymous', {'tag': 'V0-99-81', 'module': 'familiar/dist/ipkg'}),
|
||||
"git://git.openembedded.org/bitbake;branch=@foo" : ('git', 'git.openembedded.org', '/bitbake', '', '', {'branch': '@foo'})
|
||||
"cvs://anoncvs:anonymous@cvs.handhelds.org/cvs;tag=V0-99-81;module=familiar/dist/ipkg" : ('cvs', 'cvs.handhelds.org', '/cvs', 'anoncvs', 'anonymous', {'tag': 'V0-99-81', 'module': 'familiar/dist/ipkg'})
|
||||
}
|
||||
|
||||
def test_decodeurl(self):
|
||||
|
||||
@@ -20,16 +20,17 @@ import datetime
|
||||
import sys
|
||||
import bb
|
||||
import re
|
||||
import ast
|
||||
import subprocess
|
||||
|
||||
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "toaster.toastermain.settings")
|
||||
|
||||
import toaster.toastermain.settings as toaster_django_settings
|
||||
from toaster.orm.models import Build, Task, Recipe, Layer_Version, Layer, Target, LogMessage
|
||||
from toaster.orm.models import Variable, VariableHistory
|
||||
from toaster.orm.models import Package, Package_File, Target_Installed_Package
|
||||
from toaster.orm.models import Task_Dependency, Package_Dependency
|
||||
from toaster.orm.models import Recipe_Dependency
|
||||
from toaster.orm.models import Target_Package, Build_Package, Build_File
|
||||
from toaster.orm.models import Task_Dependency, Build_Package_Dependency
|
||||
from toaster.orm.models import Target_Package_Dependency, Recipe_Dependency
|
||||
from bb.msg import BBLogFormatter as format
|
||||
|
||||
class ORMWrapper(object):
|
||||
@@ -75,7 +76,6 @@ class ORMWrapper(object):
|
||||
outcome = Build.FAILED
|
||||
|
||||
build.completed_on = datetime.datetime.now()
|
||||
build.timespent = int((build.completed_on - build.started_on).total_seconds())
|
||||
build.errors_no = errors
|
||||
build.warnings_no = warnings
|
||||
build.outcome = outcome
|
||||
@@ -92,9 +92,9 @@ class ORMWrapper(object):
|
||||
for v in vars(task_object):
|
||||
if v in task_information.keys():
|
||||
vars(task_object)[v] = task_information[v]
|
||||
# if we got covered by a setscene task, we're CACHED
|
||||
if task_object.outcome == Task.OUTCOME_COVERED and 1 == Task.objects.related_setscene(task_object).count():
|
||||
task_object.outcome = Task.OUTCOME_CACHED
|
||||
# if we got covered by a setscene task, we're SSTATE
|
||||
if task_object.outcome == Task.OUTCOME_COVERED and 1 == Task.objects.filter(task_executed=True, build = task_object.build, recipe = task_object.recipe, task_name=task_object.task_name+"_setscene").count():
|
||||
task_object.outcome = Task.OUTCOME_SSTATE
|
||||
outcome_task_setscene = Task.objects.get(task_executed=True, build = task_object.build,
|
||||
recipe = task_object.recipe, task_name=task_object.task_name+"_setscene").outcome
|
||||
if outcome_task_setscene == Task.OUTCOME_SUCCESS:
|
||||
@@ -125,11 +125,10 @@ class ORMWrapper(object):
|
||||
|
||||
return recipe_object
|
||||
|
||||
def get_update_layer_version_object(self, build_obj, layer_obj, layer_version_information):
|
||||
def get_layer_version_object(self, layer_version_information):
|
||||
|
||||
layer_version_object = Layer_Version.objects.get_or_create(
|
||||
build = build_obj,
|
||||
layer = layer_obj,
|
||||
layer = layer_version_information['layer'],
|
||||
branch = layer_version_information['branch'],
|
||||
commit = layer_version_information['commit'],
|
||||
priority = layer_version_information['priority']
|
||||
@@ -150,53 +149,21 @@ class ORMWrapper(object):
|
||||
return layer_object[0]
|
||||
|
||||
|
||||
def save_target_package_information(self, build_obj, target_obj, packagedict, pkgpnmap, recipes):
|
||||
def save_target_package_information(self, target_obj, packagedict, bldpkgs, recipes):
|
||||
for p in packagedict:
|
||||
searchname = p
|
||||
if 'OPKGN' in pkgpnmap[p].keys():
|
||||
searchname = pkgpnmap[p]['OPKGN']
|
||||
|
||||
packagedict[p]['object'], created = Package.objects.get_or_create( build = build_obj, name = searchname )
|
||||
if created:
|
||||
# package was not build in the current build, but
|
||||
# fill in everything we can from the runtime-reverse package data
|
||||
try:
|
||||
packagedict[p]['object'].recipe = recipes[pkgpnmap[p]['PN']]
|
||||
packagedict[p]['object'].version = pkgpnmap[p]['PV']
|
||||
packagedict[p]['object'].installed_name = p
|
||||
packagedict[p]['object'].revision = pkgpnmap[p]['PR']
|
||||
packagedict[p]['object'].license = pkgpnmap[p]['LICENSE']
|
||||
packagedict[p]['object'].section = pkgpnmap[p]['SECTION']
|
||||
packagedict[p]['object'].summary = pkgpnmap[p]['SUMMARY']
|
||||
packagedict[p]['object'].description = pkgpnmap[p]['DESCRIPTION']
|
||||
packagedict[p]['object'].size = int(pkgpnmap[p]['PKGSIZE'])
|
||||
|
||||
# no files recorded for this package, so save files info
|
||||
for targetpath in pkgpnmap[p]['FILES_INFO']:
|
||||
targetfilesize = pkgpnmap[p]['FILES_INFO'][targetpath]
|
||||
Package_File.objects.create( package = packagedict[p]['object'],
|
||||
path = targetpath,
|
||||
size = targetfilesize)
|
||||
except KeyError as e:
|
||||
print "Key error, package", p, "key", e
|
||||
|
||||
# save disk installed size
|
||||
packagedict[p]['object'].installed_size = packagedict[p]['size']
|
||||
packagedict[p]['object'].save()
|
||||
|
||||
Target_Installed_Package.objects.create(target = target_obj, package = packagedict[p]['object'])
|
||||
packagedict[p]['object'] = Target_Package.objects.create( target = target_obj,
|
||||
name = p,
|
||||
size = packagedict[p]['size'])
|
||||
if p in bldpkgs:
|
||||
packagedict[p]['object'].version = bldpkgs[p]['version']
|
||||
packagedict[p]['object'].recipe = recipes[bldpkgs[p]['pn']]
|
||||
packagedict[p]['object'].save()
|
||||
|
||||
for p in packagedict:
|
||||
for (px,deptype) in packagedict[p]['depends']:
|
||||
if deptype == 'depends':
|
||||
tdeptype = Package_Dependency.TYPE_TRDEPENDS
|
||||
elif deptype == 'recommends':
|
||||
tdeptype = Package_Dependency.TYPE_TRECOMMENDS
|
||||
|
||||
Package_Dependency.objects.create( package = packagedict[p]['object'],
|
||||
Target_Package_Dependency.objects.create( package = packagedict[p]['object'],
|
||||
depends_on = packagedict[px]['object'],
|
||||
dep_type = tdeptype,
|
||||
target = target_obj);
|
||||
dep_type = deptype);
|
||||
|
||||
|
||||
def create_logmessage(self, log_information):
|
||||
@@ -214,58 +181,48 @@ class ORMWrapper(object):
|
||||
|
||||
def save_build_package_information(self, build_obj, package_info, recipes):
|
||||
# create and save the object
|
||||
pname = package_info['PKG']
|
||||
if 'OPKGN' in package_info.keys():
|
||||
pname = package_info['OPKGN']
|
||||
|
||||
bp_object, created = Package.objects.get_or_create( build = build_obj,
|
||||
name = pname )
|
||||
|
||||
bp_object.installed_name = package_info['PKG']
|
||||
bp_object.recipe = recipes[package_info['PN']]
|
||||
bp_object.version = package_info['PKGV']
|
||||
bp_object.revision = package_info['PKGR']
|
||||
bp_object.summary = package_info['SUMMARY']
|
||||
bp_object.description = package_info['DESCRIPTION']
|
||||
bp_object.size = int(package_info['PKGSIZE'])
|
||||
bp_object.section = package_info['SECTION']
|
||||
bp_object.license = package_info['LICENSE']
|
||||
bp_object.save()
|
||||
|
||||
bp_object = Build_Package.objects.create( build = build_obj,
|
||||
recipe = recipes[package_info['PN']],
|
||||
name = package_info['PKG'],
|
||||
version = package_info['PKGV'],
|
||||
revision = package_info['PKGR'],
|
||||
summary = package_info['SUMMARY'],
|
||||
description = package_info['DESCRIPTION'],
|
||||
size = int(package_info['PKGSIZE']) * 1024,
|
||||
section = package_info['SECTION'],
|
||||
license = package_info['LICENSE'],
|
||||
)
|
||||
# save any attached file information
|
||||
for path in package_info['FILES_INFO']:
|
||||
fo = Package_File.objects.create( package = bp_object,
|
||||
fo = Build_File.objects.create( bpackage = bp_object,
|
||||
path = path,
|
||||
size = package_info['FILES_INFO'][path] )
|
||||
|
||||
def _po_byname(p):
|
||||
return Package.objects.get_or_create(build = build_obj, name = p)[0]
|
||||
|
||||
# save soft dependency information
|
||||
if 'RDEPENDS' in package_info and package_info['RDEPENDS']:
|
||||
for p in bb.utils.explode_deps(package_info['RDEPENDS']):
|
||||
Package_Dependency.objects.get_or_create( package = bp_object,
|
||||
depends_on = _po_byname(p), dep_type = Package_Dependency.TYPE_RDEPENDS)
|
||||
Build_Package_Dependency.objects.get_or_create( package = bp_object,
|
||||
depends_on = p, dep_type = Build_Package_Dependency.TYPE_RDEPENDS)
|
||||
if 'RPROVIDES' in package_info and package_info['RPROVIDES']:
|
||||
for p in bb.utils.explode_deps(package_info['RPROVIDES']):
|
||||
Package_Dependency.objects.get_or_create( package = bp_object,
|
||||
depends_on = _po_byname(p), dep_type = Package_Dependency.TYPE_RPROVIDES)
|
||||
Build_Package_Dependency.objects.get_or_create( package = bp_object,
|
||||
depends_on = p, dep_type = Build_Package_Dependency.TYPE_RPROVIDES)
|
||||
if 'RRECOMMENDS' in package_info and package_info['RRECOMMENDS']:
|
||||
for p in bb.utils.explode_deps(package_info['RRECOMMENDS']):
|
||||
Package_Dependency.objects.get_or_create( package = bp_object,
|
||||
depends_on = _po_byname(p), dep_type = Package_Dependency.TYPE_RRECOMMENDS)
|
||||
Build_Package_Dependency.objects.get_or_create( package = bp_object,
|
||||
depends_on = p, dep_type = Build_Package_Dependency.TYPE_RRECOMMENDS)
|
||||
if 'RSUGGESTS' in package_info and package_info['RSUGGESTS']:
|
||||
for p in bb.utils.explode_deps(package_info['RSUGGESTS']):
|
||||
Package_Dependency.objects.get_or_create( package = bp_object,
|
||||
depends_on = _po_byname(p), dep_type = Package_Dependency.TYPE_RSUGGESTS)
|
||||
Build_Package_Dependency.objects.get_or_create( package = bp_object,
|
||||
depends_on = p, dep_type = Build_Package_Dependency.TYPE_RSUGGESTS)
|
||||
if 'RREPLACES' in package_info and package_info['RREPLACES']:
|
||||
for p in bb.utils.explode_deps(package_info['RREPLACES']):
|
||||
Package_Dependency.objects.get_or_create( package = bp_object,
|
||||
depends_on = _po_byname(p), dep_type = Package_Dependency.TYPE_RREPLACES)
|
||||
Build_Package_Dependency.objects.get_or_create( package = bp_object,
|
||||
depends_on = p, dep_type = Build_Package_Dependency.TYPE_RREPLACES)
|
||||
if 'RCONFLICTS' in package_info and package_info['RCONFLICTS']:
|
||||
for p in bb.utils.explode_deps(package_info['RCONFLICTS']):
|
||||
Package_Dependency.objects.get_or_create( package = bp_object,
|
||||
depends_on = _po_byname(p), dep_type = Package_Dependency.TYPE_RCONFLICTS)
|
||||
Build_Package_Dependency.objects.get_or_create( package = bp_object,
|
||||
depends_on = p, dep_type = Build_Package_Dependency.TYPE_RCONFLICTS)
|
||||
|
||||
return bp_object
|
||||
|
||||
@@ -288,11 +245,10 @@ class ORMWrapper(object):
|
||||
variable_value = value,
|
||||
description = desc)
|
||||
for vh in vardump[k]['history']:
|
||||
if not 'documentation.conf' in vh['file']:
|
||||
VariableHistory.objects.create( variable = variable_obj,
|
||||
file_name = vh['file'],
|
||||
line_number = vh['line'],
|
||||
operation = vh['op'])
|
||||
VariableHistory.objects.create( variable = variable_obj,
|
||||
file_name = vh['file'],
|
||||
line_number = vh['line'],
|
||||
operation = vh['op'])
|
||||
|
||||
class BuildInfoHelper(object):
|
||||
""" This class gathers the build information from the server and sends it
|
||||
@@ -317,6 +273,60 @@ class BuildInfoHelper(object):
|
||||
###################
|
||||
## methods to convert event/external info into objects that the ORM layer uses
|
||||
|
||||
def _get_layer_dict(self, layer_path):
|
||||
|
||||
layer_info = {}
|
||||
layer_name = layer_path.split('/')[-1]
|
||||
layer_url = 'http://layers.openembedded.org/layerindex/layer/{layer}/'
|
||||
layer_url_name = self._get_url_map_name(layer_name)
|
||||
|
||||
layer_info['name'] = layer_name
|
||||
layer_info['local_path'] = layer_path
|
||||
layer_info['layer_index_url'] = layer_url.format(layer=layer_url_name)
|
||||
|
||||
return layer_info
|
||||
|
||||
def _get_url_map_name(self, layer_name):
|
||||
""" Some layers have a different name on openembedded.org site,
|
||||
this method returns the correct name to use in the URL
|
||||
"""
|
||||
|
||||
url_name = layer_name
|
||||
url_mapping = {'meta': 'openembedded-core'}
|
||||
|
||||
for key in url_mapping.keys():
|
||||
if key == layer_name:
|
||||
url_name = url_mapping[key]
|
||||
|
||||
return url_name
|
||||
|
||||
def _get_layer_information(self):
|
||||
|
||||
layer_info = {}
|
||||
|
||||
return layer_info
|
||||
|
||||
def _get_layer_version_information(self, layer_object):
|
||||
|
||||
layer_version_info = {}
|
||||
layer_version_info['build'] = self.internal_state['build']
|
||||
layer_version_info['layer'] = layer_object
|
||||
layer_version_info['branch'] = self._get_git_branch(layer_object.local_path)
|
||||
layer_version_info['commit'] = self._get_git_revision(layer_object.local_path)
|
||||
layer_version_info['priority'] = 0
|
||||
|
||||
return layer_version_info
|
||||
|
||||
|
||||
def _get_git_branch(self, layer_path):
|
||||
branch = subprocess.Popen("git symbolic-ref HEAD 2>/dev/null ", cwd=layer_path, shell=True, stdout=subprocess.PIPE).communicate()[0]
|
||||
branch = branch.replace('refs/heads/', '').rstrip()
|
||||
return branch
|
||||
|
||||
def _get_git_revision(self, layer_path):
|
||||
revision = subprocess.Popen("git rev-parse HEAD 2>/dev/null ", cwd=layer_path, shell=True, stdout=subprocess.PIPE).communicate()[0].rstrip()
|
||||
return revision
|
||||
|
||||
|
||||
def _get_build_information(self):
|
||||
build_info = {}
|
||||
@@ -355,7 +365,7 @@ class BuildInfoHelper(object):
|
||||
|
||||
# Heuristics: we always match recipe to the deepest layer path that
|
||||
# we can match to the recipe file path
|
||||
for bl in sorted(Layer_Version.objects.filter(build = self.internal_state['build']), reverse=True, key=_slkey):
|
||||
for bl in sorted(self.internal_state['layer_versions'], reverse=True, key=_slkey):
|
||||
if (path.startswith(bl.layer.local_path)):
|
||||
return bl
|
||||
|
||||
@@ -363,16 +373,23 @@ class BuildInfoHelper(object):
|
||||
assert False
|
||||
return None
|
||||
|
||||
def _get_recipe_information_from_taskfile(self, taskfile):
|
||||
def _get_recipe_information_from_build_event(self, event):
|
||||
|
||||
layer_version_obj = self._get_layer_version_for_path(re.split(':', taskfile)[-1])
|
||||
layer_version_obj = self._get_layer_version_for_path(re.split(':', event.taskfile)[-1])
|
||||
|
||||
recipe_info = {}
|
||||
recipe_info['layer_version'] = layer_version_obj
|
||||
recipe_info['file_path'] = re.split(':', taskfile)[-1]
|
||||
recipe_info['file_path'] = re.split(':', event.taskfile)[-1]
|
||||
|
||||
return recipe_info
|
||||
|
||||
def _get_task_build_stats(self, task_object):
|
||||
bs_path = self._get_path_information(task_object)
|
||||
for bp in bs_path: # TODO: split for each target
|
||||
task_build_stats = self._get_build_stats_from_file(bp, task_object.task_name)
|
||||
|
||||
return task_build_stats
|
||||
|
||||
def _get_path_information(self, task_object):
|
||||
build_stats_format = "{tmpdir}/buildstats/{target}-{machine}/{buildname}/{package}/"
|
||||
build_stats_path = []
|
||||
@@ -393,23 +410,53 @@ class BuildInfoHelper(object):
|
||||
|
||||
return build_stats_path
|
||||
|
||||
def _get_build_stats_from_file(self, bs_path, task_name):
|
||||
|
||||
task_bs_filename = str(bs_path) + str(task_name)
|
||||
task_bs = open(task_bs_filename, 'r')
|
||||
|
||||
cpu_usage = 0
|
||||
disk_io = 0
|
||||
startio = ''
|
||||
endio = ''
|
||||
|
||||
for line in task_bs.readlines():
|
||||
if line.startswith('CPU usage: '):
|
||||
cpu_usage = line[11:]
|
||||
elif line.startswith('EndTimeIO: '):
|
||||
endio = line[11:]
|
||||
elif line.startswith('StartTimeIO: '):
|
||||
startio = line[13:]
|
||||
|
||||
task_bs.close()
|
||||
|
||||
if startio and endio:
|
||||
disk_io = int(endio.strip('\n ')) - int(startio.strip('\n '))
|
||||
|
||||
if cpu_usage:
|
||||
cpu_usage = float(cpu_usage.strip('% \n'))
|
||||
|
||||
task_build_stats = {'cpu_usage': cpu_usage, 'disk_io': disk_io}
|
||||
|
||||
return task_build_stats
|
||||
|
||||
def _remove_redundant(self, string):
|
||||
ret = []
|
||||
for i in string.split():
|
||||
if i not in ret:
|
||||
ret.append(i)
|
||||
return " ".join(sorted(ret))
|
||||
return " ".join(ret)
|
||||
|
||||
|
||||
################################
|
||||
## external available methods to store information
|
||||
|
||||
def store_layer_info(self, event):
|
||||
layerinfos = event.data
|
||||
self.internal_state['lvs'] = {}
|
||||
for layer in layerinfos:
|
||||
self.internal_state['lvs'][self.orm_wrapper.get_update_layer_object(layerinfos[layer])] = layerinfos[layer]['version']
|
||||
|
||||
def store_layer_info(self):
|
||||
layers = self.server.runCommand(["getVariable", "BBLAYERS"])[0].strip().split(" ")
|
||||
self.internal_state['layers'] = []
|
||||
for layer_path in { l for l in layers if len(l) }:
|
||||
layer_information = self._get_layer_dict(layer_path)
|
||||
self.internal_state['layers'].append(self.orm_wrapper.get_update_layer_object(layer_information))
|
||||
|
||||
def store_started_build(self, event):
|
||||
|
||||
@@ -418,12 +465,6 @@ class BuildInfoHelper(object):
|
||||
build_obj = self.orm_wrapper.create_build_object(build_information)
|
||||
self.internal_state['build'] = build_obj
|
||||
|
||||
# save layer version information for this build
|
||||
for layer_obj in self.internal_state['lvs']:
|
||||
self.orm_wrapper.get_update_layer_version_object(build_obj, layer_obj, self.internal_state['lvs'][layer_obj])
|
||||
|
||||
del self.internal_state['lvs']
|
||||
|
||||
# create target information
|
||||
target_information = {}
|
||||
target_information['targets'] = event.getPkgs()
|
||||
@@ -431,6 +472,13 @@ class BuildInfoHelper(object):
|
||||
|
||||
self.internal_state['targets'] = self.orm_wrapper.create_target_objects(target_information)
|
||||
|
||||
# Load layer information for the build
|
||||
self.internal_state['layer_versions'] = []
|
||||
for layer_object in self.internal_state['layers']:
|
||||
layer_version_information = self._get_layer_version_information(layer_object)
|
||||
self.internal_state['layer_versions'].append(self.orm_wrapper.get_layer_version_object(layer_version_information))
|
||||
|
||||
del self.internal_state['layers']
|
||||
# Save build configuration
|
||||
self.orm_wrapper.save_build_variables(build_obj, self.server.runCommand(["getAllKeysWithFlags", ["doc", "func"]])[0])
|
||||
|
||||
@@ -442,7 +490,7 @@ class BuildInfoHelper(object):
|
||||
def store_started_task(self, event):
|
||||
identifier = event.taskfile + event.taskname
|
||||
|
||||
recipe_information = self._get_recipe_information_from_taskfile(event.taskfile)
|
||||
recipe_information = self._get_recipe_information_from_build_event(event)
|
||||
recipe = self.orm_wrapper.get_update_recipe_object(recipe_information)
|
||||
|
||||
task_information = self._get_task_information(event, recipe)
|
||||
@@ -453,40 +501,21 @@ class BuildInfoHelper(object):
|
||||
if event.reason == "covered":
|
||||
task_information['outcome'] = Task.OUTCOME_COVERED
|
||||
if event.reason == "existing":
|
||||
task_information['outcome'] = Task.OUTCOME_PREBUILT
|
||||
task_information['outcome'] = Task.OUTCOME_EXISTING
|
||||
else:
|
||||
task_information['task_executed'] = True
|
||||
if 'noexec' in vars(event) and event.noexec == True:
|
||||
task_information['task_executed'] = False
|
||||
task_information['outcome'] = Task.OUTCOME_NA
|
||||
task_information['script_type'] = Task.CODING_NA
|
||||
|
||||
# do not assign order numbers to scene tasks
|
||||
if not isinstance(event, bb.runqueue.sceneQueueTaskStarted):
|
||||
self.task_order += 1
|
||||
task_information['order'] = self.task_order
|
||||
task_information['script_type'] = Task.CODING_NOEXEC
|
||||
|
||||
self.task_order += 1
|
||||
task_information['order'] = self.task_order
|
||||
task_obj = self.orm_wrapper.get_update_task_object(task_information)
|
||||
|
||||
self.internal_state[identifier] = {'start_time': datetime.datetime.now()}
|
||||
|
||||
|
||||
def store_tasks_stats(self, event):
|
||||
for (taskfile, taskname, taskstats) in event.data:
|
||||
recipe_information = self._get_recipe_information_from_taskfile(taskfile)
|
||||
recipe = self.orm_wrapper.get_update_recipe_object(recipe_information)
|
||||
|
||||
task_information = {}
|
||||
task_information['build'] = self.internal_state['build']
|
||||
task_information['recipe'] = recipe
|
||||
task_information['task_name'] = taskname
|
||||
task_information['cpu_usage'] = taskstats['cpu_usage']
|
||||
task_information['disk_io'] = taskstats['disk_io']
|
||||
task_obj = self.orm_wrapper.get_update_task_object(task_information)
|
||||
|
||||
def update_and_store_task(self, event):
|
||||
identifier = event.taskfile + event.taskname
|
||||
recipe_information = self._get_recipe_information_from_taskfile(event.taskfile)
|
||||
recipe_information = self._get_recipe_information_from_build_event(event)
|
||||
recipe = self.orm_wrapper.get_update_recipe_object(recipe_information)
|
||||
task_information = self._get_task_information(event,recipe)
|
||||
try:
|
||||
@@ -509,22 +538,66 @@ class BuildInfoHelper(object):
|
||||
|
||||
if isinstance(event, (bb.runqueue.runQueueTaskCompleted, bb.runqueue.sceneQueueTaskCompleted)):
|
||||
task_information['outcome'] = Task.OUTCOME_SUCCESS
|
||||
task_build_stats = self._get_task_build_stats(self.orm_wrapper.get_update_task_object(task_information))
|
||||
task_information['cpu_usage'] = task_build_stats['cpu_usage']
|
||||
task_information['disk_io'] = task_build_stats['disk_io']
|
||||
del self.internal_state[identifier]
|
||||
|
||||
if isinstance(event, (bb.runqueue.runQueueTaskFailed, bb.runqueue.sceneQueueTaskFailed)):
|
||||
if isinstance(event, (bb.runqueue.runQueueTaskFailed, bb.runCommand.sceneQueueTaskFailed)):
|
||||
task_information['outcome'] = Task.OUTCOME_FAILED
|
||||
del self.internal_state[identifier]
|
||||
|
||||
self.orm_wrapper.get_update_task_object(task_information)
|
||||
|
||||
|
||||
def store_target_package_data(self, event):
|
||||
# for all image targets
|
||||
def read_target_package_dep_data(self, event):
|
||||
# for all targets
|
||||
for target in self.internal_state['targets']:
|
||||
if target.is_image:
|
||||
pkgdata = event.data['pkgdata']
|
||||
imgdata = event.data['imgdata'][target.target]
|
||||
self.orm_wrapper.save_target_package_information(self.internal_state['build'], target, imgdata, pkgdata, self.internal_state['recipes'])
|
||||
# verify that we have something to read
|
||||
if not target.is_image or not self.has_build_history:
|
||||
print "not collecting package info ", target.is_image, self.has_build_history
|
||||
break
|
||||
|
||||
# TODO this is a temporary replication of the code in buildhistory.bbclass
|
||||
# This MUST be changed to query the actual BUILD_DIR_IMAGE in the target context when
|
||||
# the capability will be implemented in Bitbake
|
||||
|
||||
MACHINE_ARCH, error = self.server.runCommand(['getVariable', 'MACHINE_ARCH'])
|
||||
TCLIBC, error = self.server.runCommand(['getVariable', 'TCLIBC'])
|
||||
BUILDHISTORY_DIR, error = self.server.runCommand(['getVariable', 'BUILDHISTORY_DIR'])
|
||||
BUILDHISTORY_DIR_IMAGE = "%s/images/%s/%s/%s" % (BUILDHISTORY_DIR, MACHINE_ARCH, TCLIBC, target.target)
|
||||
|
||||
self.internal_state['packages'] = {}
|
||||
|
||||
with open("%s/installed-package-sizes.txt" % BUILDHISTORY_DIR_IMAGE, "r") as fin:
|
||||
for line in fin:
|
||||
line = line.rstrip(";")
|
||||
psize, px = line.split("\t")
|
||||
punit, pname = px.split(" ")
|
||||
self.internal_state['packages'][pname.strip()] = {'size':int(psize)*1024, 'depends' : []}
|
||||
|
||||
with open("%s/depends.dot" % BUILDHISTORY_DIR_IMAGE, "r") as fin:
|
||||
p = re.compile(r' -> ')
|
||||
dot = re.compile(r'.*style=dotted')
|
||||
for line in fin:
|
||||
line = line.rstrip(';')
|
||||
linesplit = p.split(line)
|
||||
if len(linesplit) == 2:
|
||||
pname = linesplit[0].rstrip('"').strip('"')
|
||||
dependsname = linesplit[1].split(" ")[0].strip().strip(";").strip('"').rstrip('"')
|
||||
deptype = Target_Package_Dependency.TYPE_DEPENDS
|
||||
if dot.match(line):
|
||||
deptype = Target_Package_Dependency.TYPE_RECOMMENDS
|
||||
if not pname in self.internal_state['packages']:
|
||||
self.internal_state['packages'][pname] = {'size': 0, 'depends' : []}
|
||||
if not dependsname in self.internal_state['packages']:
|
||||
self.internal_state['packages'][dependsname] = {'size': 0, 'depends' : []}
|
||||
self.internal_state['packages'][pname]['depends'].append((dependsname, deptype))
|
||||
|
||||
self.orm_wrapper.save_target_package_information(target,
|
||||
self.internal_state['packages'],
|
||||
self.internal_state['bldpkgs'], self.internal_state['recipes'])
|
||||
|
||||
|
||||
def store_dependency_information(self, event):
|
||||
# save layer version priorities
|
||||
@@ -536,6 +609,11 @@ class BuildInfoHelper(object):
|
||||
layer_version_obj.priority = priority
|
||||
layer_version_obj.save()
|
||||
|
||||
# save build time package information
|
||||
self.internal_state['bldpkgs'] = {}
|
||||
for pkg in event._depgraph['packages']:
|
||||
self.internal_state['bldpkgs'][pkg] = event._depgraph['packages'][pkg]
|
||||
|
||||
# save recipe information
|
||||
self.internal_state['recipes'] = {}
|
||||
for pn in event._depgraph['pn']:
|
||||
@@ -547,7 +625,7 @@ class BuildInfoHelper(object):
|
||||
|
||||
recipe_info = {}
|
||||
recipe_info['name'] = pn
|
||||
recipe_info['version'] = event._depgraph['pn'][pn]['version'].lstrip(":")
|
||||
recipe_info['version'] = event._depgraph['pn'][pn]['version']
|
||||
recipe_info['layer_version'] = layer_version_obj
|
||||
recipe_info['summary'] = event._depgraph['pn'][pn]['summary']
|
||||
recipe_info['license'] = event._depgraph['pn'][pn]['license']
|
||||
|
||||
@@ -185,7 +185,6 @@ class BuildDetailsPage (HobPage):
|
||||
def show_issues(self):
|
||||
self.num_of_issues += 1
|
||||
self.notebook.show_indicator_icon("Issues", self.num_of_issues)
|
||||
self.notebook.queue_draw()
|
||||
|
||||
def reset_issues(self):
|
||||
self.num_of_issues = 0
|
||||
@@ -424,7 +423,7 @@ class BuildDetailsPage (HobPage):
|
||||
if "recipes" in action:
|
||||
self.builder.show_recipes()
|
||||
elif "packages" in action:
|
||||
self.builder.show_packages()
|
||||
self.builder.show_packages(ask=False)
|
||||
elif "image" in action:
|
||||
self.builder.show_configuration()
|
||||
|
||||
|
||||
@@ -227,20 +227,14 @@ class Configuration:
|
||||
handler.set_var_in_file("DEPENDS", self.selected_recipes, "local.conf")
|
||||
handler.set_var_in_file("IMAGE_INSTALL", self.user_selected_packages, "local.conf")
|
||||
# proxy
|
||||
if self.enable_proxy == True:
|
||||
handler.set_var_in_file("http_proxy", self.combine_proxy("http"), "local.conf")
|
||||
handler.set_var_in_file("https_proxy", self.combine_proxy("https"), "local.conf")
|
||||
handler.set_var_in_file("ftp_proxy", self.combine_proxy("ftp"), "local.conf")
|
||||
handler.set_var_in_file("all_proxy", self.combine_proxy("socks"), "local.conf")
|
||||
handler.set_var_in_file("CVS_PROXY_HOST", self.combine_host_only("cvs"), "local.conf")
|
||||
handler.set_var_in_file("CVS_PROXY_PORT", self.combine_port_only("cvs"), "local.conf")
|
||||
else:
|
||||
handler.set_var_in_file("http_proxy", "", "local.conf")
|
||||
handler.set_var_in_file("https_proxy", "", "local.conf")
|
||||
handler.set_var_in_file("ftp_proxy", "", "local.conf")
|
||||
handler.set_var_in_file("all_proxy", "", "local.conf")
|
||||
handler.set_var_in_file("CVS_PROXY_HOST", "", "local.conf")
|
||||
handler.set_var_in_file("CVS_PROXY_PORT", "", "local.conf")
|
||||
handler.set_var_in_file("enable_proxy", self.enable_proxy, "local.conf")
|
||||
handler.set_var_in_file("use_same_proxy", self.same_proxy, "local.conf")
|
||||
handler.set_var_in_file("http_proxy", self.combine_proxy("http"), "local.conf")
|
||||
handler.set_var_in_file("https_proxy", self.combine_proxy("https"), "local.conf")
|
||||
handler.set_var_in_file("ftp_proxy", self.combine_proxy("ftp"), "local.conf")
|
||||
handler.set_var_in_file("all_proxy", self.combine_proxy("socks"), "local.conf")
|
||||
handler.set_var_in_file("CVS_PROXY_HOST", self.combine_host_only("cvs"), "local.conf")
|
||||
handler.set_var_in_file("CVS_PROXY_PORT", self.combine_port_only("cvs"), "local.conf")
|
||||
|
||||
def __str__(self):
|
||||
s = "VERSION: '%s', BBLAYERS: '%s', MACHINE: '%s', DISTRO: '%s', DL_DIR: '%s'," % \
|
||||
@@ -534,9 +528,9 @@ class Builder(gtk.Window):
|
||||
self.generate_configuration()
|
||||
|
||||
def update_config_async(self):
|
||||
self.switch_page(self.MACHINE_SELECTION)
|
||||
self.set_user_config()
|
||||
self.generate_configuration()
|
||||
self.switch_page(self.MACHINE_SELECTION)
|
||||
|
||||
def sanity_check(self):
|
||||
self.handler.trigger_sanity_check()
|
||||
@@ -710,6 +704,7 @@ class Builder(gtk.Window):
|
||||
self.set_user_config_proxies()
|
||||
|
||||
def set_user_config(self):
|
||||
self.handler.reset_cooker()
|
||||
# set bb layers
|
||||
self.handler.set_bblayers(self.configuration.layers)
|
||||
# set local configuration
|
||||
@@ -799,8 +794,8 @@ class Builder(gtk.Window):
|
||||
self.generate_image_async(True)
|
||||
|
||||
def show_error_dialog(self, msg):
|
||||
lbl = "<b>Hob found an error</b>"
|
||||
dialog = CrumbsMessageDialog(self, lbl, gtk.MESSAGE_ERROR, msg)
|
||||
lbl = "<b>Hob found an error</b>\n"
|
||||
dialog = CrumbsMessageDialog(self, lbl, gtk.STOCK_DIALOG_ERROR, msg)
|
||||
button = dialog.add_button("Close", gtk.RESPONSE_OK)
|
||||
HobButton.style_button(button)
|
||||
response = dialog.run()
|
||||
@@ -816,9 +811,10 @@ class Builder(gtk.Window):
|
||||
dialog.destroy()
|
||||
|
||||
def show_network_error_dialog(self):
|
||||
lbl = "<b>Hob cannot connect to the network</b>"
|
||||
msg = msg + "Please check your network connection. If you are using a proxy server, please make sure it is configured correctly."
|
||||
dialog = CrumbsMessageDialog(self, lbl, gtk.MESSAGE_ERROR, msg)
|
||||
lbl = "<b>Hob cannot connect to the network</b>\n"
|
||||
msg = "Please check your network connection. If you are using a proxy server, please make sure it is configured correctly."
|
||||
lbl = lbl + "%s\n\n" % glib.markup_escape_text(msg)
|
||||
dialog = CrumbsMessageDialog(self, lbl, gtk.STOCK_DIALOG_ERROR)
|
||||
button = dialog.add_button("Close", gtk.RESPONSE_OK)
|
||||
HobButton.style_button(button)
|
||||
button = dialog.add_button("Proxy settings", gtk.RESPONSE_CANCEL)
|
||||
@@ -1041,7 +1037,7 @@ class Builder(gtk.Window):
|
||||
self.build_failed()
|
||||
|
||||
def handler_no_provider_cb(self, running_build, msg):
|
||||
dialog = CrumbsMessageDialog(self, glib.markup_escape_text(msg), gtk.MESSAGE_INFO)
|
||||
dialog = CrumbsMessageDialog(self, glib.markup_escape_text(msg), gtk.STOCK_DIALOG_INFO)
|
||||
button = dialog.add_button("Close", gtk.RESPONSE_OK)
|
||||
HobButton.style_button(button)
|
||||
dialog.run()
|
||||
@@ -1104,10 +1100,9 @@ class Builder(gtk.Window):
|
||||
def build_packages(self):
|
||||
_, all_recipes = self.recipe_model.get_selected_recipes()
|
||||
if not all_recipes:
|
||||
lbl = "<b>No selections made</b>"
|
||||
msg = "You have not made any selections"
|
||||
msg = msg + " so there isn't anything to bake at this time."
|
||||
dialog = CrumbsMessageDialog(self, lbl, gtk.MESSAGE_INFO, msg)
|
||||
lbl = "<b>No selections made</b>\nYou have not made any selections"
|
||||
lbl = lbl + " so there isn't anything to bake at this time."
|
||||
dialog = CrumbsMessageDialog(self, lbl, gtk.STOCK_DIALOG_INFO)
|
||||
button = dialog.add_button("Close", gtk.RESPONSE_OK)
|
||||
HobButton.style_button(button)
|
||||
dialog.run()
|
||||
@@ -1118,10 +1113,9 @@ class Builder(gtk.Window):
|
||||
def build_image(self):
|
||||
selected_packages = self.package_model.get_selected_packages()
|
||||
if not selected_packages:
|
||||
lbl = "<b>No selections made</b>"
|
||||
msg = "You have not made any selections"
|
||||
msg = msg + " so there isn't anything to bake at this time."
|
||||
dialog = CrumbsMessageDialog(self, lbl, gtk.MESSAGE_INFO, msg)
|
||||
lbl = "<b>No selections made</b>\nYou have not made any selections"
|
||||
lbl = lbl + " so there isn't anything to bake at this time."
|
||||
dialog = CrumbsMessageDialog(self, lbl, gtk.STOCK_DIALOG_INFO)
|
||||
button = dialog.add_button("Close", gtk.RESPONSE_OK)
|
||||
HobButton.style_button(button)
|
||||
dialog.run()
|
||||
@@ -1135,10 +1129,9 @@ class Builder(gtk.Window):
|
||||
|
||||
# If no base image and no selected packages don't build anything
|
||||
if not (selected_packages or selected_image != self.recipe_model.__custom_image__):
|
||||
lbl = "<b>No selections made</b>"
|
||||
msg = "You have not made any selections"
|
||||
msg = msg + " so there isn't anything to bake at this time."
|
||||
dialog = CrumbsMessageDialog(self, lbl, gtk.MESSAGE_INFO, msg)
|
||||
lbl = "<b>No selections made</b>\nYou have not made any selections"
|
||||
lbl = lbl + " so there isn't anything to bake at this time."
|
||||
dialog = CrumbsMessageDialog(self, lbl, gtk.STOCK_DIALOG_INFO)
|
||||
button = dialog.add_button("Close", gtk.RESPONSE_OK)
|
||||
HobButton.style_button(button)
|
||||
dialog.run()
|
||||
@@ -1222,9 +1215,8 @@ class Builder(gtk.Window):
|
||||
response = dialog.run()
|
||||
if response == gtk.RESPONSE_YES:
|
||||
if not dialog.image_names:
|
||||
lbl = "<b>No selections made</b>"
|
||||
msg = "You have not made any selections"
|
||||
crumbs_dialog = CrumbsMessageDialog(self, lbl, gtk.MESSAGE_INFO, msg)
|
||||
lbl = "<b>No selections made</b>\nYou have not made any selections"
|
||||
crumbs_dialog = CrumbsMessageDialog(self, lbl, gtk.STOCK_DIALOG_INFO)
|
||||
button = crumbs_dialog.add_button("Close", gtk.RESPONSE_OK)
|
||||
HobButton.style_button(button)
|
||||
crumbs_dialog.run()
|
||||
@@ -1311,7 +1303,7 @@ class Builder(gtk.Window):
|
||||
def deploy_image(self, image_name):
|
||||
if not image_name:
|
||||
lbl = "<b>Please select an image to deploy.</b>"
|
||||
dialog = CrumbsMessageDialog(self, lbl, gtk.MESSAGE_INFO)
|
||||
dialog = CrumbsMessageDialog(self, lbl, gtk.STOCK_DIALOG_INFO)
|
||||
button = dialog.add_button("Close", gtk.RESPONSE_OK)
|
||||
HobButton.style_button(button)
|
||||
dialog.run()
|
||||
@@ -1357,8 +1349,8 @@ class Builder(gtk.Window):
|
||||
|
||||
def runqemu_image(self, image_name, kernel_name):
|
||||
if not image_name or not kernel_name:
|
||||
lbl = "<b>Please select %s to launch in QEMU.</b>" % ("a kernel" if image_name else "an image")
|
||||
dialog = CrumbsMessageDialog(self, lbl, gtk.MESSAGE_INFO)
|
||||
lbl = "<b>Please select an %s to launch in QEMU.</b>" % ("kernel" if image_name else "image")
|
||||
dialog = CrumbsMessageDialog(self, lbl, gtk.STOCK_DIALOG_INFO)
|
||||
button = dialog.add_button("Close", gtk.RESPONSE_OK)
|
||||
HobButton.style_button(button)
|
||||
dialog.run()
|
||||
@@ -1379,23 +1371,38 @@ class Builder(gtk.Window):
|
||||
cmdline += "runqemu " + kernel_path + " " + image_path + "\"\'"
|
||||
subprocess.Popen(shlex.split(cmdline))
|
||||
else:
|
||||
lbl = "<b>Path error</b>"
|
||||
msg = "One of your paths is wrong,"
|
||||
msg = msg + " please make sure the following paths exist:\n"
|
||||
msg = msg + "image path:" + image_path + "\n"
|
||||
msg = msg + "kernel path:" + kernel_path + "\n"
|
||||
msg = msg + "source environment path:" + source_env_path + "\n"
|
||||
msg = msg + "tmp path: " + tmp_path + "."
|
||||
msg = msg + "You may be missing either xterm or vte for terminal services."
|
||||
dialog = CrumbsMessageDialog(self, lbl, gtk.MESSAGE_ERROR, msg)
|
||||
lbl = "<b>Path error</b>\nOne of your paths is wrong,"
|
||||
lbl = lbl + " please make sure the following paths exist:\n"
|
||||
lbl = lbl + "image path:" + image_path + "\n"
|
||||
lbl = lbl + "kernel path:" + kernel_path + "\n"
|
||||
lbl = lbl + "source environment path:" + source_env_path + "\n"
|
||||
lbl = lbl + "tmp path: " + tmp_path + "."
|
||||
lbl = lbl + "You may be missing either xterm or vte for terminal services."
|
||||
dialog = CrumbsMessageDialog(self, lbl, gtk.STOCK_DIALOG_ERROR)
|
||||
button = dialog.add_button("Close", gtk.RESPONSE_OK)
|
||||
HobButton.style_button(button)
|
||||
dialog.run()
|
||||
dialog.destroy()
|
||||
|
||||
def show_packages(self):
|
||||
self.package_details_page.refresh_tables()
|
||||
self.switch_page(self.PACKAGE_SELECTION)
|
||||
def show_packages(self, ask=True):
|
||||
_, selected_recipes = self.recipe_model.get_selected_recipes()
|
||||
if selected_recipes and ask:
|
||||
lbl = "<b>Package list may be incomplete!</b>\nDo you want to build selected recipes"
|
||||
lbl = lbl + " to get a full list or just view the existing packages?"
|
||||
dialog = CrumbsMessageDialog(self, lbl, gtk.STOCK_DIALOG_INFO)
|
||||
button = dialog.add_button("View packages", gtk.RESPONSE_NO)
|
||||
HobAltButton.style_button(button)
|
||||
button = dialog.add_button("Build packages", gtk.RESPONSE_YES)
|
||||
HobButton.style_button(button)
|
||||
dialog.set_default_response(gtk.RESPONSE_YES)
|
||||
response = dialog.run()
|
||||
dialog.destroy()
|
||||
if response == gtk.RESPONSE_YES:
|
||||
self.generate_packages_async(True)
|
||||
else:
|
||||
self.switch_page(self.PACKAGE_SELECTION)
|
||||
else:
|
||||
self.switch_page(self.PACKAGE_SELECTION)
|
||||
|
||||
def show_recipes(self):
|
||||
self.switch_page(self.RECIPE_SELECTION)
|
||||
@@ -1408,28 +1415,26 @@ class Builder(gtk.Window):
|
||||
|
||||
def stop_build(self):
|
||||
if self.stopping:
|
||||
lbl = "<b>Force Stop build?</b>"
|
||||
msg = "You've already selected Stop once,"
|
||||
msg = msg + " would you like to 'Force Stop' the build?\n\n"
|
||||
msg = msg + "This will stop the build as quickly as possible but may"
|
||||
msg = msg + " well leave your build directory in an unusable state"
|
||||
msg = msg + " that requires manual steps to fix."
|
||||
dialog = CrumbsMessageDialog(self, lbl, gtk.MESSAGE_WARNING, msg)
|
||||
lbl = "<b>Force Stop build?</b>\nYou've already selected Stop once,"
|
||||
lbl = lbl + " would you like to 'Force Stop' the build?\n\n"
|
||||
lbl = lbl + "This will stop the build as quickly as possible but may"
|
||||
lbl = lbl + " well leave your build directory in an unusable state"
|
||||
lbl = lbl + " that requires manual steps to fix.\n"
|
||||
dialog = CrumbsMessageDialog(self, lbl, gtk.STOCK_DIALOG_WARNING)
|
||||
button = dialog.add_button("Cancel", gtk.RESPONSE_CANCEL)
|
||||
HobAltButton.style_button(button)
|
||||
button = dialog.add_button("Force Stop", gtk.RESPONSE_YES)
|
||||
HobButton.style_button(button)
|
||||
else:
|
||||
lbl = "<b>Stop build?</b>"
|
||||
msg = "Are you sure you want to stop this"
|
||||
msg = msg + " build?\n\n'Stop' will stop the build as soon as all in"
|
||||
msg = msg + " progress build tasks are finished. However if a"
|
||||
msg = msg + " lengthy compilation phase is in progress this may take"
|
||||
msg = msg + " some time.\n\n"
|
||||
msg = msg + "'Force Stop' will stop the build as quickly as"
|
||||
msg = msg + " possible but may well leave your build directory in an"
|
||||
msg = msg + " unusable state that requires manual steps to fix."
|
||||
dialog = CrumbsMessageDialog(self, lbl, gtk.MESSAGE_WARNING, msg)
|
||||
lbl = "<b>Stop build?</b>\n\nAre you sure you want to stop this"
|
||||
lbl = lbl + " build?\n\n'Stop' will stop the build as soon as all in"
|
||||
lbl = lbl + " progress build tasks are finished. However if a"
|
||||
lbl = lbl + " lengthy compilation phase is in progress this may take"
|
||||
lbl = lbl + " some time.\n\n"
|
||||
lbl = lbl + "'Force Stop' will stop the build as quickly as"
|
||||
lbl = lbl + " possible but may well leave your build directory in an"
|
||||
lbl = lbl + " unusable state that requires manual steps to fix."
|
||||
dialog = CrumbsMessageDialog(self, lbl, gtk.STOCK_DIALOG_WARNING)
|
||||
button = dialog.add_button("Cancel", gtk.RESPONSE_CANCEL)
|
||||
HobAltButton.style_button(button)
|
||||
button = dialog.add_button("Force stop", gtk.RESPONSE_YES)
|
||||
|
||||
@@ -183,9 +183,8 @@ class AdvancedSettingsDialog (CrumbsDialog, SettingsUIHelper):
|
||||
self.set_save_button_state()
|
||||
if self.get_num_checked_image_types() == 0:
|
||||
# Show an error dialog
|
||||
lbl = "<b>Select an image type</b>"
|
||||
msg = "You need to select at least one image type."
|
||||
dialog = CrumbsMessageDialog(self, lbl, gtk.MESSAGE_WARNING, msg)
|
||||
lbl = "<b>Select an image type</b>\n\nYou need to select at least one image type."
|
||||
dialog = CrumbsMessageDialog(self, lbl, gtk.STOCK_DIALOG_WARNING)
|
||||
button = dialog.add_button("OK", gtk.RESPONSE_OK)
|
||||
HobButton.style_button(button)
|
||||
response = dialog.run()
|
||||
|
||||
@@ -31,28 +31,51 @@ BitBake GUI's
|
||||
In summary: spacing = 12px, border-width = 6px
|
||||
"""
|
||||
|
||||
class CrumbsMessageDialog(gtk.MessageDialog):
|
||||
class CrumbsMessageDialog(CrumbsDialog):
|
||||
"""
|
||||
A GNOME HIG compliant dialog widget.
|
||||
Add buttons with gtk.Dialog.add_button or gtk.Dialog.add_buttons
|
||||
"""
|
||||
def __init__(self, parent = None, label="", dialog_type = gtk.MESSAGE_QUESTION, msg=""):
|
||||
super(CrumbsMessageDialog, self).__init__(None,
|
||||
gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
|
||||
dialog_type,
|
||||
gtk.BUTTONS_NONE,
|
||||
None)
|
||||
def __init__(self, parent=None, label="", icon=gtk.STOCK_INFO, msg=""):
|
||||
super(CrumbsMessageDialog, self).__init__("", parent, gtk.DIALOG_MODAL)
|
||||
|
||||
self.set_skip_taskbar_hint(False)
|
||||
self.set_border_width(6)
|
||||
self.vbox.set_property("spacing", 12)
|
||||
self.action_area.set_property("spacing", 12)
|
||||
self.action_area.set_property("border-width", 6)
|
||||
|
||||
self.set_markup(label)
|
||||
first_column = gtk.HBox(spacing=12)
|
||||
first_column.set_property("border-width", 6)
|
||||
first_column.show()
|
||||
self.vbox.add(first_column)
|
||||
|
||||
if 0 <= len(msg) < 300:
|
||||
self.format_secondary_markup(msg)
|
||||
self.icon = gtk.Image()
|
||||
# We have our own Info icon which should be used in preference of the stock icon
|
||||
self.icon_chk = HobIconChecker()
|
||||
self.icon.set_from_stock(self.icon_chk.check_stock_icon(icon), gtk.ICON_SIZE_DIALOG)
|
||||
self.icon.set_property("yalign", 0.00)
|
||||
self.icon.show()
|
||||
first_column.pack_start(self.icon, expand=False, fill=True, padding=0)
|
||||
|
||||
if 0 <= len(msg) < 200:
|
||||
lbl = label + "%s" % glib.markup_escape_text(msg)
|
||||
self.label_short = gtk.Label()
|
||||
self.label_short.set_use_markup(True)
|
||||
self.label_short.set_line_wrap(True)
|
||||
self.label_short.set_markup(lbl)
|
||||
self.label_short.set_property("yalign", 0.00)
|
||||
self.label_short.show()
|
||||
first_column.add(self.label_short)
|
||||
else:
|
||||
vbox = self.get_message_area()
|
||||
vbox.set_border_width(1)
|
||||
vbox.set_property("spacing", 12)
|
||||
second_row = gtk.VBox(spacing=12)
|
||||
second_row.set_property("border-width", 6)
|
||||
self.label_long = gtk.Label()
|
||||
self.label_long.set_use_markup(True)
|
||||
self.label_long.set_line_wrap(True)
|
||||
self.label_long.set_markup(label)
|
||||
self.label_long.set_alignment(0.0, 0.0)
|
||||
second_row.pack_start(self.label_long, expand=False, fill=False, padding=0)
|
||||
self.label_long.show()
|
||||
self.textWindow = gtk.ScrolledWindow()
|
||||
self.textWindow.set_shadow_type(gtk.SHADOW_IN)
|
||||
self.textWindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
|
||||
@@ -66,5 +89,7 @@ class CrumbsMessageDialog(gtk.MessageDialog):
|
||||
self.msgView.set_buffer(self.buf)
|
||||
self.textWindow.add(self.msgView)
|
||||
self.msgView.show()
|
||||
vbox.add(self.textWindow)
|
||||
second_row.add(self.textWindow)
|
||||
self.textWindow.show()
|
||||
first_column.add(second_row)
|
||||
second_row.show()
|
||||
|
||||
@@ -160,7 +160,6 @@ class DeployImageDialog (CrumbsDialog):
|
||||
def response_cb(self, dialog, response_id):
|
||||
if response_id == gtk.RESPONSE_YES:
|
||||
lbl = ''
|
||||
msg = ''
|
||||
combo_item = self.usb_combo.get_active_text()
|
||||
if combo_item and combo_item != self.__dummy_usb__ and self.image_path:
|
||||
cmdline = bb.ui.crumbs.utils.which_terminal()
|
||||
@@ -173,18 +172,15 @@ class DeployImageDialog (CrumbsDialog):
|
||||
if int(tmpfile.readline().strip()) == 0:
|
||||
lbl = "<b>Deploy image successfully.</b>"
|
||||
else:
|
||||
lbl = "<b>Failed to deploy image.</b>"
|
||||
msg = "Please check image <b>%s</b> exists and USB device <b>%s</b> is writable." % (self.image_path, combo_item)
|
||||
lbl = "<b>Failed to deploy image.</b>\nPlease check image <b>%s</b> exists and USB device <b>%s</b> is writable." % (self.image_path, combo_item)
|
||||
tmpfile.close()
|
||||
else:
|
||||
if not self.image_path:
|
||||
lbl = "<b>No selection made.</b>"
|
||||
msg = "You have not selected an image to deploy."
|
||||
lbl = "<b>No selection made.</b>\nYou have not selected an image to deploy."
|
||||
else:
|
||||
lbl = "<b>No selection made.</b>"
|
||||
msg = "You have not selected a USB device."
|
||||
lbl = "<b>No selection made.</b>\nYou have not selected a USB device."
|
||||
if len(lbl):
|
||||
crumbs_dialog = CrumbsMessageDialog(self, lbl, gtk.MESSAGE_INFO, msg)
|
||||
crumbs_dialog = CrumbsMessageDialog(self, lbl, gtk.STOCK_DIALOG_INFO)
|
||||
button = crumbs_dialog.add_button("Close", gtk.RESPONSE_OK)
|
||||
HobButton.style_button(button)
|
||||
crumbs_dialog.run()
|
||||
|
||||
@@ -92,8 +92,7 @@ class LayerSelectionDialog (CrumbsDialog):
|
||||
path = dialog.get_filename()
|
||||
dialog.destroy()
|
||||
|
||||
lbl = "<b>Error</b>"
|
||||
msg = "Unable to load layer <i>%s</i> because " % path
|
||||
lbl = "<b>Error</b>\nUnable to load layer <i>%s</i> because " % path
|
||||
if response == gtk.RESPONSE_YES:
|
||||
import os
|
||||
import os.path
|
||||
@@ -104,15 +103,15 @@ class LayerSelectionDialog (CrumbsDialog):
|
||||
it = layer_store.iter_next(it)
|
||||
|
||||
if not path:
|
||||
msg += "it is an invalid path."
|
||||
lbl += "it is an invalid path."
|
||||
elif not os.path.exists(path+"/conf/layer.conf"):
|
||||
msg += "there is no layer.conf inside the directory."
|
||||
lbl += "there is no layer.conf inside the directory."
|
||||
elif path in layers:
|
||||
msg += "it is already in loaded layers."
|
||||
lbl += "it is already in loaded layers."
|
||||
else:
|
||||
layer_store.append([path])
|
||||
return
|
||||
dialog = CrumbsMessageDialog(parent, lbl, gtk.MESSAGE_ERROR, msg)
|
||||
dialog = CrumbsMessageDialog(parent, lbl)
|
||||
dialog.add_button(gtk.STOCK_CLOSE, gtk.RESPONSE_OK)
|
||||
response = dialog.run()
|
||||
dialog.destroy()
|
||||
@@ -133,13 +132,12 @@ class LayerSelectionDialog (CrumbsDialog):
|
||||
tree_selection.set_mode(gtk.SELECTION_SINGLE)
|
||||
|
||||
# Allow enable drag and drop of rows including row move
|
||||
dnd_internal_target = ''
|
||||
dnd_targets = [(dnd_internal_target, gtk.TARGET_SAME_WIDGET, 0)]
|
||||
layer_tv.enable_model_drag_source( gtk.gdk.BUTTON1_MASK,
|
||||
dnd_targets,
|
||||
gtk.gdk.ACTION_MOVE)
|
||||
layer_tv.enable_model_drag_dest(dnd_targets,
|
||||
self.TARGETS,
|
||||
gtk.gdk.ACTION_DEFAULT|
|
||||
gtk.gdk.ACTION_MOVE)
|
||||
layer_tv.enable_model_drag_dest(self.TARGETS,
|
||||
gtk.gdk.ACTION_DEFAULT)
|
||||
layer_tv.connect("drag_data_get", self.drag_data_get_cb)
|
||||
layer_tv.connect("drag_data_received", self.drag_data_received_cb)
|
||||
|
||||
|
||||
@@ -105,14 +105,13 @@ class PropertyDialog(CrumbsDialog):
|
||||
|
||||
def create_package_visual_elements(self):
|
||||
|
||||
import json
|
||||
|
||||
name = self.properties['name']
|
||||
binb = self.properties['binb']
|
||||
size = self.properties['size']
|
||||
recipe = self.properties['recipe']
|
||||
file_list = json.loads(self.properties['files_list'])
|
||||
file_list = self.properties['files_list']
|
||||
|
||||
file_list = file_list.strip("{}'")
|
||||
files_temp = ''
|
||||
paths_temp = ''
|
||||
files_binb = []
|
||||
@@ -181,43 +180,58 @@ class PropertyDialog(CrumbsDialog):
|
||||
|
||||
#################################### FILES BROUGHT BY PACKAGES ###################################
|
||||
|
||||
if file_list:
|
||||
if file_list != '':
|
||||
|
||||
self.textWindow = gtk.ScrolledWindow()
|
||||
self.textWindow.set_shadow_type(gtk.SHADOW_IN)
|
||||
self.textWindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
|
||||
self.textWindow.set_size_request(100, 170)
|
||||
|
||||
packagefiles_store = gtk.ListStore(str)
|
||||
sstatemirrors_store = gtk.ListStore(str)
|
||||
|
||||
self.packagefiles_tv = gtk.TreeView()
|
||||
self.packagefiles_tv.set_rules_hint(True)
|
||||
self.packagefiles_tv.set_headers_visible(True)
|
||||
self.textWindow.add(self.packagefiles_tv)
|
||||
self.sstatemirrors_tv = gtk.TreeView()
|
||||
self.sstatemirrors_tv.set_rules_hint(True)
|
||||
self.sstatemirrors_tv.set_headers_visible(True)
|
||||
self.textWindow.add(self.sstatemirrors_tv)
|
||||
|
||||
self.cell1 = gtk.CellRendererText()
|
||||
col1 = gtk.TreeViewColumn('Package files', self.cell1)
|
||||
col1.set_cell_data_func(self.cell1, self.regex_field)
|
||||
self.packagefiles_tv.append_column(col1)
|
||||
self.sstatemirrors_tv.append_column(col1)
|
||||
|
||||
items = file_list.keys()
|
||||
items.sort()
|
||||
for item in items:
|
||||
fullpath = item
|
||||
while len(item) > 35:
|
||||
item = item[:len(item)/2] + "" + item[len(item)/2+1:]
|
||||
if len(item) == 35:
|
||||
item = item[:len(item)/2] + "..." + item[len(item)/2+3:]
|
||||
self.tooltip_items[item] = fullpath
|
||||
for items in file_list.split(']'):
|
||||
if len(items) > 1:
|
||||
paths_temp = items.split(":")[0]
|
||||
paths_binb.append(paths_temp.strip(" ,'"))
|
||||
files_temp = items.split(":")[1]
|
||||
files_binb.append(files_temp.strip(" ['"))
|
||||
|
||||
packagefiles_store.append([str(item)])
|
||||
unsorted_list = []
|
||||
|
||||
for items in range(len(paths_binb)):
|
||||
if len(files_binb[items]) > 1:
|
||||
for aduse in (files_binb[items].split(",")):
|
||||
unsorted_list.append(paths_binb[items].split(name)[len(paths_binb[items].split(name))-1] + '/' + aduse.strip(" '"))
|
||||
|
||||
|
||||
unsorted_list.sort()
|
||||
for items in unsorted_list:
|
||||
temp = items
|
||||
while len(items) > 35:
|
||||
items = items[:len(items)/2] + "" + items[len(items)/2+1:]
|
||||
if len(items) == 35:
|
||||
items = items[:len(items)/2] + "..." + items[len(items)/2+3:]
|
||||
self.tooltip_items[items] = temp
|
||||
|
||||
self.packagefiles_tv.set_model(packagefiles_store)
|
||||
sstatemirrors_store.append([str(items)])
|
||||
|
||||
|
||||
self.sstatemirrors_tv.set_model(sstatemirrors_store)
|
||||
|
||||
tips = gtk.Tooltips()
|
||||
tips.set_tip(self.packagefiles_tv, "")
|
||||
self.packagefiles_tv.connect("motion-notify-event", self.treeViewTooltip, tips, 0)
|
||||
self.packagefiles_tv.set_events(gtk.gdk.POINTER_MOTION_MASK)
|
||||
tips.set_tip(self.sstatemirrors_tv, "")
|
||||
self.sstatemirrors_tv.connect("motion-notify-event", self.treeViewTooltip, tips, 0)
|
||||
self.sstatemirrors_tv.set_events(gtk.gdk.POINTER_MOTION_MASK)
|
||||
|
||||
self.vbox.add(self.textWindow)
|
||||
|
||||
|
||||
@@ -146,11 +146,12 @@ class SaveImageDialog (CrumbsDialog):
|
||||
self.show_invalid_input_error_dialog()
|
||||
|
||||
def show_invalid_input_error_dialog(self):
|
||||
lbl = "<b>Invalid characters in image recipe name</b>"
|
||||
lbl = "<b>Invalid characters in image recipe name</b>\n"
|
||||
msg = "Image recipe names should be all lowercase and\n"
|
||||
msg += "include only alphanumeric characters. The only\n"
|
||||
msg += "special character you can use is the ASCII hyphen (-)."
|
||||
dialog = CrumbsMessageDialog(self, lbl, gtk.MESSAGE_ERROR, msg)
|
||||
lbl = lbl + "\n%s\n" % glib.markup_escape_text(msg)
|
||||
dialog = CrumbsMessageDialog(self, lbl, gtk.STOCK_DIALOG_ERROR)
|
||||
button = dialog.add_button("Close", gtk.RESPONSE_OK)
|
||||
HobButton.style_button(button)
|
||||
|
||||
|
||||
@@ -211,19 +211,18 @@ class SimpleSettingsDialog (CrumbsDialog, SettingsUIHelper):
|
||||
|
||||
def response_cb(self, dialog, response_id):
|
||||
if response_id == gtk.RESPONSE_YES:
|
||||
if self.proxy_checkbox.get_active():
|
||||
# Check that all proxy entries have a corresponding port
|
||||
for proxy, port in zip(self.all_proxy_addresses, self.all_proxy_ports):
|
||||
if proxy.get_text() and not port.get_text():
|
||||
lbl = "<b>Enter all port numbers</b>"
|
||||
msg = "Proxy servers require a port number. Please make sure you have entered a port number for each proxy server."
|
||||
dialog = CrumbsMessageDialog(self, lbl, gtk.MESSAGE_WARNING, msg)
|
||||
button = dialog.add_button("Close", gtk.RESPONSE_OK)
|
||||
HobButton.style_button(button)
|
||||
response = dialog.run()
|
||||
dialog.destroy()
|
||||
self.emit_stop_by_name("response")
|
||||
return
|
||||
# Check that all proxy entries have a corresponding port
|
||||
for proxy, port in zip(self.all_proxy_addresses, self.all_proxy_ports):
|
||||
if proxy.get_text() and not port.get_text():
|
||||
lbl = "<b>Enter all port numbers</b>\n\n"
|
||||
msg = "Proxy servers require a port number. Please make sure you have entered a port number for each proxy server."
|
||||
dialog = CrumbsMessageDialog(self, lbl, gtk.STOCK_DIALOG_WARNING, msg)
|
||||
button = dialog.add_button("Close", gtk.RESPONSE_OK)
|
||||
HobButton.style_button(button)
|
||||
response = dialog.run()
|
||||
dialog.destroy()
|
||||
self.emit_stop_by_name("response")
|
||||
return
|
||||
|
||||
self.configuration.dldir = self.dldir_text.get_text()
|
||||
self.configuration.sstatedir = self.sstatedir_text.get_text()
|
||||
|
||||
@@ -147,7 +147,9 @@ class HobHandler(gobject.GObject):
|
||||
elif next_command == self.SUB_MATCH_CLASS:
|
||||
self.runCommand(["findFilesMatchingInDir", "rootfs_", "classes"])
|
||||
elif next_command == self.SUB_PARSE_CONFIG:
|
||||
self.runCommand(["resetCooker"])
|
||||
self.runCommand(["enableDataTracking"])
|
||||
self.runCommand(["parseConfigurationFiles", "conf/.hob.conf", ""])
|
||||
self.runCommand(["disableDataTracking"])
|
||||
elif next_command == self.SUB_GNERATE_TGTS:
|
||||
self.runCommand(["generateTargetsTree", "classes/image.bbclass", []])
|
||||
elif next_command == self.SUB_GENERATE_PKGINFO:
|
||||
@@ -202,8 +204,7 @@ class HobHandler(gobject.GObject):
|
||||
reparse = self.runCommand(["getVariable", "BB_INVALIDCONF"]) or None
|
||||
if reparse is True:
|
||||
self.set_var_in_file("BB_INVALIDCONF", False, "local.conf")
|
||||
self.runCommand(["setPrePostConfFiles", "conf/.hob.conf", ""])
|
||||
self.commands_async.prepend(self.SUB_PARSE_CONFIG)
|
||||
self.runCommand(["parseConfigurationFiles", "conf/.hob.conf", ""])
|
||||
self.run_next_command()
|
||||
|
||||
elif isinstance(event, bb.event.SanityCheckFailed):
|
||||
@@ -250,8 +251,6 @@ class HobHandler(gobject.GObject):
|
||||
self.current_phase = None
|
||||
self.run_next_command()
|
||||
elif isinstance(event, bb.command.CommandFailed):
|
||||
if event.error not in ("Forced shutdown", "Stopped build"):
|
||||
self.error_msg += event.error
|
||||
self.commands_async = []
|
||||
self.display_error()
|
||||
elif isinstance(event, (bb.event.ParseStarted,
|
||||
@@ -299,10 +298,18 @@ class HobHandler(gobject.GObject):
|
||||
return
|
||||
|
||||
def init_cooker(self):
|
||||
self.runCommand(["initCooker"])
|
||||
self.runCommand(["createConfigFile", ".hob.conf"])
|
||||
|
||||
def reset_cooker(self):
|
||||
self.runCommand(["enableDataTracking"])
|
||||
self.runCommand(["resetCooker"])
|
||||
self.runCommand(["disableDataTracking"])
|
||||
|
||||
def set_extra_inherit(self, bbclass):
|
||||
self.append_var_in_file("INHERIT", bbclass, ".hob.conf")
|
||||
inherits = self.runCommand(["getVariable", "INHERIT"]) or ""
|
||||
inherits = inherits + " " + bbclass
|
||||
self.set_var_in_file("INHERIT", inherits, ".hob.conf")
|
||||
|
||||
def set_bblayers(self, bblayers):
|
||||
self.set_var_in_file("BBLAYERS", " ".join(bblayers), "bblayers.conf")
|
||||
@@ -398,7 +405,6 @@ class HobHandler(gobject.GObject):
|
||||
self.run_next_command(self.NETWORK_TEST)
|
||||
|
||||
def generate_configuration(self):
|
||||
self.runCommand(["setPrePostConfFiles", "conf/.hob.conf", ""])
|
||||
self.commands_async.append(self.SUB_PARSE_CONFIG)
|
||||
self.commands_async.append(self.SUB_PATH_LAYERS)
|
||||
self.commands_async.append(self.SUB_FILES_DISTRO)
|
||||
@@ -408,7 +414,6 @@ class HobHandler(gobject.GObject):
|
||||
self.run_next_command(self.GENERATE_CONFIGURATION)
|
||||
|
||||
def generate_recipes(self):
|
||||
self.runCommand(["setPrePostConfFiles", "conf/.hob.conf", ""])
|
||||
self.commands_async.append(self.SUB_PARSE_CONFIG)
|
||||
self.commands_async.append(self.SUB_GNERATE_TGTS)
|
||||
self.run_next_command(self.GENERATE_RECIPES)
|
||||
@@ -418,7 +423,6 @@ class HobHandler(gobject.GObject):
|
||||
targets.extend(tgts)
|
||||
self.recipe_queue = targets
|
||||
self.default_task = default_task
|
||||
self.runCommand(["setPrePostConfFiles", "conf/.hob.conf", ""])
|
||||
self.commands_async.append(self.SUB_PARSE_CONFIG)
|
||||
self.commands_async.append(self.SUB_BUILD_RECIPES)
|
||||
self.run_next_command(self.GENERATE_PACKAGES)
|
||||
@@ -430,7 +434,6 @@ class HobHandler(gobject.GObject):
|
||||
self.package_queue = image_packages
|
||||
self.toolchain_packages = toolchain_packages
|
||||
self.default_task = default_task
|
||||
self.runCommand(["setPrePostConfFiles", "conf/.hob.conf", ""])
|
||||
self.commands_async.append(self.SUB_PARSE_CONFIG)
|
||||
self.commands_async.append(self.SUB_BUILD_IMAGE)
|
||||
self.run_next_command(self.GENERATE_IMAGE)
|
||||
|
||||
@@ -199,9 +199,7 @@ class PackageListModel(gtk.ListStore):
|
||||
return self.cmp_vals(val1, val2, user_data)
|
||||
|
||||
def cmp_vals(self, val1, val2, user_data):
|
||||
if val1 is None or val2 is None:
|
||||
return 0
|
||||
elif val1.startswith(user_data) and not val2.startswith(user_data):
|
||||
if val1.startswith(user_data) and not val2.startswith(user_data):
|
||||
return -1
|
||||
elif not val1.startswith(user_data) and val2.startswith(user_data):
|
||||
return 1
|
||||
@@ -251,7 +249,7 @@ class PackageListModel(gtk.ListStore):
|
||||
pkgv = getpkgvalue(pkginfo, 'PKGV', pkg)
|
||||
pkgr = getpkgvalue(pkginfo, 'PKGR', pkg)
|
||||
# PKGSIZE is artificial, will always be overridden with the package name if present
|
||||
pkgsize = int(pkginfo.get('PKGSIZE_%s' % pkg, "0"))
|
||||
pkgsize = pkginfo.get('PKGSIZE_%s' % pkg, "0")
|
||||
# PKG_%s is the renamed version
|
||||
pkg_rename = pkginfo.get('PKG_%s' % pkg, "")
|
||||
# The rest may be overridden or not
|
||||
@@ -268,10 +266,11 @@ class PackageListModel(gtk.ListStore):
|
||||
|
||||
allow_empty = getpkgvalue(pkginfo, 'ALLOW_EMPTY', pkg, "")
|
||||
|
||||
if pkgsize == 0 and not allow_empty:
|
||||
if pkgsize == "0" and not allow_empty:
|
||||
continue
|
||||
|
||||
size = HobPage._size_to_string(pkgsize)
|
||||
# pkgsize is in KB
|
||||
size = HobPage._size_to_string(HobPage._string_to_size(pkgsize + ' KB'))
|
||||
self.set(self.append(), self.COL_NAME, pkg, self.COL_VER, pkgv,
|
||||
self.COL_REV, pkgr, self.COL_RNM, pkg_rename,
|
||||
self.COL_SEC, section, self.COL_SUM, summary,
|
||||
@@ -576,9 +575,7 @@ class RecipeListModel(gtk.ListStore):
|
||||
return self.cmp_vals(val1, val2, user_data)
|
||||
|
||||
def cmp_vals(self, val1, val2, user_data):
|
||||
if val1 is None or val2 is None:
|
||||
return 0
|
||||
elif val1.startswith(user_data) and not val2.startswith(user_data):
|
||||
if val1.startswith(user_data) and not val2.startswith(user_data):
|
||||
return -1
|
||||
elif not val1.startswith(user_data) and val2.startswith(user_data):
|
||||
return 1
|
||||
|
||||
@@ -734,7 +734,7 @@ class HobCellRendererController(gobject.GObject):
|
||||
self.current_angle_pos += self.step_angle
|
||||
if self.running_mode == self.MODE_CYCLE_RUNNING:
|
||||
if (self.current_angle_pos >= 1):
|
||||
self.current_angle_pos = 0
|
||||
self.current_angle_pos = self.step_angle
|
||||
else:
|
||||
if self.current_angle_pos > 1:
|
||||
self.force_stop()
|
||||
|
||||
@@ -304,15 +304,14 @@ class ImageConfigurationPage (HobPage):
|
||||
self.builder.window.set_cursor(None)
|
||||
|
||||
def machine_combo_changed_cb(self, machine_combo):
|
||||
self.builder.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.WATCH))
|
||||
self.builder.wait(0.1) #wait for combo and cursor to update
|
||||
self.stopping = False
|
||||
self.builder.parsing_warnings = []
|
||||
combo_item = machine_combo.get_active_text()
|
||||
if not combo_item or combo_item == self.__dummy_machine__:
|
||||
return
|
||||
|
||||
self.builder.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.WATCH))
|
||||
self.builder.wait(0.1) #wait for combo and cursor to update
|
||||
|
||||
# remove __dummy_machine__ item from the store list after first user selection
|
||||
# because it is no longer valid
|
||||
combo_store = machine_combo.get_model()
|
||||
|
||||
@@ -355,9 +355,9 @@ class ImageDetailsPage (HobPage):
|
||||
vallist.append(base_image)
|
||||
i = 0
|
||||
for layer in layers:
|
||||
varlist.append(" - ")
|
||||
if i > layer_num_limit:
|
||||
break
|
||||
varlist.append(" - ")
|
||||
i += 1
|
||||
vallist.append("")
|
||||
i = 0
|
||||
@@ -655,7 +655,7 @@ class ImageDetailsPage (HobPage):
|
||||
self.builder.show_configuration()
|
||||
|
||||
def edit_packages_button_clicked_cb(self, button):
|
||||
self.builder.show_packages()
|
||||
self.builder.show_packages(ask=False)
|
||||
|
||||
def my_images_button_clicked_cb(self, button):
|
||||
self.builder.show_load_my_images_dialog()
|
||||
|
||||
@@ -174,15 +174,6 @@ class RunningBuild (gobject.GObject):
|
||||
color,
|
||||
0))
|
||||
|
||||
# if there are warnings while processing a package
|
||||
# (parent), mark the task with warning color;
|
||||
# in case there are errors, the updates will be
|
||||
# handled on TaskFailed.
|
||||
if color == HobColors.WARNING and parent:
|
||||
self.model.set(parent, self.model.COL_COLOR, color)
|
||||
if task: #then we have a parent (package), and update it's color
|
||||
self.model.set(self.tasks_to_iter[(package, None)], self.model.COL_COLOR, color)
|
||||
|
||||
elif isinstance(event, bb.build.TaskStarted):
|
||||
(package, task) = (event._package, event._task)
|
||||
|
||||
@@ -210,10 +201,9 @@ class RunningBuild (gobject.GObject):
|
||||
|
||||
# Because this parent package now has an active child mark it as
|
||||
# such.
|
||||
self.model.set(parent, self.model.COL_ICON, "gtk-execute")
|
||||
parent_color = self.model.get(parent, self.model.COL_COLOR)[0]
|
||||
if parent_color != HobColors.ERROR and parent_color != HobColors.WARNING:
|
||||
self.model.set(parent, self.model.COL_COLOR, HobColors.RUNNING)
|
||||
# @todo if parent is already in error, don't mark it green
|
||||
self.model.set(parent, self.model.COL_ICON, "gtk-execute",
|
||||
self.model.COL_COLOR, HobColors.RUNNING)
|
||||
|
||||
# Add an entry in the model for this task
|
||||
i = self.model.append (parent, (None,
|
||||
@@ -256,28 +246,20 @@ class RunningBuild (gobject.GObject):
|
||||
self.model.set(i, self.model.COL_ICON, icon,
|
||||
self.model.COL_COLOR, color)
|
||||
else:
|
||||
# Mark the parent package and the task as inactive,
|
||||
# but make sure to preserve error, warnings and active
|
||||
# states
|
||||
parent_color = self.model.get(parent, self.model.COL_COLOR)[0]
|
||||
task_color = self.model.get(current, self.model.COL_COLOR)[0]
|
||||
icon = None
|
||||
color = HobColors.OK
|
||||
|
||||
# Mark the task as inactive
|
||||
self.model.set(current, self.model.COL_ICON, None)
|
||||
if task_color != HobColors.ERROR:
|
||||
if task_color == HobColors.WARNING:
|
||||
self.model.set(current, self.model.COL_ICON, 'dialog-warning')
|
||||
else:
|
||||
self.model.set(current, self.model.COL_COLOR, HobColors.OK)
|
||||
self.model.set(current, self.model.COL_ICON, icon,
|
||||
self.model.COL_COLOR, color)
|
||||
|
||||
# Mark the parent as inactive
|
||||
if parent_color != HobColors.ERROR:
|
||||
if parent_color == HobColors.WARNING:
|
||||
self.model.set(parent, self.model.COL_ICON, "dialog-warning")
|
||||
else:
|
||||
self.model.set(parent, self.model.COL_ICON, None)
|
||||
if num_active == 0:
|
||||
self.model.set(parent, self.model.COL_COLOR, HobColors.OK)
|
||||
# Mark the parent package as inactive, but make sure to
|
||||
# preserve error and active states
|
||||
i = self.tasks_to_iter[(package, None)]
|
||||
if self.model.get(parent, self.model.COL_ICON) != 'dialog-error':
|
||||
self.model.set(parent, self.model.COL_ICON, icon)
|
||||
if num_active == 0:
|
||||
self.model.set(parent, self.model.COL_COLOR, HobColors.OK)
|
||||
|
||||
# Clear the iters and the pids since when the task goes away the
|
||||
# pid will no longer be used for messages
|
||||
|
||||
@@ -202,7 +202,7 @@ def main(server, eventHandler, params):
|
||||
return 1
|
||||
cmdline = cmdline['action']
|
||||
if not cmdline or cmdline[0] != "generateDotGraph":
|
||||
print("This UI requires the -g option")
|
||||
print("This UI is only compatible with the -g option")
|
||||
return 1
|
||||
ret, error = server.runCommand(["generateDepTreeEvent", cmdline[1], cmdline[2]])
|
||||
if error:
|
||||
|
||||
@@ -46,7 +46,7 @@ from bb.ui.crumbs.hoblistmodel import RecipeListModel, PackageListModel
|
||||
from bb.ui.crumbs.hobeventhandler import HobHandler
|
||||
from bb.ui.crumbs.builder import Builder
|
||||
|
||||
featureSet = [bb.cooker.CookerFeatures.HOB_EXTRA_CACHES, bb.cooker.CookerFeatures.BASEDATASTORE_TRACKING]
|
||||
featureSet = [bb.cooker.CookerFeatures.HOB_EXTRA_CACHES]
|
||||
|
||||
def event_handle_idle_func(eventHandler, hobHandler):
|
||||
# Consume as many messages as we can in the time available to us
|
||||
|
||||
@@ -93,6 +93,7 @@ def main(server, eventHandler, params ):
|
||||
taskfailures = []
|
||||
|
||||
buildinfohelper = BuildInfoHelper(server, build_history_enabled)
|
||||
buildinfohelper.store_layer_info()
|
||||
|
||||
|
||||
while True:
|
||||
@@ -209,19 +210,13 @@ def main(server, eventHandler, params ):
|
||||
continue
|
||||
|
||||
if isinstance(event, (bb.event.BuildCompleted)):
|
||||
buildinfohelper.read_target_package_dep_data(event)
|
||||
buildinfohelper.update_build_information(event, errors, warnings, taskfailures)
|
||||
continue
|
||||
|
||||
if isinstance(event, (bb.command.CommandCompleted,
|
||||
bb.command.CommandFailed,
|
||||
bb.command.CommandExit)):
|
||||
if (isinstance(event, bb.command.CommandFailed)):
|
||||
event.levelno = format.ERROR
|
||||
event.msg = event.error
|
||||
event.pathname = ""
|
||||
event.lineno = 0
|
||||
buildinfohelper.store_log_event(event)
|
||||
errors += 1
|
||||
|
||||
buildinfohelper.update_build_information(event, errors, warnings, taskfailures)
|
||||
|
||||
@@ -230,17 +225,12 @@ def main(server, eventHandler, params ):
|
||||
warnings = 0
|
||||
taskfailures = []
|
||||
buildinfohelper = BuildInfoHelper(server, build_history_enabled)
|
||||
buildinfohelper.store_layer_info()
|
||||
continue
|
||||
|
||||
if isinstance(event, bb.event.MetadataEvent):
|
||||
if event.type == "SinglePackageInfo":
|
||||
buildinfohelper.store_build_package_information(event)
|
||||
if event.type == "LayerInfo":
|
||||
buildinfohelper.store_layer_info(event)
|
||||
if event.type == "BuildStatsList":
|
||||
buildinfohelper.store_tasks_stats(event)
|
||||
if event.type == "ImagePkgList":
|
||||
buildinfohelper.store_target_package_data(event)
|
||||
continue
|
||||
|
||||
# ignore
|
||||
|
||||
@@ -354,9 +354,6 @@ def better_exec(code, context, text = None, realfile = "<code>"):
|
||||
code = better_compile(code, realfile, realfile)
|
||||
try:
|
||||
exec(code, get_context(), context)
|
||||
except bb.BBHandledException:
|
||||
# Error already shown so passthrough
|
||||
raise
|
||||
except Exception as e:
|
||||
(t, value, tb) = sys.exc_info()
|
||||
|
||||
@@ -796,28 +793,22 @@ def copyfile(src, dest, newmtime = None, sstat = None):
|
||||
newmtime = sstat[stat.ST_MTIME]
|
||||
return newmtime
|
||||
|
||||
def which(path, item, direction = 0, history = False):
|
||||
def which(path, item, direction = 0):
|
||||
"""
|
||||
Locate a file in a PATH
|
||||
"""
|
||||
|
||||
hist = []
|
||||
paths = (path or "").split(':')
|
||||
if direction != 0:
|
||||
paths.reverse()
|
||||
|
||||
for p in paths:
|
||||
next = os.path.join(p, item)
|
||||
hist.append(next)
|
||||
if os.path.exists(next):
|
||||
if not os.path.isabs(next):
|
||||
next = os.path.abspath(next)
|
||||
if history:
|
||||
return next, hist
|
||||
return next
|
||||
|
||||
if history:
|
||||
return "", hist
|
||||
return ""
|
||||
|
||||
def to_boolean(string, default=None):
|
||||
|
||||
@@ -13,7 +13,6 @@ except ImportError:
|
||||
import bb.server.xmlrpc
|
||||
import prserv
|
||||
import prserv.db
|
||||
import errno
|
||||
|
||||
logger = logging.getLogger("BitBake.PRserv")
|
||||
|
||||
@@ -281,18 +280,8 @@ def stop_daemon(host, port):
|
||||
if pid:
|
||||
if os.path.exists(pidfile):
|
||||
os.remove(pidfile)
|
||||
|
||||
wait_timeout = 0
|
||||
while is_running(pid) and wait_timeout < 10:
|
||||
print("Waiting for pr-server to exit.")
|
||||
time.sleep(0.5)
|
||||
wait_timeout += 1
|
||||
|
||||
if is_running(pid):
|
||||
print("Sending SIGTERM to pr-server.")
|
||||
os.kill(pid,signal.SIGTERM)
|
||||
time.sleep(0.1)
|
||||
|
||||
os.kill(pid,signal.SIGTERM)
|
||||
time.sleep(0.1)
|
||||
except OSError as e:
|
||||
err = str(e)
|
||||
if err.find("No such process") <= 0:
|
||||
@@ -300,14 +289,6 @@ def stop_daemon(host, port):
|
||||
|
||||
return 0
|
||||
|
||||
def is_running(pid):
|
||||
try:
|
||||
os.kill(pid, 0)
|
||||
except OSError as err:
|
||||
if err.errno == errno.ESRCH:
|
||||
return False
|
||||
return True
|
||||
|
||||
def is_local_special(host, port):
|
||||
if host.strip().upper() == 'localhost'.upper() and (not port):
|
||||
return True
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
#
|
||||
# ex:ts=4:sw=4:sts=4:et
|
||||
# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
|
||||
#
|
||||
# BitBake Toaster Implementation
|
||||
#
|
||||
# Copyright (C) 2013 Intel Corporation
|
||||
@@ -27,16 +24,14 @@ urlpatterns = patterns('bldviewer.views',
|
||||
url(r'^targets$', 'model_explorer', {'model_name':'target'}, name='targets'),
|
||||
url(r'^tasks$', 'model_explorer', {'model_name':'task'}, name='task'),
|
||||
url(r'^task_dependencies$', 'model_explorer', {'model_name':'task_dependency'}, name='task_dependencies'),
|
||||
url(r'^packages$', 'model_explorer', {'model_name':'package'}, name='package'),
|
||||
url(r'^package_dependencies$', 'model_explorer', {'model_name':'package_dependency'}, name='package_dependency'),
|
||||
url(r'^packages$', 'model_explorer', {'model_name':'build_package'}, name='build_packages'),
|
||||
url(r'^package_dependencies$', 'model_explorer', {'model_name':'build_package_dependency'}, name='build_package_dependencies'),
|
||||
url(r'^target_packages$', 'model_explorer', {'model_name':'target_package'}, name='target_packages'),
|
||||
url(r'^target_installed_packages$', 'model_explorer', {'model_name':'target_installed_package'}, name='target_installed_package'),
|
||||
url(r'^package_files$', 'model_explorer', {'model_name':'build_file'}, name='build_file'),
|
||||
url(r'^package_files$', 'model_explorer', {'model_name':'build_file'}, name='build_files'),
|
||||
url(r'^layers$', 'model_explorer', {'model_name':'layer'}, name='layer'),
|
||||
url(r'^layerversions$', 'model_explorer', {'model_name':'layerversion'}, name='layerversion'),
|
||||
url(r'^recipes$', 'model_explorer', {'model_name':'recipe'}, name='recipe'),
|
||||
url(r'^recipe_dependencies$', 'model_explorer', {'model_name':'recipe_dependency'}, name='recipe_dependencies'),
|
||||
url(r'^variables$', 'model_explorer', {'model_name':'variable'}, name='variables'),
|
||||
url(r'^variableshistory$', 'model_explorer', {'model_name':'variablehistory'}, name='variablehistory'),
|
||||
url(r'^logmessages$', 'model_explorer', {'model_name':'logmessage'}, name='logmessages'),
|
||||
)
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
<div style="width:100%; height: 100%; position:absolute">
|
||||
<div style="width: 100%; height: 3em" class="nav">
|
||||
<ul class="nav nav-tabs">
|
||||
<li><a href="{% url "simple-all-builds" %}">All Builds</a></li>
|
||||
<li><a href="{% url "simple-all-layers" %}">All Layers</a></li>
|
||||
<li><a href="{% url all-builds %}">All Builds</a></li>
|
||||
<li><a href="{% url all-layers %}">All Layers</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
17
bitbake/lib/toaster/bldviewer/templates/basebuildpage.html
Normal file
17
bitbake/lib/toaster/bldviewer/templates/basebuildpage.html
Normal file
@@ -0,0 +1,17 @@
|
||||
{% extends "basetable.html" %}
|
||||
|
||||
{% block pagename %}
|
||||
<ul class="nav nav-tabs" style="display: inline-block">
|
||||
<li><a>Build {{build.target_set.all|join:" "}} at {{build.started_on}} : </a></li>
|
||||
<li><a href="{% url task build.id %}"> Tasks </a></li>
|
||||
<li><a href="{% url bpackage build.id %}"> Build Packages </a></li>
|
||||
{% for t in build.target_set.all %}
|
||||
{% if t.is_image %}
|
||||
<li><a href="{% url tpackage build.id t.pk %}"> Packages for {{t.target}} </a> </li>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
<li><a href="{% url configuration build.id %}"> Configuration </a> </li>
|
||||
</ul>
|
||||
<h1>Toaster - Build {% block pagetitle %} {% endblock %}</h1>
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{% extends "simple_base.html" %}
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block pagecontent %}
|
||||
<script>
|
||||
@@ -26,7 +26,7 @@ function filterTableRows(test) {
|
||||
|
||||
{% block pagename %}
|
||||
{% endblock %}
|
||||
<div align="left" style="display:inline-block; width: 40%; margin-left: 2em"> Filter: <input type="search" id="filterstring" style="width: 80%" onkeyup="filterTableRows($('#filterstring').val())" autocomplete="off">
|
||||
<div align="left" style="display:inline-block; width: 40%; margin-left: 2em"> Search: <input type="search" id="filterstring" style="width: 80%" onkeyup="filterTableRows($('#filterstring').val())" autocomplete="off">
|
||||
</div>
|
||||
{% if hideshowcols %}
|
||||
<div align="right" style="display: inline-block; width: 40%">Show/Hide columns:
|
||||
@@ -36,25 +36,7 @@ function filterTableRows(test) {
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div style="display: block; float:right; margin-left: auto; margin-right:5em"><span class="pagination" style="vertical-align: top; margin-right: 3em">Showing {{objects.start_index}} to {{objects.end_index}} out of {{objects.paginator.count}} entries. </span>
|
||||
<ul class="pagination" style="display: block-inline">
|
||||
{%if objects.has_previous %}
|
||||
<li><a href="?page={{objects.previous_page_number}}">«</a></li>
|
||||
{%else%}
|
||||
<li class="disabled"><a href="#">«</a></li>
|
||||
{%endif%}
|
||||
{% for i in objects.page_range %}
|
||||
<li{%if i == objects.number %} class="active" {%endif%}><a href="?page={{i}}">{{i}}</a></li>
|
||||
{% endfor %}
|
||||
{%if objects.has_next%}
|
||||
<li><a href="?page={{objects.next_page_number}}">»</a></li>
|
||||
{%else%}
|
||||
<li class="disabled"><a href="#">»</a></li>
|
||||
{%endif%}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<table class="table table-striped table-condensed" style="width:95%">
|
||||
{% block pagetable %}
|
||||
{% endblock %}
|
||||
@@ -1,8 +1,8 @@
|
||||
{% extends "basebuildpage.html" %}
|
||||
|
||||
{% block pagetitle %}Files for package {{objects.0.bpackage.name}} {% endblock %}
|
||||
{% block pagetitle %}Files for package {{files.0.bpackage.name}} {% endblock %}
|
||||
{% block pagetable %}
|
||||
{% if not objects %}
|
||||
{% if not files %}
|
||||
<p>No files were recorded for this package!</p>
|
||||
{% else %}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<th>Size (Bytes)</th>
|
||||
</tr>
|
||||
|
||||
{% for file in objects %}
|
||||
{% for file in files %}
|
||||
|
||||
<tr class="data">
|
||||
<td>{{file.path}}</td>
|
||||
@@ -1,8 +1,8 @@
|
||||
{% extends "simple_basebuildpage.html" %}
|
||||
{% extends "basebuildpage.html" %}
|
||||
|
||||
{% block pagetitle %}Packages{% endblock %}
|
||||
{% block pagetable %}
|
||||
{% if not objects %}
|
||||
{% if not packages %}
|
||||
<p>No packages were recorded for this target!</p>
|
||||
{% else %}
|
||||
|
||||
@@ -18,12 +18,12 @@
|
||||
<th>Dependencies List (all)</th>
|
||||
</tr>
|
||||
|
||||
{% for package in objects %}
|
||||
{% for package in packages %}
|
||||
|
||||
<tr class="data">
|
||||
<td><a name="#{{package.name}}" href="{% url "simple-bfile" build.pk package.pk %}">{{package.name}} ({{package.filelist_bpackage.count}} files)</a></td>
|
||||
<td><a name="#{{package.name}}" href="{% url bfile build.pk package.pk %}">{{package.name}} ({{package.filelist_bpackage.count}} files)</a></td>
|
||||
<td>{{package.version}}-{{package.revision}}</td>
|
||||
<td>{%if package.recipe%}<a href="{% url "simple-layer_versions_recipes" package.recipe.layer_version_id %}#{{package.recipe.name}}">{{package.recipe.name}}</a>{{package.package_name}}</a>{%endif%}</td>
|
||||
<td><a href="{% url layer_versions_recipes package.recipe.layer_version_id %}#{{package.recipe.name}}">{{package.recipe.name}}</a>{{package.package_name}}</a></td>
|
||||
|
||||
<td>{{package.summary}}</td>
|
||||
<td>{{package.section}}</td>
|
||||
@@ -32,8 +32,8 @@
|
||||
<td>{{package.license}}</td>
|
||||
<td>
|
||||
<div style="height: 3em; overflow:auto">
|
||||
{% for bpd in package.package_dependencies_source.all %}
|
||||
{{bpd.dep_type}}: {{bpd.depends_on.name}} <br/>
|
||||
{% for bpd in package.bpackage_dependencies_package.all %}
|
||||
{{bpd.dep_type}}: {{bpd.depends_on}} <br/>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</td>
|
||||
@@ -1,4 +1,4 @@
|
||||
{% extends "simple_basetable.html" %}
|
||||
{% extends "basetable.html" %}
|
||||
|
||||
{% block pagename %}
|
||||
<h1>Toaster - Builds</h1>
|
||||
@@ -21,12 +21,12 @@
|
||||
<th>Bitbake Version</th>
|
||||
<th>Build Name</th>
|
||||
</tr>
|
||||
{% for build in objects %}
|
||||
{% for build in builds %}
|
||||
<tr class="data">
|
||||
<td><a href="{% url "simple-configuration" build.id %}">{{build.get_outcome_display}}</a></td>
|
||||
<td><a href="{% url configuration build.id %}">{{build.get_outcome_display}}</a></td>
|
||||
<td>{{build.started_on}}</td>
|
||||
<td>{{build.completed_on}}</td>
|
||||
<td>{% for t in build.target_set.all %}{%if t.is_image %}<a href="{% url "simple-tpackage" build.id t.id %}">{% endif %}{{t.target}}{% if t.is_image %}</a>{% endif %}<br/>{% endfor %}</td>
|
||||
<td>{% for t in build.target_set.all %}<a href="{% url tpackage build.id t.id %}">{{t.target}}</a>{% if t.is_image %} (Img){% endif %}<br/>{% endfor %}</td>
|
||||
<td>{{build.machine}}</td>
|
||||
<td>{% time_difference build.started_on build.completed_on %}</td>
|
||||
<td>{{build.errors_no}}:{% if build.errors_no %}{% for error in logs %}{% if error.build == build %}{% if error.level == 2 %}<p>{{error.message}}</p>{% endif %}{% endif %}{% endfor %}{% else %}None{% endif %}</td>
|
||||
@@ -1,4 +1,4 @@
|
||||
{% extends "simple_basebuildpage.html" %}
|
||||
{% extends "basebuildpage.html" %}
|
||||
|
||||
{% block pagetitle %}Configuration{% endblock %}
|
||||
{% block pagetable %}
|
||||
@@ -10,7 +10,7 @@
|
||||
<th>Value</th>
|
||||
</tr>
|
||||
|
||||
{% for variable in objects %}
|
||||
{% for variable in configuration %}
|
||||
|
||||
<tr class="data">
|
||||
<td>{{variable.variable_name}}</td>
|
||||
@@ -14,7 +14,7 @@
|
||||
<th>Known Versions</th>
|
||||
</tr>
|
||||
|
||||
{% for layer in objects %}
|
||||
{% for layer in layers %}
|
||||
|
||||
<tr class="data">
|
||||
<td>{{layer.name}}</td>
|
||||
@@ -23,7 +23,7 @@
|
||||
<td><table>
|
||||
{% for lv in layer.versions %}
|
||||
<tr><td>
|
||||
<a href="{% url "layer_versions_recipes" lv.id %}">({{lv.priority}}){{lv.branch}}:{{lv.commit}} ({{lv.count}} recipes)</a>
|
||||
<a href="{% url layer_versions_recipes lv.id %}">({{lv.priority}}){{lv.branch}}:{{lv.commit}} ({{lv.count}} recipes)</a>
|
||||
</td></tr>
|
||||
{% endfor %}
|
||||
</table></td>
|
||||
@@ -1,7 +1,7 @@
|
||||
{% extends "basebuildpage.html" %}
|
||||
|
||||
{% block pagetable %}
|
||||
{% if not objects %}
|
||||
{% if not packages %}
|
||||
<p>No packages were recorded for this target!</p>
|
||||
{% else %}
|
||||
|
||||
@@ -13,17 +13,17 @@
|
||||
<th>Depends on</th>
|
||||
</tr>
|
||||
|
||||
{% for package in objects %}
|
||||
{% for package in packages %}
|
||||
|
||||
<tr class="data">
|
||||
<td><a name="#{{package.name}}">{{package.name}}</a></td>
|
||||
<td>{{package.version}}</td>
|
||||
<td>{{package.size}}</td>
|
||||
<td>{%if package.recipe %}<a name="{{package.recipe.name}}.{{package.package_name}}">
|
||||
<a href="{% url "layer_versions_recipes" package.recipe.layer_version_id %}#{{package.recipe.name}}">{{package.recipe.name}}</a>{{package.package_name}}</a>{%endif%}</td>
|
||||
<a href="{% url layer_versions_recipes package.recipe.layer_version_id %}#{{package.recipe.name}}">{{package.recipe.name}}</a>{{package.package_name}}</a>{%endif%}</td>
|
||||
<td>
|
||||
<div style="height: 4em; overflow:auto">
|
||||
{% for d in package.package_dependencies_source.all %}
|
||||
{% for d in package.tpackage_dependencies_package.all %}
|
||||
<a href="#{{d.name}}">{{d.depends_on.name}}</a><br/>
|
||||
{% endfor %}
|
||||
</div>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user