mirror of
https://git.yoctoproject.org/poky
synced 2026-09-19 00:49:33 +02:00
Compare commits
78 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0d3591db9c | ||
|
|
753f79806b | ||
|
|
50ece536ae | ||
|
|
fdcda41c5e | ||
|
|
6ceab2c76d | ||
|
|
0b8fcb95dd | ||
|
|
45526f5ecf | ||
|
|
d1fd60f69d | ||
|
|
7fa2b1c154 | ||
|
|
fd7a07b3a2 | ||
|
|
01bc47f4d4 | ||
|
|
12a3d41a24 | ||
|
|
ce4f835679 | ||
|
|
54f08d23cd | ||
|
|
8a3d0f375c | ||
|
|
0c2003f134 | ||
|
|
6e71b0a012 | ||
|
|
4b5c1c0530 | ||
|
|
171e709ae6 | ||
|
|
a8b8557e4c | ||
|
|
399e6b8008 | ||
|
|
290280b332 | ||
|
|
9e11fbf904 | ||
|
|
0f8244faba | ||
|
|
0cc23a8656 | ||
|
|
30c39cc97c | ||
|
|
261ca88596 | ||
|
|
72ddd5c202 | ||
|
|
6026999e81 | ||
|
|
c5ab4d56f9 | ||
|
|
b9d6950732 | ||
|
|
95b64df744 | ||
|
|
941855f0c0 | ||
|
|
17641a7ead | ||
|
|
c6e842d9f5 | ||
|
|
372186ff62 | ||
|
|
c718ef5b60 | ||
|
|
e160e68136 | ||
|
|
c42340603f | ||
|
|
1a0cf646cf | ||
|
|
3ed9ba33a3 | ||
|
|
88ff0a4470 | ||
|
|
7b6db199fa | ||
|
|
a28bc0d0b6 | ||
|
|
47cfaec4ea | ||
|
|
59df74164d | ||
|
|
b5419d931e | ||
|
|
1ddda942bd | ||
|
|
c115f07678 | ||
|
|
73be41e475 | ||
|
|
b96412845d | ||
|
|
f0c88f220e | ||
|
|
1a3140eaf6 | ||
|
|
e34401720d | ||
|
|
72aadcf274 | ||
|
|
411910bb98 | ||
|
|
23bae7e299 | ||
|
|
13642c439c | ||
|
|
784f9b3369 | ||
|
|
0826752c04 | ||
|
|
a168d77ea9 | ||
|
|
297c60afd8 | ||
|
|
0f49a2c359 | ||
|
|
37eec34886 | ||
|
|
2e793fe2bf | ||
|
|
2bf160150f | ||
|
|
c3a5bee36f | ||
|
|
4a5a659674 | ||
|
|
ce18dde858 | ||
|
|
e51e4870f0 | ||
|
|
440a4cfffb | ||
|
|
779288f438 | ||
|
|
c3fa1a6677 | ||
|
|
e8ea66f5ff | ||
|
|
476242adc4 | ||
|
|
e9ef9424a3 | ||
|
|
fc9c11de28 | ||
|
|
4ae9c0785e |
11
.gitignore
vendored
11
.gitignore
vendored
@@ -2,7 +2,6 @@
|
|||||||
*.pyo
|
*.pyo
|
||||||
build/conf/local.conf
|
build/conf/local.conf
|
||||||
build/conf/bblayers.conf
|
build/conf/bblayers.conf
|
||||||
build/downloads
|
|
||||||
build/tmp/
|
build/tmp/
|
||||||
build/sstate-cache
|
build/sstate-cache
|
||||||
build/pyshtables.py
|
build/pyshtables.py
|
||||||
@@ -24,14 +23,4 @@ documentation/poky-ref-manual/poky-ref-manual.pdf
|
|||||||
documentation/poky-ref-manual/poky-ref-manual.tgz
|
documentation/poky-ref-manual/poky-ref-manual.tgz
|
||||||
documentation/poky-ref-manual/bsp-guide.html
|
documentation/poky-ref-manual/bsp-guide.html
|
||||||
documentation/poky-ref-manual/bsp-guide.pdf
|
documentation/poky-ref-manual/bsp-guide.pdf
|
||||||
documentation/bsp-guide/bsp-guide.html
|
|
||||||
documentation/bsp-guide/bsp-guide.pdf
|
|
||||||
documentation/bsp-guide/bsp-guide.tgz
|
|
||||||
documentation/yocto-project-qs/yocto-project-qs.html
|
|
||||||
documentation/yocto-project-qs/yocto-project-qs.tgz
|
|
||||||
documentation/kernel-manual/kernel-manual.html
|
|
||||||
documentation/kernel-manual/kernel-manual.tgz
|
|
||||||
documentation/kernel-manual/kernel-manual.pdf
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
220
CHANGELOG
Normal file
220
CHANGELOG
Normal file
@@ -0,0 +1,220 @@
|
|||||||
|
commit fd7a07b3a2153826bedda2ef76b9a33ab2791680
|
||||||
|
Author: Scott Garman <scott.a.garman@intel.com>
|
||||||
|
Date: Fri Jan 21 14:15:05 2011 -0800
|
||||||
|
|
||||||
|
poky-extract-sdk: allow relative paths for extract-dir
|
||||||
|
|
||||||
|
psuedo needs a full path to its pid file, so convert
|
||||||
|
relative extract-dir paths to full ones.
|
||||||
|
|
||||||
|
The symptom of this bug is receiving the following error:
|
||||||
|
|
||||||
|
pseudo: Couldn't open relative/path/to/var/pseudo/pseudo.pid: No such file or directory
|
||||||
|
|
||||||
|
This fixes [BUGID #670]
|
||||||
|
|
||||||
|
Signed-off-by: Scott Garman <scott.a.garman@intel.com>
|
||||||
|
|
||||||
|
commit 01bc47f4d47df3276b4b6c2583bcddd834fd5050
|
||||||
|
Author: Beth Flanagan <elizabeth.flanagan@intel.com>
|
||||||
|
Date: Wed Nov 3 17:20:00 2010 -0700
|
||||||
|
|
||||||
|
quilt: Fixed configure test for patch --version.
|
||||||
|
|
||||||
|
OpenSuSE 11.3 uses GNU patch 2.6.1.81-5b68 which breaks quilt's
|
||||||
|
configure test for patch version.
|
||||||
|
|
||||||
|
Signed-off-by: Beth Flanagan <elizabeth.flanagan@intel.com>
|
||||||
|
|
||||||
|
commit 12a3d41a24db79ae6c0491defffcf4f4753001cf
|
||||||
|
Author: Richard Purdie <richard.purdie@linuxfoundation.org>
|
||||||
|
Date: Fri Jan 14 11:57:18 2011 +0000
|
||||||
|
|
||||||
|
image.bbclass: Use the dedicated BB_WORKERCONTEXT, not bitbake internals to detect context
|
||||||
|
|
||||||
|
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
|
||||||
|
|
||||||
|
commit ce4f8356796bc797d9156ed252a4ed638a2150d5
|
||||||
|
Author: Richard Purdie <rpurdie@linux.intel.com>
|
||||||
|
Date: Wed Dec 15 23:22:16 2010 +0000
|
||||||
|
|
||||||
|
scripts/poky-qemu: Improve tmp layout assumption
|
||||||
|
|
||||||
|
If someone has changed TMPDIR in local.conf to a non-standard location, the
|
||||||
|
poky-qemu script currently doesn't handle this and assumes if BUILDDIR is set,
|
||||||
|
$BUILDDIR/tmp will exist.
|
||||||
|
|
||||||
|
Its simple to check if this exists and if not, to ask bitbake where the
|
||||||
|
directory is so this patch changes the code to do that.
|
||||||
|
|
||||||
|
Signed-off-by: Richard Purdie <rpurdie@linux.intel.com>
|
||||||
|
|
||||||
|
commit 54f08d23cd7d0de6aec31f4764389ff4dab2990d
|
||||||
|
Author: Scott Garman <scott.a.garman@intel.com>
|
||||||
|
Date: Tue Dec 7 20:59:06 2010 -0800
|
||||||
|
|
||||||
|
Make poky-qemu and related scripts work with arbitrary SDK locations
|
||||||
|
|
||||||
|
* No longer assume SDK toolchains are installed in /opt/poky
|
||||||
|
* [BUGFIX #568] where specifying paths to both the kernel and fs
|
||||||
|
image caused an error due to POKY_NATIVE_SYSROOT never being
|
||||||
|
set, triggering failure of poky-qemu-ifup/ifdown
|
||||||
|
* Cosmetic improvements to usage() functions by using basename
|
||||||
|
|
||||||
|
Signed-off-by: Scott Garman <scott.a.garman@intel.com>
|
||||||
|
|
||||||
|
commit 8a3d0f375ce416ada1a5443e4a8e467504001beb
|
||||||
|
Author: Scott Garman <scott.a.garman@intel.com>
|
||||||
|
Date: Fri Nov 12 16:31:13 2010 -0800
|
||||||
|
|
||||||
|
poky-qemu: Fix issues when running Yocto 0.9 release images
|
||||||
|
|
||||||
|
This fixes two bugs with poky-qemu when it is run from a
|
||||||
|
standalone meta-toolchain setup.
|
||||||
|
|
||||||
|
[BUGFIX #535] and [BUGFIX #536]
|
||||||
|
|
||||||
|
Signed-off-by: Scott Garman <scott.a.garman@intel.com>
|
||||||
|
|
||||||
|
commit 0c2003f13434c77f901a976523478d37d8aadb48
|
||||||
|
Author: Paul Eggleton <paul.eggleton@linux.intel.com>
|
||||||
|
Date: Thu Dec 16 10:29:50 2010 +0000
|
||||||
|
|
||||||
|
openssl: restore -Wall flag
|
||||||
|
|
||||||
|
The -Wall flag was unintentionally removed from the end of the CFLAG var in
|
||||||
|
089612794d4d8d9c79bd2a4365d6df78371f7f40 by me. This patch puts it back in.
|
||||||
|
|
||||||
|
Signed-off-by: Paul Eggleton <paul.eggleton@linux.intel.com>
|
||||||
|
Signed-off-by: Richard Purdie <rpurdie@linux.intel.com>
|
||||||
|
|
||||||
|
commit 6e71b0a012f0676c06b7b4788d932f320fca0b74
|
||||||
|
Author: Joshua Lock <josh@linux.intel.com>
|
||||||
|
Date: Wed Dec 15 14:31:21 2010 +0000
|
||||||
|
|
||||||
|
web-webkit: fix for make 3.82
|
||||||
|
|
||||||
|
Signed-off-by: Joshua Lock <josh@linux.intel.com>
|
||||||
|
|
||||||
|
commit 4b5c1c053000d297956f08949ffde7454ee33c5d
|
||||||
|
Author: Joshua Lock <josh@linux.intel.com>
|
||||||
|
Date: Wed Dec 15 13:42:15 2010 +0000
|
||||||
|
|
||||||
|
contacts: fix for make 3.82
|
||||||
|
|
||||||
|
Signed-off-by: Joshua Lock <josh@linux.intel.com>
|
||||||
|
|
||||||
|
commit 171e709ae6f4b1a7640bf393f57aa787648cdc0f
|
||||||
|
Author: Joshua Lock <josh@linux.intel.com>
|
||||||
|
Date: Wed Dec 15 12:58:09 2010 +0000
|
||||||
|
|
||||||
|
dates: fix for Make 3.82
|
||||||
|
|
||||||
|
Signed-off-by: Joshua Lock <josh@linux.intel.com>
|
||||||
|
|
||||||
|
commit a8b8557e4cb34b594bb620eb276bcaf7a8e0a8e3
|
||||||
|
Author: Joshua Lock <josh@linux.intel.com>
|
||||||
|
Date: Wed Dec 15 12:27:52 2010 +0000
|
||||||
|
|
||||||
|
owl-video-widget: fix Makefile for super strict make 3.82
|
||||||
|
|
||||||
|
Signed-off-by: Joshua Lock <josh@linux.intel.com>
|
||||||
|
|
||||||
|
commit 399e6b8008cb0b8cc0b75efd48dd821a6cf5a8a8
|
||||||
|
Author: Joshua Lock <josh@linux.intel.com>
|
||||||
|
Date: Tue Dec 14 18:29:43 2010 +0000
|
||||||
|
|
||||||
|
libowl-av: fix for Make 3.82
|
||||||
|
|
||||||
|
Signed-off-by: Joshua Lock <josh@linux.intel.com>
|
||||||
|
|
||||||
|
commit 290280b332570ec73301f76765b1c5f2de20a9fd
|
||||||
|
Author: Joshua Lock <josh@linux.intel.com>
|
||||||
|
Date: Tue Dec 14 17:56:53 2010 +0000
|
||||||
|
|
||||||
|
gst-plugins: fix for make 3.82
|
||||||
|
|
||||||
|
Signed-off-by: Joshua Lock <josh@linux.intel.com>
|
||||||
|
|
||||||
|
commit 9e11fbf9048b17526ca8160d82b69f386595c9a7
|
||||||
|
Author: Joshua Lock <josh@linux.intel.com>
|
||||||
|
Date: Tue Dec 14 15:39:42 2010 +0000
|
||||||
|
|
||||||
|
gstreamer: fix to comply with make 3.82's stricter parser
|
||||||
|
|
||||||
|
Signed-off-by: Joshua Lock <josh@linux.intel.com>
|
||||||
|
|
||||||
|
commit 0f8244faba5c36c0580081c112ea27ce683af99b
|
||||||
|
Author: Joshua Lock <josh@linux.intel.com>
|
||||||
|
Date: Tue Dec 14 12:49:13 2010 +0000
|
||||||
|
|
||||||
|
linux-libc-headers: fix for Make 3.82
|
||||||
|
|
||||||
|
Fix the kernel Makefile for use with Make 3.82 by splitting mixed implicit and
|
||||||
|
normal rules into separate rules.
|
||||||
|
|
||||||
|
Signed-off-by: Joshua Lock <josh@linux.intel.com>
|
||||||
|
|
||||||
|
commit 0cc23a86562d0ce1e236ceb4a56a8f19d400192f
|
||||||
|
Author: Joshua Lock <josh@linux.intel.com>
|
||||||
|
Date: Tue Dec 14 12:21:33 2010 +0000
|
||||||
|
|
||||||
|
busybox: additional fixes for Make 3.82
|
||||||
|
|
||||||
|
There where still some mixed implicit and normal rules in the Busybox Makefile,
|
||||||
|
Update our existing make-382.patch to split these into separate rules.
|
||||||
|
|
||||||
|
Signed-off-by: Joshua Lock <josh@linux.intel.com>
|
||||||
|
|
||||||
|
commit 30c39cc97c384134661300e107d7a81f257f8034
|
||||||
|
Author: Joshua Lock <josh@linux.intel.com>
|
||||||
|
Date: Fri Nov 12 16:36:54 2010 +0000
|
||||||
|
|
||||||
|
procps: fix for build against make 3.82
|
||||||
|
|
||||||
|
Signed-off-by: Joshua Lock <josh@linux.intel.com>
|
||||||
|
|
||||||
|
commit 261ca885962ba9606bcad4c5415927a79fdd7b96
|
||||||
|
Author: Joshua Lock <josh@linux.intel.com>
|
||||||
|
Date: Tue Nov 9 12:18:14 2010 +0000
|
||||||
|
|
||||||
|
busybox: import upstream patch for make 3.82
|
||||||
|
|
||||||
|
Signed-off-by: Joshua Lock <josh@linux.intel.com>
|
||||||
|
|
||||||
|
commit 72ddd5c20246a5d5b1752b58a61ef75b4c39cc40
|
||||||
|
Author: Joshua Lock <josh@linux.intel.com>
|
||||||
|
Date: Tue Nov 9 12:14:28 2010 +0000
|
||||||
|
|
||||||
|
eglibc: fix build of eglibc-initial for make 3.82
|
||||||
|
|
||||||
|
Make 3.82, as shipped with Fedora 14, fixes some holes in the parser which in
|
||||||
|
turn breaks behaviour of some Makefiles. Most notably eglibc's.
|
||||||
|
|
||||||
|
Signed-off-by: Joshua Lock <josh@linux.intel.com>
|
||||||
|
|
||||||
|
commit 6026999e81042a7f6560f9bce04390865509b235
|
||||||
|
Author: Paul Eggleton <paul.eggleton@intel.com>
|
||||||
|
Date: Fri Nov 19 15:03:32 2010 +0000
|
||||||
|
|
||||||
|
qemu: fix failure to find zlib header files during configure
|
||||||
|
|
||||||
|
Corrects problems during configure of qemu-native due to the BUILD_CFLAGS
|
||||||
|
not being included when attempting to compile the test program for zlib
|
||||||
|
within the configure script.
|
||||||
|
|
||||||
|
Signed-off-by: Paul Eggleton <paul.eggleton@intel.com>
|
||||||
|
Signed-off-by: Richard Purdie <rpurdie@linux.intel.com>
|
||||||
|
|
||||||
|
commit c5ab4d56f97a0e45b124d40c9f536541be04c201
|
||||||
|
Author: Paul Eggleton <paul.eggleton@intel.com>
|
||||||
|
Date: Wed Nov 17 11:37:47 2010 +0000
|
||||||
|
|
||||||
|
openssl-native: disable execstack flag to prevent problems with SELinux
|
||||||
|
|
||||||
|
The execstack flag gets set on libcrypto.so by default which causes SELinux
|
||||||
|
to prevent it from being loaded on systems using SELinux, which includes
|
||||||
|
Fedora. This patch disables the execstack flag. (Note: Red Hat do this in
|
||||||
|
their openssl packaging.)
|
||||||
|
|
||||||
|
Signed-off-by: Paul Eggleton <paul.eggleton@linux.intel.com>
|
||||||
70
NOTES
Normal file
70
NOTES
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
Name: Laverne
|
||||||
|
Version: 4.0.1
|
||||||
|
Built from Revision: fd7a07b3a2153826bedda2ef76b9a33ab2791680
|
||||||
|
Build Date: Jan 26 2011
|
||||||
|
Builder: autobuilder.pokylinux.org
|
||||||
|
|
||||||
|
The Laverne 4.0.1 Release ensures you can use Poky Laverne on systems running
|
||||||
|
Fedora 14 and Opensuse 11.3, fixes issues with the poky-qemu script, and fixes
|
||||||
|
several other bugs. For the full changelog for Laverne 4.0.1 please read
|
||||||
|
CHANGELOG.
|
||||||
|
|
||||||
|
Following are descriptions of fixes and known issues.
|
||||||
|
|
||||||
|
Fixes
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
* Make 3.82, as shipped with Fedora 14, included parser bug fixes that
|
||||||
|
resulted in a much stricter parser. As a result, the Makefiles could not be
|
||||||
|
parsed for many of the software versions shipped with Laverne. The Makefiles
|
||||||
|
in the following recipes were fixed:
|
||||||
|
|
||||||
|
o eglibc
|
||||||
|
o busybox
|
||||||
|
o procps
|
||||||
|
o linux-libc-headers
|
||||||
|
o gstreamer
|
||||||
|
o gst-plugins
|
||||||
|
o libowl-av
|
||||||
|
o owl-video-widget
|
||||||
|
o dates
|
||||||
|
o contacts
|
||||||
|
o web-webkit
|
||||||
|
|
||||||
|
* The ability to build openssl-native on a system that has SELINUX enabled
|
||||||
|
was restored. (We disabled the execstack flag at compile time.)
|
||||||
|
|
||||||
|
* A host-intrusion issue caused by a failure in QEMU to find zlib headers
|
||||||
|
during configure was fixed. The issue was causing qemu-native to use the
|
||||||
|
system zlib if it was present. If the system zlib was not present the build
|
||||||
|
would fail.
|
||||||
|
|
||||||
|
* Stability and usability enhancements, which included handling relative
|
||||||
|
filesystem paths, were made to poky-qemu scripts.
|
||||||
|
|
||||||
|
* The run-time remapping of package names when adding extra packages to an
|
||||||
|
image via the IMAGE_INSTALL mechanism were fixed.
|
||||||
|
|
||||||
|
* The configure test in quilt for GNU patch was fixed to that it correctly
|
||||||
|
detects the version.
|
||||||
|
|
||||||
|
Known Issues
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
* The mpc3815e-rbd and routerstationpro machines were untested and not a
|
||||||
|
part of the official Laverne 4.0 release. These machines are still unusable
|
||||||
|
for this Laverne 4.0.1 release.
|
||||||
|
o mpx3815e-rdb will not boot due to a kernel/uboot issue Bug #685
|
||||||
|
o routerstation will not boot (by default) due to incorrect boot
|
||||||
|
parameters Bug #681
|
||||||
|
o routerstationpro debug messages related to the ethernet driver print
|
||||||
|
during boot Bug #679
|
||||||
|
* Shutdown/poweroff on qemuarm does not cleanly halt the virtual machine.
|
||||||
|
To workaround this issue use the reboot command. Using this command avoids
|
||||||
|
a "power-cycle" and instead cleanly shuts down the VM Bug #684
|
||||||
|
* Two "Connection Manager" icons appear in the Sato UI. This duplication has
|
||||||
|
been fixed in master. Note that you can use either icon to launch the
|
||||||
|
connectivity UI. Bug #683
|
||||||
|
* The on-screen keyboard incorrectly launches in the qemumips machine. This
|
||||||
|
issue is due to a mis-configured formfactor file Bug #682
|
||||||
|
|
||||||
575
README.hardware
575
README.hardware
@@ -1,417 +1,436 @@
|
|||||||
Poky Hardware README
|
Poky Hardware Reference Guide
|
||||||
====================
|
=============================
|
||||||
|
|
||||||
This file gives details about using Poky with different hardware reference
|
This file gives details about using Poky with different hardware reference
|
||||||
boards and consumer devices. A full list of target machines can be found by
|
boards and consumer devices. A full list of target machines can be found by
|
||||||
looking in the meta/conf/machine/ directory. If in doubt about using Poky with
|
looking in the meta/conf/machine/ directory. If in doubt about using Poky with
|
||||||
your hardware, consult the documentation for your board/device.
|
your hardware, consult the documentation for your board/device. To discuss
|
||||||
|
support for further hardware reference boards/devices please contact OpenedHand.
|
||||||
|
|
||||||
Support for additional devices is normally added by creating BSP layers - for
|
QEMU Emulation Images (qemuarm and qemux86)
|
||||||
more information please see the Yocto Board Support Package (BSP) Developer's
|
===========================================
|
||||||
Guide - documentation source is in documentation/bspguide or download the PDF
|
|
||||||
from:
|
|
||||||
|
|
||||||
http://yoctoproject.org/community/documentation
|
|
||||||
|
|
||||||
Support for machines other than QEMU may be moved out to separate BSP layers in
|
|
||||||
future versions.
|
|
||||||
|
|
||||||
|
|
||||||
QEMU Emulation Targets
|
|
||||||
======================
|
|
||||||
|
|
||||||
To simplify development Poky supports building images to work with the QEMU
|
To simplify development Poky supports building images to work with the QEMU
|
||||||
emulator in system emulation mode. Several architectures are currently
|
emulator in system emulation mode. Two architectures are currently supported,
|
||||||
supported:
|
ARM (via qemuarm) and x86 (via qemux86). Use of the QEMU images is covered
|
||||||
|
in the Poky Handbook.
|
||||||
* ARM (qemuarm)
|
|
||||||
* x86 (qemux86)
|
|
||||||
* x86-64 (qemux86-64)
|
|
||||||
* PowerPC (qemuppc)
|
|
||||||
* MIPS (qemumips)
|
|
||||||
|
|
||||||
Use of the QEMU images is covered in the Poky Reference Manual. The Poky
|
|
||||||
MACHINE setting corresponding to the target is given in brackets.
|
|
||||||
|
|
||||||
|
|
||||||
Hardware Reference Boards
|
Hardware Reference Boards
|
||||||
=========================
|
=========================
|
||||||
|
|
||||||
The following boards are supported by Poky's core layer:
|
The following boards are supported by Poky:
|
||||||
|
|
||||||
* Texas Instruments Beagleboard (beagleboard)
|
* Compulab CM-X270 (cm-x270)
|
||||||
* Freescale MPC8315E-RDB (mpc8315e-rdb)
|
* Compulab EM-X270 (em-x270)
|
||||||
* Ubiquiti Networks RouterStation Pro (routerstationpro)
|
* FreeScale iMX31ADS (mx31ads)
|
||||||
|
* Marvell PXA3xx Zylonite (zylonite)
|
||||||
|
* Logic iMX31 Lite Kit (mx31litekit)
|
||||||
|
* Phytec phyCORE-iMX31 (mx31phy)
|
||||||
|
|
||||||
For more information see the board's section below. The Poky MACHINE setting
|
For more information see board's section below. The Poky MACHINE setting
|
||||||
corresponding to the board is given in brackets.
|
corresponding to the board is given in brackets.
|
||||||
|
|
||||||
|
|
||||||
Consumer Devices
|
Consumer Devices
|
||||||
================
|
================
|
||||||
|
|
||||||
The following consumer devices are supported by Poky's core layer:
|
The following consumer devices are supported by Poky:
|
||||||
|
|
||||||
* Intel Atom based PCs and devices (atom-pc)
|
* FIC Neo1973 GTA01 smartphone (fic-gta01)
|
||||||
|
* HTC Universal (htcuniversal)
|
||||||
|
* Nokia 770/N800/N810 Internet Tablets (nokia770 and nokia800)
|
||||||
|
* Sharp Zaurus SL-C7x0 series (c7x0)
|
||||||
|
* Sharp Zaurus SL-C1000 (akita)
|
||||||
|
* Sharp Zaurus SL-C3x00 series (spitz)
|
||||||
|
|
||||||
For more information see the device's section below. The Poky MACHINE setting
|
For more information see board's section below. The Poky MACHINE setting
|
||||||
corresponding to the device is given in brackets.
|
corresponding to the board is given in brackets.
|
||||||
|
|
||||||
|
Poky Boot CD (bootcdx86)
|
||||||
|
========================
|
||||||
|
|
||||||
|
The Poky boot CD iso images are designed as a demonstration of the Poky
|
||||||
|
environment and to show the versatile image formats Poky can generate. It will
|
||||||
|
run on Pentium2 or greater PC style computers. The iso image can be
|
||||||
|
burnt to CD and then booted from.
|
||||||
|
|
||||||
Specific Hardware Documentation
|
|
||||||
===============================
|
|
||||||
|
|
||||||
|
Hardware Reference Boards
|
||||||
|
=========================
|
||||||
|
|
||||||
Intel Atom based PCs and devices (atom-pc)
|
Compulab CM-X270 (cm-x270)
|
||||||
==========================================
|
==========================
|
||||||
|
|
||||||
The atom-pc MACHINE is tested on the following platforms:
|
The bootloader on this board doesn't support writing jffs2 images directly to
|
||||||
|
NAND and normally uses a proprietary kernel flash driver. To allow the use of
|
||||||
|
jffs2 images, a two stage updating procedure is needed. Firstly, an initramfs
|
||||||
|
is booted which contains mtd utilities and this is then used to write the main
|
||||||
|
filesystem.
|
||||||
|
|
||||||
o Asus eee901
|
It is assumed the board is connected to a network where a TFTP server is
|
||||||
o Acer Aspire One
|
available and that a serial terminal is available to communicate with the
|
||||||
o Toshiba NB305
|
bootloader (38400, 8N1). If a DHCP server is available the device will use it
|
||||||
o Intel Embedded Development Board 1-N450 (Black Sand)
|
to obtain an IP address. If not, run:
|
||||||
|
|
||||||
and is likely to work on many unlisted atom based devices. The MACHINE type
|
ARMmon > setip dhcp off
|
||||||
supports ethernet, wifi, sound, and i915 graphics by default in addition to
|
ARMmon > setip ip 192.168.1.203
|
||||||
common PC input devices, busses, and so on.
|
ARMmon > setip mask 255.255.255.0
|
||||||
|
|
||||||
Depending on the device, it can boot from a traditional hard-disk, a USB device,
|
To reflash the kernel:
|
||||||
or over the network. Writing poky generated images to physical media is
|
|
||||||
straightforward with a caveat for USB devices. The following examples assume the
|
|
||||||
target boot device is /dev/sdb, be sure to verify this and use the correct
|
|
||||||
device as the following commands are run as root and are not reversable.
|
|
||||||
|
|
||||||
Hard Disk:
|
ARMmon > download kernel tftp zimage 192.168.1.202
|
||||||
1. Build a directdisk image format. This will generate proper partition tables
|
ARMmon > flash kernel
|
||||||
that will in turn be written to the physical media. For example:
|
|
||||||
|
|
||||||
$ bitbake poky-image-minimal-directdisk
|
where zimage is the name of the kernel on the TFTP server and its IP address is
|
||||||
|
192.168.1.202. The names of the files must be all lowercase.
|
||||||
|
|
||||||
2. Use the "dd" utility to write the image to the raw block device. For example:
|
To reflash the initrd/initramfs:
|
||||||
|
|
||||||
# dd if=poky-image-minimal-directdisk-atom-pc.hdddirect of=/dev/sdb
|
ARMmon > download ramdisk tftp diskimage 192.168.1.202
|
||||||
|
ARMmon > flash ramdisk
|
||||||
|
|
||||||
USB Device:
|
where diskimage is the name of the initramfs image (a cpio.gz file).
|
||||||
1. Build an hddimg image format. This is a simple filesystem without partition
|
|
||||||
tables and is suitable for USB keys. For example:
|
|
||||||
|
|
||||||
$ bitbake poky-image-minimal-live
|
To boot the initramfs:
|
||||||
|
|
||||||
2. Use the "dd" utility to write the image to the raw block device. For
|
ARMmon > ramdisk on
|
||||||
example:
|
ARMmon > bootos "console=ttyS0,38400 rdinit=/sbin/init"
|
||||||
|
|
||||||
# dd if=poky-image-minimal-live-atom-pc.hddimg of=/dev/sdb
|
To reflash the main image login to the system as user "root", then run:
|
||||||
|
|
||||||
If the device fails to boot with "Boot error" displayed, it is likely the BIOS
|
# ifconfig eth0 192.168.1.203
|
||||||
cannot understand the physical layout of the disk (or rather it expects a
|
# tftp -g -r mainimage 192.168.1.202
|
||||||
particular layout and cannot handle anything else). There are two possible
|
# flash_eraseall /dev/mtd1
|
||||||
solutions to this problem:
|
# nandwrite /dev/mtd1 mainimage
|
||||||
|
|
||||||
1. Change the BIOS USB Device setting to HDD mode. The label will vary by
|
which configures the network interface with the IP address 192.168.1.203,
|
||||||
device, but the idea is to force BIOS to read the Cylinder/Head/Sector
|
downloads the "mainimage" file from the TFTP server at 192.168.1.202, erases
|
||||||
geometry from the device.
|
the flash and then writes the new image to the flash.
|
||||||
|
|
||||||
2. Without such an option, the BIOS generally boots the device in USB-ZIP
|
The main image can then be booted with:
|
||||||
mode.
|
|
||||||
|
|
||||||
a. Configure the USB device for USB-ZIP mode:
|
ARMmon > bootos "console=ttyS0,38400 root=/dev/mtdblock1 rootfstype=jffs2"
|
||||||
|
|
||||||
# mkdiskimage -4 /dev/sdb 0 63 62
|
Note that the initramfs image is built by poky in a slightly different mode to
|
||||||
|
normal since it uses uclibc. To generate this use a command like:
|
||||||
|
|
||||||
Where 63 and 62 are the head and sector count as reported by fdisk.
|
IMAGE_FSTYPES=cpio.gz MACHINE=cm-x270 POKYLIBC=uclibc bitbake poky-image-minimal-mtdutils
|
||||||
Remove and reinsert the device to allow the kernel to detect the new
|
|
||||||
partition layout.
|
|
||||||
|
|
||||||
b. Copy the contents of the poky image to the USB-ZIP mode device:
|
|
||||||
|
|
||||||
# mount -o loop poky-image-minimal-live-atom-pc.hddimg /tmp/image
|
Compulab EM-X270 (em-x270)
|
||||||
# mount /dev/sdb4 /tmp/usbkey
|
==========================
|
||||||
# cp -rf /tmp/image/* /tmp/usbkey
|
|
||||||
|
|
||||||
c. Install the syslinux boot loader:
|
Fetch the "Linux - kernel and run-time image (Angstrom)" ZIP file from the
|
||||||
|
Compulab website. Inside the images directory of this ZIP file is another ZIP
|
||||||
|
file called 'LiveDisk.zip'. Extract this over a cleanly formatted vfat USB flash
|
||||||
|
drive. Replace the 'em_x270.img' file with the 'updater-em-x270.ext2' file.
|
||||||
|
|
||||||
# syslinux /dev/sdb4
|
Insert this USB disk into the supplied adapter and connect this to the
|
||||||
|
board. Whilst holding down the the suspend button press the reset button. The
|
||||||
|
board will now boot off the USB key and into a version of Angstrom. On the
|
||||||
|
desktop is an icon labelled "Updater". Run this program to launch the updater
|
||||||
|
that will flash the Poky kernel and rootfs to the board.
|
||||||
|
|
||||||
Install the boot device in the target board and configure the BIOS to boot
|
|
||||||
from it.
|
|
||||||
|
|
||||||
For more details on the USB-ZIP scenario, see the syslinux documentation:
|
FreeScale iMX31ADS (mx31ads)
|
||||||
http://git.kernel.org/?p=boot/syslinux/syslinux.git;a=blob_plain;f=doc/usbkey.txt;hb=HEAD
|
===========================
|
||||||
|
|
||||||
|
The correct serial port is the top-most female connector to the right of the
|
||||||
|
ethernet socket.
|
||||||
|
|
||||||
Texas Instruments Beagleboard (beagleboard)
|
For uploading data to RedBoot we are going to use tftp. In this example we
|
||||||
===========================================
|
assume that the tftpserver is on 192.168.9.1 and the board is on192.168.9.2.
|
||||||
|
|
||||||
The Beagleboard is an ARM Cortex-A8 development board with USB, DVI-D, S-Video,
|
To set the IP address, run:
|
||||||
2D/3D accelerated graphics, audio, serial, JTAG, and SD/MMC. The xM adds a
|
|
||||||
faster CPU, more RAM, an ethernet port, more USB ports, microSD, and removes
|
|
||||||
the NAND flash. The beagleboard MACHINE is tested on the following platforms:
|
|
||||||
|
|
||||||
o Beagleboard xM
|
ip_address -l 192.168.9.2/24 -h 192.168.9.1
|
||||||
|
|
||||||
TODO: need someone with a Beagleboard C4 to verify these instructions.
|
To download a kernel called "zimage" from the TFTP server, run:
|
||||||
|
|
||||||
Due to the lack of NAND on the xM, the install and boot process varies a bit
|
load -r -b 0x100000 zimage
|
||||||
between boards. The C4 can run the x-loader and u-boot binaries from NAND or
|
|
||||||
the SD, while the xM can only run them from the SD. The following instructions
|
|
||||||
apply to both the C4 and the xM, but the C4 can skip step 2 (as noted below),
|
|
||||||
and may require modification of the NAND environment.
|
|
||||||
|
|
||||||
1. Partition and format an SD card:
|
To write the kernel to flash run:
|
||||||
# fdisk -lu /dev/mmcblk0
|
|
||||||
|
|
||||||
Disk /dev/mmcblk0: 3951 MB, 3951034368 bytes
|
fis create kernel
|
||||||
255 heads, 63 sectors/track, 480 cylinders, total 7716864 sectors
|
|
||||||
Units = sectors of 1 * 512 = 512 bytes
|
|
||||||
|
|
||||||
Device Boot Start End Blocks Id System
|
To download a rootfs jffs2 image "rootfs" from the TFTP server, run:
|
||||||
/dev/mmcblk0p1 * 63 144584 72261 c Win95 FAT32 (LBA)
|
|
||||||
/dev/mmcblk0p2 144585 465884 160650 83 Linux
|
|
||||||
|
|
||||||
# mkfs.vfat -F 16 -n "boot" /dev/mmcblk0p1
|
load -r -b 0x100000 rootfs
|
||||||
# mke2fs -j -L "root" /dev/mmcblk0p2
|
|
||||||
|
|
||||||
The following assumes the SD card partition 1 and 2 are mounted at
|
To write the root filesystem to flash run:
|
||||||
/media/boot and /media/root respectively. The files referenced here
|
|
||||||
are made available after the build in build/tmp/deploy/images.
|
|
||||||
|
|
||||||
2. Install the boot loaders
|
fis create root
|
||||||
This step can be omitted for the C4 as it can have the x-loader and
|
|
||||||
u-boot installed in NAND.
|
|
||||||
|
|
||||||
# cp MLO-beagleboard /media/boot/MLO
|
To load and boot a kernel and rootfs from flash:
|
||||||
# cp u-boot-beagleboard.bin /media/boot/u-boot.bin
|
|
||||||
|
|
||||||
3. Install the root filesystem
|
fis load kernel
|
||||||
# tar x -C /media/root -f poky-image-$IMAGE_TYPE-beagleboard.tar.bz2
|
exec -b 0x100000 -l 0x200000 -c "noinitrd console=ttymxc0,115200 root=/dev/mtdblock2 rootfstype=jffs2 init=linuxrc ip=none"
|
||||||
# tar x -C /media/root -f modules-$KERNEL_VERSION-beagleboard.tgz
|
|
||||||
|
|
||||||
4. Install the kernel uImage
|
To load and boot a kernel from a TFTP server with the rootfs over NFS:
|
||||||
# cp uImage-beagleboard.bin /media/boot/uImage
|
|
||||||
|
|
||||||
5. Prepare a u-boot script to simplify the boot process
|
load -r -b 0x100000 zimage
|
||||||
The Beagleboard can be made to boot at this point from the u-boot command
|
exec -b 0x100000 -l 0x200000 -c "noinitrd console=ttymxc0,115200 root=/dev/nfs nfsroot=192.168.9.1:/mnt/nfsmx31 rw ip=192.168.9.2::192.168.9.1:255.255.255.0"
|
||||||
shell. To automate this process, generate a user.scr script as follows.
|
|
||||||
|
|
||||||
Install uboot-mkimage (from uboot-mkimage on Ubuntu or uboot-tools on Fedora).
|
The instructions above are for using the (default) NOR flash on the board,
|
||||||
|
there is also 128M of NAND flash. It is possible to install Poky to the NAND
|
||||||
|
flash which gives more space for the rootfs and instructions for using this are
|
||||||
|
given below. To switch to the NAND flash:
|
||||||
|
|
||||||
Prepare a script config:
|
factive NAND
|
||||||
|
|
||||||
# (cat << EOF
|
This will then restart RedBoot using the NAND rather than the NOR. If you
|
||||||
setenv bootcmd 'mmc init; fatload mmc 0:1 0x80300000 uImage; bootm 0x80300000'
|
have not used the NAND before then it is unlikely that there will be a
|
||||||
setenv bootargs 'console=tty0 console=ttyO2,115200n8 root=/dev/mmcblk0p2 rootwait rootfstype=ext3 ro'
|
partition table yet. You can get the list of partitions with 'fis list'.
|
||||||
boot
|
|
||||||
EOF
|
|
||||||
) > serial-boot.cmd
|
|
||||||
# mkimage -A arm -O linux -T script -C none -a 0 -e 0 -n "Poky Minimal" -d ./serial-boot.cmd ./boot.scr
|
|
||||||
# cp boot.scr /media/boot
|
|
||||||
|
|
||||||
6. Unmount the SD partitions and boot the Beagleboard
|
If this shows no partitions then you can create them with:
|
||||||
|
|
||||||
Note: As of the 2.6.37 linux-yocto kernel recipe, the Beagleboard uses the
|
fis init
|
||||||
OMAP_SERIAL device (ttyO2). If you are using an older kernel, such as the
|
|
||||||
2.6.35 linux-yocto-stable, be sure replace ttyO2 with ttyS2 above. You
|
|
||||||
should also override the machine SERIAL_CONSOLE in your local.conf in
|
|
||||||
order to setup the getty on the serial line:
|
|
||||||
|
|
||||||
SERIAL_CONSOLE_beagleboard = "115200 ttyS2"
|
The output of 'fis list' should now show:
|
||||||
|
|
||||||
|
Name FLASH addr Mem addr Length Entry point
|
||||||
|
RedBoot 0xE0000000 0xE0000000 0x00040000 0x00000000
|
||||||
|
FIS directory 0xE7FF4000 0xE7FF4000 0x00003000 0x00000000
|
||||||
|
RedBoot config 0xE7FF7000 0xE7FF7000 0x00001000 0x00000000
|
||||||
|
|
||||||
Freescale MPC8315E-RDB (mpc8315e-rdb)
|
Partitions for the kernel and rootfs need to be created:
|
||||||
=====================================
|
|
||||||
|
|
||||||
The MPC8315 PowerPC reference platform (MPC8315E-RDB) is aimed at hardware and
|
fis create -l 0x1A0000 -e 0x00100000 kernel
|
||||||
software development of network attached storage (NAS) and digital media server
|
fis create -l 0x5000000 -e 0x00100000 root
|
||||||
applications. The MPC8315E-RDB features the PowerQUICC II Pro processor, which
|
|
||||||
includes a built-in security accelerator.
|
|
||||||
|
|
||||||
Setup instructions
|
You may now use the instructions above for flashing. However it is important
|
||||||
------------------
|
to note that the erase block size for the NAND is different to the NOR so the
|
||||||
|
JFFS erase size will need to be changed to 0x4000. Stardard images are built
|
||||||
|
for NOR and you will need to build custom images for NAND.
|
||||||
|
|
||||||
You will need the following:
|
You will also need to update the kernel command line to use the correct root
|
||||||
* nfs root setup on your workstation
|
filesystem. This should be '/dev/mtdblock7' if you adhere to the partitioning
|
||||||
* tftp server installed on your workstation
|
scheme shown above. If this fails then you can doublecheck against the output
|
||||||
|
from the kernel when it evaluates the available mtd partitions.
|
||||||
|
|
||||||
The original U-Boot image on board can't boot kernel versions 2.6.34 or later
|
|
||||||
successfully, so the U-Boot image should be upgraded to the latest U-Boot.
|
|
||||||
|
|
||||||
1. First build a new U-Boot image for mpc8315e-rdb, u-boot.bin.mpc8315erdb,
|
Marvell PXA3xx Zylonite (zylonite)
|
||||||
then make it available on your tftp server. To compile the new u-boot:
|
==================================
|
||||||
|
|
||||||
$ git clone git://git.denx.de/u-boot.git
|
These instructions assume the Zylonite is connected to a machine running a TFTP
|
||||||
$ cd u-boot
|
server at address 192.168.123.5 and that a serial link (38400 8N1) is available
|
||||||
$ git checkout -b v2010.09-mpc8315erdb v2010.09
|
to access the blob bootloader. The kernel is on the TFTP server as
|
||||||
$ make ARCH=powerpc CROSS_COMPILE=<powerpc cross compiler path> MPC8315ERDB_config
|
"zylonite-kernel" and the root filesystem jffs2 file is "zylonite-rootfs" and
|
||||||
$ make ARCH=powerpc CROSS_COMPILE=<powerpc cross compiler path> all
|
the images are to be saved in NAND flash.
|
||||||
$ cp u-boot.bin u-boot.bin.mpc8315erdb
|
|
||||||
|
|
||||||
2. Set up the environment in U-Boot:
|
The following commands setup blob:
|
||||||
|
|
||||||
=>setenv ipaddr <board ip>
|
blob> setip client 192.168.123.4
|
||||||
=>setenv serverip <tftp server ip>
|
blob> setip server 192.168.123.5
|
||||||
|
|
||||||
3. Flash the new U-Boot image:
|
To flash the kernel:
|
||||||
|
|
||||||
=>tftp 200000 u-boot.bin.mpc8315erdb
|
blob> tftp zylonite-kernel
|
||||||
=>protect off all
|
blob> nandwrite -j 0x80800000 0x60000 0x200000
|
||||||
=>erase fe000000 +60000
|
|
||||||
=>cp.b 200000 fe000000 60000
|
|
||||||
|
|
||||||
Then the kernel can be booted successfully:
|
To flash the rootfs:
|
||||||
|
|
||||||
1. Get the kernel (uImage.mpc8315erdb) and dtb (mpc8315erdb.dtb) files from
|
blob> tftp zylonite-rootfs
|
||||||
the Poky build tmp/deploy directory, and make them available on your tftp
|
blob> nanderase -j 0x260000 0x5000000
|
||||||
server.
|
blob> nandwrite -j 0x80800000 0x260000 <length>
|
||||||
|
|
||||||
2. Set up the environment in U-Boot:
|
(where <length> is the rootfs size which will be printed by the tftp step)
|
||||||
|
|
||||||
=>setenv bootargs root=/dev/nfs rw nfsroot=<nfsroot ip>:<rootfs path> ip=<board ip>:<server ip>:<gateway ip>:255.255.255.0:mpc8315e:eth0:off console=ttyS0,115200
|
To boot the board:
|
||||||
|
|
||||||
3. Download kernel and dtb to boot kernel.
|
blob> nkernel
|
||||||
|
blob> boot
|
||||||
|
|
||||||
=>tftp 800000 uImage.mpc8315erdb
|
|
||||||
=>tftp 780000 mpc8315erdb.dtb
|
|
||||||
=>bootm 800000 - 780000
|
|
||||||
|
|
||||||
|
Logic iMX31 Lite Kit (mx31litekit)
|
||||||
|
===============================
|
||||||
|
|
||||||
Ubiquiti Networks RouterStation Pro (routerstationpro)
|
The easiest method to boot this board is to take an MMC/SD card and format
|
||||||
======================================================
|
the first partition as ext2, then extract the poky image onto this as root.
|
||||||
|
Assuming the board is network connected, a TFTP server is available at
|
||||||
|
192.168.1.33 and a serial terminal is available (115200 8N1), the following
|
||||||
|
commands will boot a kernel called "mx31kern" from the TFTP server:
|
||||||
|
|
||||||
The RouterStation Pro is an Atheros AR7161 MIPS-based board. Geared towards
|
losh> ifconfig sm0 192.168.1.203 255.255.255.0 192.168.1.33
|
||||||
networking applications, it has all of the usual features as well as three
|
losh> load raw 0x80100000 0x200000 /tftp/192.168.1.33:mx31kern
|
||||||
type IIIA mini-PCI slots and an on-board 3-port 10/100/1000 Ethernet switch,
|
losh> exec 0x80100000 -
|
||||||
in addition to the 10/100/1000 Ethernet WAN port which supports
|
|
||||||
Power-over-Ethernet.
|
|
||||||
|
|
||||||
Setup instructions
|
|
||||||
------------------
|
|
||||||
|
|
||||||
You will need the following:
|
Phytec phyCORE-iMX31 (mx31phy)
|
||||||
* A serial cable - female to female (or female to male + gender changer)
|
==============================
|
||||||
NOTE: cable must be straight through, *not* a null modem cable.
|
|
||||||
* USB flash drive or hard disk that is able to be powered from the
|
|
||||||
board's USB port.
|
|
||||||
* tftp server installed on your workstation
|
|
||||||
|
|
||||||
NOTE: in the following instructions it is assumed that /dev/sdb corresponds
|
Support for this board is currently being developed. Experimental jffs2
|
||||||
to the USB disk when it is plugged into your workstation. If this is not the
|
images and a suitable kernel are available and are known to work with the
|
||||||
case in your setup then please be careful to substitute the correct device
|
board.
|
||||||
name in all commands where appropriate.
|
|
||||||
|
|
||||||
--- Preparation ---
|
|
||||||
|
|
||||||
1) Build an image (e.g. poky-image-minimal) using "routerstationpro" as the
|
Consumer Devices
|
||||||
MACHINE
|
================
|
||||||
|
|
||||||
2) Partition the USB drive so that primary partition 1 is type Linux (83).
|
FIC Neo1973 GTA01 smartphone (fic-gta01)
|
||||||
Minimum size depends on your root image size - poky-image-minimal probably
|
========================================
|
||||||
only needs 8-16MB, other images will need more.
|
|
||||||
|
|
||||||
# fdisk /dev/sdb
|
To install Poky on a GTA01 smartphone you will need "dfu-util" tool
|
||||||
Command (m for help): p
|
which you can build with "bitbake dfu-util-native" command.
|
||||||
|
|
||||||
Disk /dev/sdb: 4011 MB, 4011491328 bytes
|
Flashing requires these steps:
|
||||||
124 heads, 62 sectors/track, 1019 cylinders, total 7834944 sectors
|
|
||||||
Units = sectors of 1 * 512 = 512 bytes
|
|
||||||
Sector size (logical/physical): 512 bytes / 512 bytes
|
|
||||||
I/O size (minimum/optimal): 512 bytes / 512 bytes
|
|
||||||
Disk identifier: 0x0009e87d
|
|
||||||
|
|
||||||
Device Boot Start End Blocks Id System
|
1. Power down the device.
|
||||||
/dev/sdb1 62 1952751 976345 83 Linux
|
2. Connect the device to the host machine via USB.
|
||||||
|
3. Hold AUX key and press Power key. There should be a bootmenu
|
||||||
|
on screen.
|
||||||
|
4. Run "dfu-util -l" to check if the phone is visible on the USB bus.
|
||||||
|
The output should look like this:
|
||||||
|
|
||||||
3) Format partition 1 on the USB as ext3
|
dfu-util - (C) 2007 by OpenMoko Inc.
|
||||||
|
This program is Free Software and has ABSOLUTELY NO WARRANTY
|
||||||
|
|
||||||
# mke2fs -j /dev/sdb1
|
Found Runtime: [0x1457:0x5119] devnum=19, cfg=0, intf=2, alt=0, name="USB Device Firmware Upgrade"
|
||||||
|
|
||||||
4) Mount partition 1 and then extract the contents of
|
5. Flash the kernel with "dfu-util -a kernel -D uImage-2.6.21.6-moko11-r2-fic-gta01.bin"
|
||||||
tmp/deploy/images/poky-image-XXXX.tar.bz2 into it (preserving permissions).
|
6. Flash rootfs with "dfu-util -a rootfs -D <image>", where <image> is the
|
||||||
|
jffs2 image file to use as the root filesystem
|
||||||
|
(e.g. ./tmp/deploy/images/poky-image-sato-fic-gta01.jffs2)
|
||||||
|
|
||||||
# mount /dev/sdb1 /media/sdb1
|
|
||||||
# cd /media/sdb1
|
|
||||||
# tar -xvjpf tmp/deploy/images/poky-image-XXXX.tar.bz2
|
|
||||||
|
|
||||||
5) Unmount the USB drive and then plug it into the board's USB port
|
HTC Universal (htcuniversal)
|
||||||
|
============================
|
||||||
|
|
||||||
6) Connect the board's serial port to your workstation and then start up
|
Note: HTC Universal support is highly experimental.
|
||||||
your favourite serial terminal so that you will be able to interact with
|
|
||||||
the serial console. If you don't have a favourite, picocom is suggested:
|
|
||||||
|
|
||||||
$ picocom /dev/ttyUSB0 -b 115200
|
On the HTC Universal, entirely replacing the Windows installation is not
|
||||||
|
supported, instead Poky is booted from an MMC/SD card from Windows. Once Poky
|
||||||
|
has booted, Windows is no longer in memory or active but when power is removed,
|
||||||
|
the user will be returned to windows and will need to return to Linux from
|
||||||
|
there.
|
||||||
|
|
||||||
7) Connect the network into eth0 (the one that is NOT the 3 port switch). If
|
Once an MMC/SD card is available it is suggested its split into two partitions,
|
||||||
you are using power-over-ethernet then the board will power up at this point.
|
one for a program called HaRET which lets you boot Linux from within Windows
|
||||||
|
and the second for the rootfs. The HaRET partition should be the first partition
|
||||||
|
on the card and be vfat formatted. It doesn't need to be large, just enough for
|
||||||
|
HaRET and a kernel (say 5MB max). The rootfs should be ext2 and is usually the
|
||||||
|
second partition. The first partition should be vfat so Windows recognises it
|
||||||
|
as if it doesn't, it has been known to reformat cards.
|
||||||
|
|
||||||
8) Start up the board, watch the serial console. Hit Ctrl+C to abort the
|
On the first partition you need three files:
|
||||||
autostart if the board is configured that way (it is by default). The
|
|
||||||
bootloader's fconfig command can be used to disable autostart and configure
|
|
||||||
the IP settings if you need to change them (default IP is 192.168.1.20).
|
|
||||||
|
|
||||||
9) Make the kernel (tmp/deploy/images/vmlinux-routerstationpro.bin) available
|
* a HaRET binary (version 0.5.1 works well and a working version
|
||||||
on the tftp server.
|
should be part of the last Poky release)
|
||||||
|
* a kernel renamed to "zImage"
|
||||||
|
* a default.txt which contains:
|
||||||
|
|
||||||
10) If you are going to write the kernel to flash (optional - see "Booting a
|
set kernel "zImage"
|
||||||
kernel directly" below for the alternative), remove the current kernel and
|
set mtype "855"
|
||||||
rootfs flash partitions. You can list the partitions using the following
|
set cmdline "root=/dev/mmcblk0p2 rw console=ttyS0,115200n8 console=tty0 rootdelay=5 fbcon=rotate:1"
|
||||||
bootloader command:
|
boot2
|
||||||
|
|
||||||
RedBoot> fis list
|
On the second parition the root file system is extracted as root. A different
|
||||||
|
partition layout or other kernel options can be changed in the default.txt file.
|
||||||
|
|
||||||
You can delete the existing kernel and rootfs with these commands:
|
When inserted into the device, Windows should see the card and let you browse
|
||||||
|
its contents using File Explorer. Running the HaRET binary will present a dialog
|
||||||
|
box (maybe after messages warning about running unsigned binaries) where you
|
||||||
|
select OK and you should then see Poky boot. Kernel messages can be seen by
|
||||||
|
adding psplash=false to the kernel commandline.
|
||||||
|
|
||||||
RedBoot> fis delete kernel
|
|
||||||
RedBoot> fis delete rootfs
|
|
||||||
|
|
||||||
--- Booting a kernel directly ---
|
Nokia 770/N800/N810 Internet Tablets (nokia770 and nokia800)
|
||||||
|
============================================================
|
||||||
|
|
||||||
1) Load the kernel using the following bootloader command:
|
Note: Nokia tablet support is highly experimental.
|
||||||
|
|
||||||
RedBoot> load -m tftp -h <ip of tftp server> vmlinux-routerstationpro.bin
|
The Nokia internet tablet devices are OMAP based tablet formfactor devices
|
||||||
|
with large screens (800x480), wifi and touchscreen.
|
||||||
|
|
||||||
You should see a message on it being successfully loaded.
|
To flash images to these devices you need the "flasher" utility which can be
|
||||||
|
downloaded from the http://tablets-dev.nokia.com/d3.php?f=flasher-3.0. This
|
||||||
|
utility needs to be run as root and the usb filesystem needs to be mounted
|
||||||
|
although most distributions will have done this for you. Once you have this
|
||||||
|
follow these steps:
|
||||||
|
|
||||||
2) Execute the kernel:
|
1. Power down the device.
|
||||||
|
2. Connect the device to the host machine via USB
|
||||||
|
(connecting power to the device doesn't hurt either).
|
||||||
|
3. Run "flasher -i"
|
||||||
|
4. Power on the device.
|
||||||
|
5. The program should give an indication it's found
|
||||||
|
a tablet device. If not, recheck the cables, make sure you're
|
||||||
|
root and usbfs/usbdevfs is mounted.
|
||||||
|
6. Run "flasher -r <image> -k <kernel> -f", where <image> is the
|
||||||
|
jffs2 image file to use as the root filesystem
|
||||||
|
(e.g. ./tmp/deploy/images/poky-image-sato-nokia800.jffs2)
|
||||||
|
and <kernel> is the kernel to use
|
||||||
|
(e.g. ./tmp/deploy/images/zImage-nokia800.bin).
|
||||||
|
7. Run "flasher -R" to reboot the device.
|
||||||
|
8. The device should boot into Poky.
|
||||||
|
|
||||||
RedBoot> exec -c "console=ttyS0,115200 root=/dev/sda1 rw rootdelay=2 board=UBNT-RSPRO"
|
The nokia800 images and kernel will run on both the N800 and N810.
|
||||||
|
|
||||||
Note that specifying the command line with -c is important as linux-yocto does
|
|
||||||
not provide a default command line.
|
|
||||||
|
|
||||||
--- Writing a kernel to flash ---
|
Sharp Zaurus SL-C7x0 series (c7x0)
|
||||||
|
==================================
|
||||||
|
|
||||||
1) Go to your tftp server and gzip the kernel you want in flash. It should
|
The Sharp Zaurus c7x0 series (SL-C700, SL-C750, SL-C760, SL-C860, SL-7500)
|
||||||
halve the size.
|
are PXA25x based handheld PDAs with VGA screens. To install Poky images on
|
||||||
|
these devices follow these steps:
|
||||||
|
|
||||||
2) Load the kernel using the following bootloader command:
|
1. Obtain an SD/MMC or CF card with a vfat or ext2 filesystem.
|
||||||
|
2. Copy a jffs2 image file (e.g. poky-image-sato-c7x0.jffs2) onto the
|
||||||
|
card as "initrd.bin":
|
||||||
|
|
||||||
RedBoot> load -r -b 0x80600000 -m tftp -h <ip of tftp server> vmlinux-routerstationpro.bin.gz
|
$ cp ./tmp/deploy/images/poky-image-sato-c7x0.jffs2 /path/to/my-cf-card/initrd.bin
|
||||||
|
|
||||||
This should output something similar to the following:
|
3. Copy an Linux kernel file (zImage-c7x0.bin) onto the card as
|
||||||
|
"zImage.bin":
|
||||||
|
|
||||||
Raw file loaded 0x80600000-0x8087c537, assumed entry at 0x80600000
|
$ cp ./tmp/deploy/images/zImage-c7x0.bin /path/to/my-cf-card/zImage.bin
|
||||||
|
|
||||||
Calculate the length by subtracting the first number from the second number
|
4. Copy an updater script (updater.sh.c7x0) onto the card
|
||||||
and then rounding the result up to the nearest 0x1000.
|
as "updater.sh":
|
||||||
|
|
||||||
3) Using the length calculated above, create a flash partition for the kernel:
|
$ cp ./tmp/deploy/images/updater.sh.c7x0 /path/to/my-cf-card/updater.sh
|
||||||
|
|
||||||
RedBoot> fis create -b 0x80600000 -l 0x240000 kernel
|
5. Power down the Zaurus.
|
||||||
|
6. Hold "OK" key and power on the device. An update menu should appear
|
||||||
|
(in Japanese).
|
||||||
|
7. Choose "Update" (item 4).
|
||||||
|
8. The next screen will ask for the source, choose the appropriate
|
||||||
|
card (CF or SD).
|
||||||
|
9. Make sure AC power is connected.
|
||||||
|
10. The next screen asks for confirmation, choose "Yes" (the left button).
|
||||||
|
11. The update process will start, flash the files on the card onto
|
||||||
|
the device and the device will then reboot into Poky.
|
||||||
|
|
||||||
(change 0x240000 to your rounded length -- change "kernel" to whatever
|
|
||||||
you want to name your kernel)
|
|
||||||
|
|
||||||
--- Booting a kernel from flash ---
|
Sharp Zaurus SL-C1000 (akita)
|
||||||
|
=============================
|
||||||
|
|
||||||
To boot the flashed kernel perform the following steps.
|
The Sharp Zaurus SL-C1000 is a PXA270 based device otherwise similar to the
|
||||||
|
c7x0. To install Poky images on this device follow the instructions for
|
||||||
|
the c7x0 but replace "c7x0" with "akita" where appropriate.
|
||||||
|
|
||||||
1) At the bootloader prompt, load the kernel:
|
|
||||||
|
|
||||||
RedBoot> fis load -d -e kernel
|
Sharp Zaurus SL-C3x00 series (spitz)
|
||||||
|
====================================
|
||||||
|
|
||||||
|
The Sharp Zaurus SL-C3x00 devices are PXA270 based devices similar
|
||||||
|
to akita but with an internal microdrive. The installation procedure
|
||||||
|
assumes a standard microdrive based device where the root (first)
|
||||||
|
partition has been enlarged to fit the image (at least 100MB,
|
||||||
|
400MB for the SDK).
|
||||||
|
|
||||||
|
The procedure is the same as for the c7x0 and akita models with the
|
||||||
|
following differences:
|
||||||
|
|
||||||
|
1. Instead of a jffs2 image you need to copy a compressed tarball of the
|
||||||
|
root fileystem (e.g. poky-image-sato-spitz.tar.gz) onto the
|
||||||
|
card as "hdimage1.tgz":
|
||||||
|
|
||||||
|
$ cp ./tmp/deploy/images/poky-image-sato-spitz.tar.gz /path/to/my-cf-card/hdimage1.tgz
|
||||||
|
|
||||||
|
2. You additionally need to copy a special tar utility (gnu-tar) onto
|
||||||
|
the card as "gnu-tar":
|
||||||
|
|
||||||
|
$ cp ./tmp/deploy/images/gnu-tar /path/to/my-cf-card/gnu-tar
|
||||||
|
|
||||||
(Change the name "kernel" above if you chose something different earlier)
|
|
||||||
|
|
||||||
(-e means 'elf', -d 'decompress')
|
|
||||||
|
|
||||||
2) Execute the kernel using the exec command as above.
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
Tim Ansell <mithro@mithis.net>
|
Tim Ansell <mithro@mithis.net>
|
||||||
Phil Blundell <pb@handhelds.org>
|
Phil Blundell <pb@handhelds.org>
|
||||||
Seb Frankengul <seb@frankengul.org>
|
Seb Frankengul <seb@frankengul.org>
|
||||||
Holger Freyther <holger@moiji-mobile.com>
|
Holger Freyther <zecke@handhelds.org>
|
||||||
Marcin Juszkiewicz <marcin@juszkiewicz.com.pl>
|
Marcin Juszkiewicz <marcin@juszkiewicz.com.pl>
|
||||||
Chris Larson <kergoth@handhelds.org>
|
Chris Larson <kergoth@handhelds.org>
|
||||||
Ulrich Luckas <luckas@musoft.de>
|
Ulrich Luckas <luckas@musoft.de>
|
||||||
|
|||||||
@@ -23,18 +23,14 @@
|
|||||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import sys, logging
|
import sys
|
||||||
sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(__file__)),
|
sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(sys.argv[0])),
|
||||||
'lib'))
|
'lib'))
|
||||||
|
|
||||||
import optparse
|
import optparse
|
||||||
import warnings
|
import warnings
|
||||||
from traceback import format_exception
|
from traceback import format_exception
|
||||||
try:
|
import bb
|
||||||
import bb
|
|
||||||
except RuntimeError, exc:
|
|
||||||
sys.exit(str(exc))
|
|
||||||
from bb import event
|
|
||||||
import bb.msg
|
import bb.msg
|
||||||
from bb import cooker
|
from bb import cooker
|
||||||
from bb import ui
|
from bb import ui
|
||||||
@@ -43,9 +39,12 @@ from bb.server import none
|
|||||||
#from bb.server import xmlrpc
|
#from bb.server import xmlrpc
|
||||||
|
|
||||||
__version__ = "1.11.0"
|
__version__ = "1.11.0"
|
||||||
logger = logging.getLogger("BitBake")
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#============================================================================#
|
||||||
|
# BBOptions
|
||||||
|
#============================================================================#
|
||||||
class BBConfiguration(object):
|
class BBConfiguration(object):
|
||||||
"""
|
"""
|
||||||
Manages build options and configurations for one run
|
Manages build options and configurations for one run
|
||||||
@@ -57,44 +56,34 @@ class BBConfiguration(object):
|
|||||||
self.pkgs_to_build = []
|
self.pkgs_to_build = []
|
||||||
|
|
||||||
|
|
||||||
def get_ui(config):
|
def print_exception(exc, value, tb):
|
||||||
if config.ui:
|
"""Send exception information through bb.msg"""
|
||||||
interface = config.ui
|
bb.fatal("".join(format_exception(exc, value, tb, limit=8)))
|
||||||
else:
|
|
||||||
interface = 'knotty'
|
|
||||||
|
|
||||||
try:
|
sys.excepthook = print_exception
|
||||||
# Dynamically load the UI based on the ui name. Although we
|
|
||||||
# suggest a fixed set this allows you to have flexibility in which
|
|
||||||
# ones are available.
|
|
||||||
module = __import__("bb.ui", fromlist = [interface])
|
|
||||||
return getattr(module, interface).main
|
|
||||||
except AttributeError:
|
|
||||||
sys.exit("FATAL: Invalid user interface '%s' specified.\n"
|
|
||||||
"Valid interfaces: depexp, goggle, ncurses, knotty [default]." % interface)
|
|
||||||
|
|
||||||
|
|
||||||
# Display bitbake/OE warnings via the BitBake.Warnings logger, ignoring others"""
|
|
||||||
warnlog = logging.getLogger("BitBake.Warnings")
|
|
||||||
_warnings_showwarning = warnings.showwarning
|
_warnings_showwarning = warnings.showwarning
|
||||||
def _showwarning(message, category, filename, lineno, file=None, line=None):
|
def _showwarning(message, category, filename, lineno, file=None, line=None):
|
||||||
|
"""Display python warning messages using bb.msg"""
|
||||||
if file is not None:
|
if file is not None:
|
||||||
if _warnings_showwarning is not None:
|
if _warnings_showwarning is not None:
|
||||||
_warnings_showwarning(message, category, filename, lineno, file, line)
|
_warnings_showwarning(message, category, filename, lineno, file, line)
|
||||||
else:
|
else:
|
||||||
s = warnings.formatwarning(message, category, filename, lineno)
|
s = warnings.formatwarning(message, category, filename, lineno)
|
||||||
warnlog.warn(s)
|
s = s.split("\n")[0]
|
||||||
|
bb.msg.warn(None, s)
|
||||||
|
|
||||||
warnings.showwarning = _showwarning
|
warnings.showwarning = _showwarning
|
||||||
warnings.filterwarnings("ignore")
|
warnings.simplefilter("ignore", DeprecationWarning)
|
||||||
warnings.filterwarnings("default", module="(<string>$|(oe|bb)\.)")
|
|
||||||
warnings.filterwarnings("ignore", category=PendingDeprecationWarning)
|
|
||||||
warnings.filterwarnings("ignore", category=ImportWarning)
|
|
||||||
warnings.filterwarnings("ignore", category=DeprecationWarning, module="<string>$")
|
|
||||||
warnings.filterwarnings("ignore", message="With-statements now directly support multiple context managers")
|
|
||||||
|
|
||||||
|
#============================================================================#
|
||||||
|
# main
|
||||||
|
#============================================================================#
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
return_value = 1
|
||||||
|
|
||||||
parser = optparse.OptionParser(
|
parser = optparse.OptionParser(
|
||||||
version = "BitBake Build Tool Core version %s, %%prog version %s" % (bb.__version__, __version__),
|
version = "BitBake Build Tool Core version %s, %%prog version %s" % (bb.__version__, __version__),
|
||||||
usage = """%prog [options] [package ...]
|
usage = """%prog [options] [package ...]
|
||||||
@@ -170,11 +159,6 @@ Default BBFILES are the .bb files in the current directory.""")
|
|||||||
configuration.pkgs_to_build.extend(args[1:])
|
configuration.pkgs_to_build.extend(args[1:])
|
||||||
configuration.initial_path = os.environ['PATH']
|
configuration.initial_path = os.environ['PATH']
|
||||||
|
|
||||||
ui_main = get_ui(configuration)
|
|
||||||
|
|
||||||
loghandler = event.LogHandler()
|
|
||||||
logger.addHandler(loghandler)
|
|
||||||
|
|
||||||
#server = bb.server.xmlrpc
|
#server = bb.server.xmlrpc
|
||||||
server = bb.server.none
|
server = bb.server.none
|
||||||
|
|
||||||
@@ -191,17 +175,16 @@ Default BBFILES are the .bb files in the current directory.""")
|
|||||||
bb.utils.clean_environment()
|
bb.utils.clean_environment()
|
||||||
|
|
||||||
cooker = bb.cooker.BBCooker(configuration, server)
|
cooker = bb.cooker.BBCooker(configuration, server)
|
||||||
|
|
||||||
cooker.parseCommandLine()
|
cooker.parseCommandLine()
|
||||||
|
|
||||||
serverinfo = server.BitbakeServerInfo(cooker.server)
|
serverinfo = server.BitbakeServerInfo(cooker.server)
|
||||||
|
|
||||||
server.BitBakeServerFork(cooker, cooker.server, serverinfo, cooker_logfile)
|
server.BitBakeServerFork(serverinfo, cooker.serve, cooker_logfile)
|
||||||
del cooker
|
del cooker
|
||||||
|
|
||||||
logger.removeHandler(loghandler)
|
|
||||||
|
|
||||||
# Setup a connection to the server (cooker)
|
# Setup a connection to the server (cooker)
|
||||||
server_connection = server.BitBakeServerConnection(serverinfo)
|
serverConnection = server.BitBakeServerConnection(serverinfo)
|
||||||
|
|
||||||
# Launch the UI
|
# Launch the UI
|
||||||
if configuration.ui:
|
if configuration.ui:
|
||||||
@@ -210,15 +193,25 @@ Default BBFILES are the .bb files in the current directory.""")
|
|||||||
ui = "knotty"
|
ui = "knotty"
|
||||||
|
|
||||||
try:
|
try:
|
||||||
return server.BitbakeUILauch().launch(serverinfo, ui_main, server_connection.connection, server_connection.events)
|
# Dynamically load the UI based on the ui name. Although we
|
||||||
|
# suggest a fixed set this allows you to have flexibility in which
|
||||||
|
# ones are available.
|
||||||
|
uimodule = __import__("bb.ui", fromlist = [ui])
|
||||||
|
ui_init = getattr(uimodule, ui).init
|
||||||
|
except AttributeError:
|
||||||
|
print("FATAL: Invalid user interface '%s' specified. " % ui)
|
||||||
|
print("Valid interfaces are 'ncurses', 'depexp' or the default, 'knotty'.")
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
return_value = ui_init(serverConnection.connection, serverConnection.events)
|
||||||
|
except Exception as e:
|
||||||
|
print("FATAL: Unable to start to '%s' UI: %s" % (ui, e))
|
||||||
|
raise
|
||||||
finally:
|
finally:
|
||||||
server_connection.terminate()
|
serverConnection.terminate()
|
||||||
|
|
||||||
|
return return_value
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
try:
|
ret = main()
|
||||||
ret = main()
|
|
||||||
except Exception:
|
|
||||||
ret = 1
|
|
||||||
import traceback
|
|
||||||
traceback.print_exc(5)
|
|
||||||
sys.exit(ret)
|
sys.exit(ret)
|
||||||
|
|||||||
@@ -1,158 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
|
|
||||||
# This script has subcommands which operate against your bitbake layers, either
|
|
||||||
# displaying useful information, or acting against them.
|
|
||||||
# Currently, it only provides a show_appends command, which shows you what
|
|
||||||
# bbappends are in effect, and warns you if you have appends which are not being
|
|
||||||
# utilized.
|
|
||||||
|
|
||||||
import cmd
|
|
||||||
import logging
|
|
||||||
import os.path
|
|
||||||
import sys
|
|
||||||
|
|
||||||
bindir = os.path.dirname(__file__)
|
|
||||||
topdir = os.path.dirname(bindir)
|
|
||||||
sys.path[0:0] = [os.path.join(topdir, 'lib')]
|
|
||||||
|
|
||||||
import bb.cache
|
|
||||||
import bb.cooker
|
|
||||||
import bb.providers
|
|
||||||
from bb.cooker import state
|
|
||||||
from bb.server import none
|
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger('BitBake')
|
|
||||||
default_cmd = 'show_appends'
|
|
||||||
|
|
||||||
|
|
||||||
def main(args):
|
|
||||||
logging.basicConfig(format='%(levelname)s: %(message)s')
|
|
||||||
bb.utils.clean_environment()
|
|
||||||
|
|
||||||
cmds = Commands()
|
|
||||||
if args:
|
|
||||||
cmds.onecmd(' '.join(args))
|
|
||||||
else:
|
|
||||||
cmds.onecmd(default_cmd)
|
|
||||||
return cmds.returncode
|
|
||||||
|
|
||||||
|
|
||||||
class Commands(cmd.Cmd):
|
|
||||||
def __init__(self):
|
|
||||||
cmd.Cmd.__init__(self)
|
|
||||||
|
|
||||||
self.returncode = 0
|
|
||||||
self.config = Config(parse_only=True)
|
|
||||||
self.cooker = bb.cooker.BBCooker(self.config,
|
|
||||||
bb.server.none)
|
|
||||||
self.config_data = self.cooker.configuration.data
|
|
||||||
bb.providers.logger.setLevel(logging.ERROR)
|
|
||||||
self.prepare_cooker()
|
|
||||||
|
|
||||||
def prepare_cooker(self):
|
|
||||||
sys.stderr.write("Parsing recipes..")
|
|
||||||
logger.setLevel(logging.ERROR)
|
|
||||||
|
|
||||||
try:
|
|
||||||
while self.cooker.state in (state.initial, state.parsing):
|
|
||||||
self.cooker.updateCache()
|
|
||||||
except KeyboardInterrupt:
|
|
||||||
self.cooker.shutdown()
|
|
||||||
self.cooker.updateCache()
|
|
||||||
sys.exit(2)
|
|
||||||
|
|
||||||
logger.setLevel(logging.INFO)
|
|
||||||
sys.stderr.write("done.\n")
|
|
||||||
|
|
||||||
self.cooker_data = self.cooker.status
|
|
||||||
self.cooker_data.appends = self.cooker.appendlist
|
|
||||||
|
|
||||||
def do_show_layers(self, args):
|
|
||||||
logger.info(str(self.config_data.getVar('BBLAYERS', True)))
|
|
||||||
|
|
||||||
def do_show_appends(self, args):
|
|
||||||
if not self.cooker_data.appends:
|
|
||||||
logger.info('No append files found')
|
|
||||||
return
|
|
||||||
|
|
||||||
logger.info('State of append files:')
|
|
||||||
|
|
||||||
for pn in self.cooker_data.pkg_pn:
|
|
||||||
self.show_appends_for_pn(pn)
|
|
||||||
|
|
||||||
self.show_appends_with_no_recipes()
|
|
||||||
|
|
||||||
def show_appends_for_pn(self, pn):
|
|
||||||
filenames = self.cooker_data.pkg_pn[pn]
|
|
||||||
|
|
||||||
best = bb.providers.findBestProvider(pn,
|
|
||||||
self.cooker.configuration.data,
|
|
||||||
self.cooker_data,
|
|
||||||
self.cooker_data.pkg_pn)
|
|
||||||
best_filename = os.path.basename(best[3])
|
|
||||||
|
|
||||||
appended, missing = self.get_appends_for_files(filenames)
|
|
||||||
if appended:
|
|
||||||
for basename, appends in appended:
|
|
||||||
logger.info('%s:', basename)
|
|
||||||
for append in appends:
|
|
||||||
logger.info(' %s', append)
|
|
||||||
|
|
||||||
if best_filename in missing:
|
|
||||||
logger.warn('%s: missing append for preferred version',
|
|
||||||
best_filename)
|
|
||||||
self.returncode |= 1
|
|
||||||
|
|
||||||
def get_appends_for_files(self, filenames):
|
|
||||||
appended, notappended = set(), set()
|
|
||||||
for filename in filenames:
|
|
||||||
_, cls = bb.cache.Cache.virtualfn2realfn(filename)
|
|
||||||
if cls:
|
|
||||||
continue
|
|
||||||
|
|
||||||
basename = os.path.basename(filename)
|
|
||||||
appends = self.cooker_data.appends.get(basename)
|
|
||||||
if appends:
|
|
||||||
appended.add((basename, frozenset(appends)))
|
|
||||||
else:
|
|
||||||
notappended.add(basename)
|
|
||||||
return appended, notappended
|
|
||||||
|
|
||||||
def show_appends_with_no_recipes(self):
|
|
||||||
recipes = set(os.path.basename(f)
|
|
||||||
for f in self.cooker_data.pkg_fn.iterkeys())
|
|
||||||
appended_recipes = self.cooker_data.appends.iterkeys()
|
|
||||||
appends_without_recipes = [self.cooker_data.appends[recipe]
|
|
||||||
for recipe in appended_recipes
|
|
||||||
if recipe not in recipes]
|
|
||||||
if appends_without_recipes:
|
|
||||||
appendlines = (' %s' % append
|
|
||||||
for appends in appends_without_recipes
|
|
||||||
for append in appends)
|
|
||||||
logger.warn('No recipes available for:\n%s',
|
|
||||||
'\n'.join(appendlines))
|
|
||||||
self.returncode |= 4
|
|
||||||
|
|
||||||
def do_EOF(self, line):
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
class Config(object):
|
|
||||||
def __init__(self, **options):
|
|
||||||
self.pkgs_to_build = []
|
|
||||||
self.debug_domains = []
|
|
||||||
self.extra_assume_provided = []
|
|
||||||
self.file = []
|
|
||||||
self.debug = 0
|
|
||||||
self.__dict__.update(options)
|
|
||||||
|
|
||||||
def __getattr__(self, attribute):
|
|
||||||
try:
|
|
||||||
return super(Config, self).__getattribute__(attribute)
|
|
||||||
except AttributeError:
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
sys.exit(main(sys.argv[1:]) or 0)
|
|
||||||
@@ -100,9 +100,6 @@ the_data = cooker.bb_cache.loadDataFull(fn, cooker.get_file_appends(fn), cooker.
|
|||||||
cooker.bb_cache.setData(fn, buildfile, the_data)
|
cooker.bb_cache.setData(fn, buildfile, the_data)
|
||||||
cooker.bb_cache.handle_data(fn, cooker.status)
|
cooker.bb_cache.handle_data(fn, cooker.status)
|
||||||
|
|
||||||
#exportlist = bb.utils.preserved_envvars_export_list()
|
|
||||||
#bb.utils.filter_environment(exportlist)
|
|
||||||
|
|
||||||
if taskname.endswith("_setscene"):
|
if taskname.endswith("_setscene"):
|
||||||
the_data.setVarFlag(taskname, "quieterrors", "1")
|
the_data.setVarFlag(taskname, "quieterrors", "1")
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
import optparse, os, sys
|
import optparse, os, sys
|
||||||
|
|
||||||
# bitbake
|
# bitbake
|
||||||
sys.path.append(os.path.join(os.path.dirname(os.path.dirname(__file__), 'lib'))
|
sys.path.append(os.path.join(os.path.dirname(os.path.dirname(sys.argv[0])), 'lib'))
|
||||||
import bb
|
import bb
|
||||||
import bb.parse
|
import bb.parse
|
||||||
from string import split, join
|
from string import split, join
|
||||||
@@ -497,7 +497,7 @@ def main():
|
|||||||
doc.insert_doc_item(doc_ins)
|
doc.insert_doc_item(doc_ins)
|
||||||
|
|
||||||
# let us create the HTML now
|
# let us create the HTML now
|
||||||
bb.utils.mkdirhier(output_dir)
|
bb.mkdirhier(output_dir)
|
||||||
os.chdir(output_dir)
|
os.chdir(output_dir)
|
||||||
|
|
||||||
# Let us create the sites now. We do it in the following order
|
# Let us create the sites now. We do it in the following order
|
||||||
|
|||||||
@@ -1,24 +1,4 @@
|
|||||||
" Vim filetype detection file
|
au BufNewFile,BufRead *.bb setfiletype bitbake
|
||||||
" Language: BitBake
|
au BufNewFile,BufRead *.bbclass setfiletype bitbake
|
||||||
" Author: Ricardo Salveti <rsalveti@rsalveti.net>
|
au BufNewFile,BufRead *.inc setfiletype bitbake
|
||||||
" Copyright: Copyright (C) 2008 Ricardo Salveti <rsalveti@rsalveti.net>
|
" au BufNewFile,BufRead *.conf setfiletype bitbake
|
||||||
" Licence: You may redistribute this under the same terms as Vim itself
|
|
||||||
"
|
|
||||||
" This sets up the syntax highlighting for BitBake files, like .bb, .bbclass and .inc
|
|
||||||
|
|
||||||
if &compatible || version < 600
|
|
||||||
finish
|
|
||||||
endif
|
|
||||||
|
|
||||||
" .bb and .bbclass
|
|
||||||
au BufNewFile,BufRead *.b{b,bclass} set filetype=bitbake
|
|
||||||
|
|
||||||
" .inc
|
|
||||||
au BufNewFile,BufRead *.inc set filetype=bitbake
|
|
||||||
|
|
||||||
" .conf
|
|
||||||
au BufNewFile,BufRead *.conf
|
|
||||||
\ if (match(expand("%:p:h"), "conf") > 0) |
|
|
||||||
\ set filetype=bitbake |
|
|
||||||
\ endif
|
|
||||||
|
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
set sts=4 sw=4 et
|
|
||||||
@@ -1,85 +0,0 @@
|
|||||||
" Vim plugin file
|
|
||||||
" Purpose: Create a template for new bb files
|
|
||||||
" Author: Ricardo Salveti <rsalveti@gmail.com>
|
|
||||||
" Copyright: Copyright (C) 2008 Ricardo Salveti <rsalveti@gmail.com>
|
|
||||||
"
|
|
||||||
" This file is licensed under the MIT license, see COPYING.MIT in
|
|
||||||
" this source distribution for the terms.
|
|
||||||
"
|
|
||||||
" Based on the gentoo-syntax package
|
|
||||||
"
|
|
||||||
" Will try to use git to find the user name and email
|
|
||||||
|
|
||||||
if &compatible || v:version < 600
|
|
||||||
finish
|
|
||||||
endif
|
|
||||||
|
|
||||||
fun! <SID>GetUserName()
|
|
||||||
let l:user_name = system("git-config --get user.name")
|
|
||||||
if v:shell_error
|
|
||||||
return "Unknow User"
|
|
||||||
else
|
|
||||||
return substitute(l:user_name, "\n", "", "")
|
|
||||||
endfun
|
|
||||||
|
|
||||||
fun! <SID>GetUserEmail()
|
|
||||||
let l:user_email = system("git-config --get user.email")
|
|
||||||
if v:shell_error
|
|
||||||
return "unknow@user.org"
|
|
||||||
else
|
|
||||||
return substitute(l:user_email, "\n", "", "")
|
|
||||||
endfun
|
|
||||||
|
|
||||||
fun! BBHeader()
|
|
||||||
let l:current_year = strftime("%Y")
|
|
||||||
let l:user_name = <SID>GetUserName()
|
|
||||||
let l:user_email = <SID>GetUserEmail()
|
|
||||||
0 put ='# Copyright (C) ' . l:current_year .
|
|
||||||
\ ' ' . l:user_name . ' <' . l:user_email . '>'
|
|
||||||
put ='# Released under the MIT license (see COPYING.MIT for the terms)'
|
|
||||||
$
|
|
||||||
endfun
|
|
||||||
|
|
||||||
fun! NewBBTemplate()
|
|
||||||
let l:paste = &paste
|
|
||||||
set nopaste
|
|
||||||
|
|
||||||
" Get the header
|
|
||||||
call BBHeader()
|
|
||||||
|
|
||||||
" New the bb template
|
|
||||||
put ='DESCRIPTION = \"\"'
|
|
||||||
put ='HOMEPAGE = \"\"'
|
|
||||||
put ='LICENSE = \"\"'
|
|
||||||
put ='SECTION = \"\"'
|
|
||||||
put ='DEPENDS = \"\"'
|
|
||||||
put ='PR = \"r0\"'
|
|
||||||
put =''
|
|
||||||
put ='SRC_URI = \"\"'
|
|
||||||
|
|
||||||
" Go to the first place to edit
|
|
||||||
0
|
|
||||||
/^DESCRIPTION =/
|
|
||||||
exec "normal 2f\""
|
|
||||||
|
|
||||||
if paste == 1
|
|
||||||
set paste
|
|
||||||
endif
|
|
||||||
endfun
|
|
||||||
|
|
||||||
if !exists("g:bb_create_on_empty")
|
|
||||||
let g:bb_create_on_empty = 1
|
|
||||||
endif
|
|
||||||
|
|
||||||
" disable in case of vimdiff
|
|
||||||
if v:progname =~ "vimdiff"
|
|
||||||
let g:bb_create_on_empty = 0
|
|
||||||
endif
|
|
||||||
|
|
||||||
augroup NewBB
|
|
||||||
au BufNewFile *.bb
|
|
||||||
\ if g:bb_create_on_empty |
|
|
||||||
\ call NewBBTemplate() |
|
|
||||||
\ endif
|
|
||||||
augroup END
|
|
||||||
|
|
||||||
@@ -1,123 +1,127 @@
|
|||||||
" Vim syntax file
|
" Vim syntax file
|
||||||
" Language: BitBake bb/bbclasses/inc
|
|
||||||
" Author: Chris Larson <kergoth@handhelds.org>
|
|
||||||
" Ricardo Salveti <rsalveti@rsalveti.net>
|
|
||||||
" Copyright: Copyright (C) 2004 Chris Larson <kergoth@handhelds.org>
|
|
||||||
" Copyright (C) 2008 Ricardo Salveti <rsalveti@rsalveti.net>
|
|
||||||
"
|
"
|
||||||
|
" Copyright (C) 2004 Chris Larson <kergoth@handhelds.org>
|
||||||
" This file is licensed under the MIT license, see COPYING.MIT in
|
" This file is licensed under the MIT license, see COPYING.MIT in
|
||||||
" this source distribution for the terms.
|
" this source distribution for the terms.
|
||||||
"
|
"
|
||||||
" Syntax highlighting for bb, bbclasses and inc files.
|
" Language: BitBake
|
||||||
"
|
" Maintainer: Chris Larson <kergoth@handhelds.org>
|
||||||
" It's an entirely new type, just has specific syntax in shell and python code
|
" Filenames: *.bb, *.bbclass
|
||||||
|
|
||||||
if &compatible || v:version < 600
|
if version < 600
|
||||||
finish
|
syntax clear
|
||||||
endif
|
elseif exists("b:current_syntax")
|
||||||
if exists("b:current_syntax")
|
finish
|
||||||
finish
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
syn case match
|
||||||
|
|
||||||
|
" Catch incorrect syntax (only matches if nothing else does)
|
||||||
|
"
|
||||||
|
syn match bbUnmatched "."
|
||||||
|
|
||||||
|
|
||||||
syn include @python syntax/python.vim
|
syn include @python syntax/python.vim
|
||||||
if exists("b:current_syntax")
|
if exists("b:current_syntax")
|
||||||
unlet b:current_syntax
|
unlet b:current_syntax
|
||||||
endif
|
endif
|
||||||
|
|
||||||
" BitBake syntax
|
|
||||||
|
|
||||||
" Matching case
|
" Other
|
||||||
syn case match
|
|
||||||
|
|
||||||
" Indicates the error when nothing is matched
|
syn match bbComment "^#.*$" display contains=bbTodo
|
||||||
syn match bbUnmatched "."
|
syn keyword bbTodo TODO FIXME XXX contained
|
||||||
|
syn match bbDelimiter "[(){}=]" contained
|
||||||
|
syn match bbQuote /['"]/ contained
|
||||||
|
syn match bbArrayBrackets "[\[\]]" contained
|
||||||
|
|
||||||
" Comments
|
|
||||||
syn cluster bbCommentGroup contains=bbTodo,@Spell
|
|
||||||
syn keyword bbTodo COMBAK FIXME TODO XXX contained
|
|
||||||
syn match bbComment "#.*$" contains=@bbCommentGroup
|
|
||||||
|
|
||||||
" String helpers
|
|
||||||
syn match bbQuote +['"]+ contained
|
|
||||||
syn match bbDelimiter "[(){}=]" contained
|
|
||||||
syn match bbArrayBrackets "[\[\]]" contained
|
|
||||||
|
|
||||||
" BitBake strings
|
" BitBake strings
|
||||||
syn match bbContinue "\\$"
|
|
||||||
syn region bbString matchgroup=bbQuote start=+"+ skip=+\\$+ excludenl end=+"+ contained keepend contains=bbTodo,bbContinue,bbVarDeref,bbVarPyValue,@Spell
|
|
||||||
syn region bbString matchgroup=bbQuote start=+'+ skip=+\\$+ excludenl end=+'+ contained keepend contains=bbTodo,bbContinue,bbVarDeref,bbVarPyValue,@Spell
|
|
||||||
|
|
||||||
" Vars definition
|
syn match bbContinue "\\$"
|
||||||
syn match bbExport "^export" nextgroup=bbIdentifier skipwhite
|
syn region bbString matchgroup=bbQuote start=/"/ skip=/\\$/ excludenl end=/"/ contained keepend contains=bbTodo,bbContinue,bbVarInlinePy,bbVarDeref
|
||||||
syn keyword bbExportFlag export contained nextgroup=bbIdentifier skipwhite
|
syn region bbString matchgroup=bbQuote start=/'/ skip=/\\$/ excludenl end=/'/ contained keepend contains=bbTodo,bbContinue,bbVarInlinePy,bbVarDeref
|
||||||
syn match bbIdentifier "[a-zA-Z0-9\-_\.\/\+]\+" display contained
|
|
||||||
syn match bbVarDeref "${[a-zA-Z0-9\-_\.\/\+]\+}" contained
|
|
||||||
syn match bbVarEq "\(:=\|+=\|=+\|\.=\|=\.\|?=\|=\)" contained nextgroup=bbVarValue
|
|
||||||
syn match bbVarDef "^\(export\s*\)\?\([a-zA-Z0-9\-_\.\/\+]\+\(_[${}a-zA-Z0-9\-_\.\/\+]\+\)\?\)\s*\(:=\|+=\|=+\|\.=\|=\.\|?=\|=\)\@=" contains=bbExportFlag,bbIdentifier,bbVarDeref nextgroup=bbVarEq
|
|
||||||
syn match bbVarValue ".*$" contained contains=bbString,bbVarDeref,bbVarPyValue
|
|
||||||
syn region bbVarPyValue start=+${@+ skip=+\\$+ excludenl end=+}+ contained contains=@python
|
|
||||||
|
|
||||||
" Vars metadata flags
|
" BitBake variable metadata
|
||||||
syn match bbVarFlagDef "^\([a-zA-Z0-9\-_\.]\+\)\(\[[a-zA-Z0-9\-_\.]\+\]\)\@=" contains=bbIdentifier nextgroup=bbVarFlagFlag
|
|
||||||
syn region bbVarFlagFlag matchgroup=bbArrayBrackets start="\[" end="\]\s*\(=\)\@=" keepend excludenl contained contains=bbIdentifier nextgroup=bbVarEq
|
|
||||||
|
|
||||||
" Includes and requires
|
syn match bbVarBraces "[\${}]"
|
||||||
syn keyword bbInclude inherit include require contained
|
syn region bbVarDeref matchgroup=bbVarBraces start="${" end="}" contained
|
||||||
syn match bbIncludeRest ".*$" contained contains=bbString,bbVarDeref
|
" syn region bbVarDeref start="${" end="}" contained
|
||||||
syn match bbIncludeLine "^\(inherit\|include\|require\)\s\+" contains=bbInclude nextgroup=bbIncludeRest
|
" syn region bbVarInlinePy start="${@" end="}" contained contains=@python
|
||||||
|
syn region bbVarInlinePy matchgroup=bbVarBraces start="${@" end="}" contained contains=@python
|
||||||
|
|
||||||
" Add taks and similar
|
syn keyword bbExportFlag export contained nextgroup=bbIdentifier skipwhite
|
||||||
syn keyword bbStatement addtask addhandler after before EXPORT_FUNCTIONS contained
|
" syn match bbVarDeref "${[a-zA-Z0-9\-_\.]\+}" contained
|
||||||
syn match bbStatementRest ".*$" skipwhite contained contains=bbStatement
|
syn match bbVarDef "^\(export\s*\)\?\([a-zA-Z0-9\-_\.]\+\(_[${}a-zA/-Z0-9\-_\.]\+\)\?\)\s*\(:=\|+=\|=+\|\.=\|=\.\|?=\|=\)\@=" contains=bbExportFlag,bbIdentifier,bbVarDeref nextgroup=bbVarEq
|
||||||
syn match bbStatementLine "^\(addtask\|addhandler\|after\|before\|EXPORT_FUNCTIONS\)\s\+" contains=bbStatement nextgroup=bbStatementRest
|
|
||||||
|
|
||||||
" OE Important Functions
|
syn match bbIdentifier "[a-zA-Z0-9\-_\./]\+" display contained
|
||||||
syn keyword bbOEFunctions do_fetch do_unpack do_patch do_configure do_compile do_stage do_install do_package contained
|
"syn keyword bbVarEq = display contained nextgroup=bbVarValue
|
||||||
|
syn match bbVarEq "\(:=\|+=\|=+\|\.=\|=\.\|?=\|=\)" contained nextgroup=bbVarValue
|
||||||
|
syn match bbVarValue ".*$" contained contains=bbString
|
||||||
|
|
||||||
|
" BitBake variable metadata flags
|
||||||
|
syn match bbVarFlagDef "^\([a-zA-Z0-9\-_\.]\+\)\(\[[a-zA-Z0-9\-_\.]\+\]\)\@=" contains=bbIdentifier nextgroup=bbVarFlagFlag
|
||||||
|
syn region bbVarFlagFlag matchgroup=bbArrayBrackets start="\[" end="\]\s*\(=\)\@=" keepend excludenl contained contains=bbIdentifier nextgroup=bbVarEq
|
||||||
|
"syn match bbVarFlagFlag "\[\([a-zA-Z0-9\-_\.]\+\)\]\s*\(=\)\@=" contains=bbIdentifier nextgroup=bbVarEq
|
||||||
|
|
||||||
|
|
||||||
|
" Functions!
|
||||||
|
syn match bbFunction "\h\w*" display contained
|
||||||
|
|
||||||
|
|
||||||
|
" BitBake python metadata
|
||||||
|
|
||||||
|
syn keyword bbPythonFlag python contained nextgroup=bbFunction
|
||||||
|
syn match bbPythonFuncDef "^\(python\s\+\)\(\w\+\)\?\(\s*()\s*\)\({\)\@=" contains=bbPythonFlag,bbFunction,bbDelimiter nextgroup=bbPythonFuncRegion skipwhite
|
||||||
|
syn region bbPythonFuncRegion matchgroup=bbDelimiter start="{\s*$" end="^}\s*$" keepend contained contains=@python
|
||||||
|
"hi def link bbPythonFuncRegion Comment
|
||||||
|
|
||||||
" Generic Functions
|
|
||||||
syn match bbFunction "\h[0-9A-Za-z_-]*" display contained contains=bbOEFunctions
|
|
||||||
|
|
||||||
" BitBake shell metadata
|
" BitBake shell metadata
|
||||||
syn include @shell syntax/sh.vim
|
syn include @shell syntax/sh.vim
|
||||||
if exists("b:current_syntax")
|
if exists("b:current_syntax")
|
||||||
unlet b:current_syntax
|
unlet b:current_syntax
|
||||||
endif
|
endif
|
||||||
syn keyword bbShFakeRootFlag fakeroot contained
|
|
||||||
syn match bbShFuncDef "^\(fakeroot\s*\)\?\([0-9A-Za-z_-]\+\)\(python\)\@<!\(\s*()\s*\)\({\)\@=" contains=bbShFakeRootFlag,bbFunction,bbDelimiter nextgroup=bbShFuncRegion skipwhite
|
|
||||||
syn region bbShFuncRegion matchgroup=bbDelimiter start="{\s*$" end="^}\s*$" keepend contained contains=@shell
|
|
||||||
|
|
||||||
" BitBake python metadata
|
syn keyword bbFakerootFlag fakeroot contained nextgroup=bbFunction
|
||||||
syn keyword bbPyFlag python contained
|
syn match bbShellFuncDef "^\(fakeroot\s*\)\?\(\w\+\)\(python\)\@<!\(\s*()\s*\)\({\)\@=" contains=bbFakerootFlag,bbFunction,bbDelimiter nextgroup=bbShellFuncRegion skipwhite
|
||||||
syn match bbPyFuncDef "^\(python\s\+\)\([0-9A-Za-z_-]\+\)\?\(\s*()\s*\)\({\)\@=" contains=bbPyFlag,bbFunction,bbDelimiter nextgroup=bbPyFuncRegion skipwhite
|
syn region bbShellFuncRegion matchgroup=bbDelimiter start="{\s*$" end="^}\s*$" keepend contained contains=@shell
|
||||||
syn region bbPyFuncRegion matchgroup=bbDelimiter start="{\s*$" end="^}\s*$" keepend contained contains=@python
|
"hi def link bbShellFuncRegion Comment
|
||||||
|
|
||||||
|
|
||||||
" BitBake 'def'd python functions
|
" BitBake 'def'd python functions
|
||||||
syn keyword bbPyDef def contained
|
syn keyword bbDef def contained
|
||||||
syn region bbPyDefRegion start='^\(def\s\+\)\([0-9A-Za-z_-]\+\)\(\s*(.*)\s*\):\s*$' end='^\(\s\|$\)\@!' contains=@python
|
syn region bbDefRegion start='^def\s\+\w\+\s*([^)]*)\s*:\s*$' end='^\(\s\|$\)\@!' contains=@python
|
||||||
|
|
||||||
" Highlighting Definitions
|
|
||||||
hi def link bbUnmatched Error
|
" BitBake statements
|
||||||
hi def link bbInclude Include
|
syn keyword bbStatement include inherit require addtask addhandler EXPORT_FUNCTIONS display contained
|
||||||
hi def link bbTodo Todo
|
syn match bbStatementLine "^\(include\|inherit\|require\|addtask\|addhandler\|EXPORT_FUNCTIONS\)\s\+" contains=bbStatement nextgroup=bbStatementRest
|
||||||
hi def link bbComment Comment
|
syn match bbStatementRest ".*$" contained contains=bbString,bbVarDeref
|
||||||
hi def link bbQuote String
|
|
||||||
hi def link bbString String
|
" Highlight
|
||||||
hi def link bbDelimiter Keyword
|
"
|
||||||
hi def link bbArrayBrackets Statement
|
hi def link bbArrayBrackets Statement
|
||||||
hi def link bbContinue Special
|
hi def link bbUnmatched Error
|
||||||
hi def link bbExport Type
|
hi def link bbContinue Special
|
||||||
hi def link bbExportFlag Type
|
hi def link bbDef Statement
|
||||||
hi def link bbIdentifier Identifier
|
hi def link bbPythonFlag Type
|
||||||
hi def link bbVarDeref PreProc
|
hi def link bbExportFlag Type
|
||||||
hi def link bbVarDef Identifier
|
hi def link bbFakerootFlag Type
|
||||||
hi def link bbVarValue String
|
hi def link bbStatement Statement
|
||||||
hi def link bbShFakeRootFlag Type
|
hi def link bbString String
|
||||||
hi def link bbFunction Function
|
hi def link bbTodo Todo
|
||||||
hi def link bbPyFlag Type
|
hi def link bbComment Comment
|
||||||
hi def link bbPyDef Statement
|
hi def link bbOperator Operator
|
||||||
hi def link bbStatement Statement
|
hi def link bbError Error
|
||||||
hi def link bbStatementRest Identifier
|
hi def link bbFunction Function
|
||||||
hi def link bbOEFunctions Special
|
hi def link bbDelimiter Delimiter
|
||||||
hi def link bbVarPyValue PreProc
|
hi def link bbIdentifier Identifier
|
||||||
|
hi def link bbVarEq Operator
|
||||||
|
hi def link bbQuote String
|
||||||
|
hi def link bbVarValue String
|
||||||
|
" hi def link bbVarInlinePy PreProc
|
||||||
|
hi def link bbVarDeref PreProc
|
||||||
|
hi def link bbVarBraces PreProc
|
||||||
|
|
||||||
let b:current_syntax = "bb"
|
let b:current_syntax = "bb"
|
||||||
|
|||||||
@@ -318,7 +318,7 @@ a per URI parameters separated by a <quote>;</quote> consisting of a key and a v
|
|||||||
<title>CVS File Fetcher</title>
|
<title>CVS File Fetcher</title>
|
||||||
<para>The URN for the CVS Fetcher is <emphasis>cvs</emphasis>. This Fetcher honors the variables <varname>DL_DIR</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 should be used when doing the CVS checkout or update.
|
<para>The URN for the CVS Fetcher is <emphasis>cvs</emphasis>. This Fetcher honors the variables <varname>DL_DIR</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 should be used when doing the CVS checkout or update.
|
||||||
</para>
|
</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>. If <varname>scmdata</varname> is set to <quote>keep</quote>
|
<para>The supported Parameters are <varname>module</varname>, <varname>tag</varname>, <varname>date</varname>, <varname>method</varname>, <varname>localdir</varname>, <varname>rsh</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"
|
<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"
|
<varname>SRC_URI</varname> = "cvs://CVSROOT;module=mymodule;date=20060126;localdir=usethat"
|
||||||
</screen>
|
</screen>
|
||||||
@@ -351,7 +351,7 @@ will be tried first when fetching a file if that fails the actual file will be t
|
|||||||
</para>
|
</para>
|
||||||
<para>This Fetcher honors the variables <varname>FETCHCOMMAND_svn</varname>, <varname>DL_DIR</varname>, <varname>SRCDATE</varname>. <varname>FETCHCOMMAND</varname> contains the subversion command, <varname>DL_DIR</varname> is the directory where tarballs will be 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).
|
<para>This Fetcher honors the variables <varname>FETCHCOMMAND_svn</varname>, <varname>DL_DIR</varname>, <varname>SRCDATE</varname>. <varname>FETCHCOMMAND</varname> contains the subversion command, <varname>DL_DIR</varname> is the directory where tarballs will be 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).
|
||||||
</para>
|
</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>The supported Parameters are <varname>proto</varname>, <varname>rev</varname>. <varname>proto</varname> is the subversion prototype, <varname>rev</varname> is the subversions revision.
|
||||||
</para>
|
</para>
|
||||||
<para><screen><varname>SRC_URI</varname> = "svn://svn.oe.handhelds.org/svn;module=vip;proto=http;rev=667"
|
<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"
|
<varname>SRC_URI</varname> = "svn://svn.oe.handhelds.org/svn/;module=opie;proto=svn+ssh;date=20060126"
|
||||||
@@ -364,7 +364,7 @@ will be tried first when fetching a file if that fails the actual file will be t
|
|||||||
</para>
|
</para>
|
||||||
<para>The Variables <varname>DL_DIR</varname>, <varname>GITDIR</varname> are used. <varname>DL_DIR</varname> will be used to store the checkedout version. <varname>GITDIR</varname> will be used as the base directory where the git tree is cloned to.
|
<para>The Variables <varname>DL_DIR</varname>, <varname>GITDIR</varname> are used. <varname>DL_DIR</varname> will be used to store the checkedout version. <varname>GITDIR</varname> will be used as the base directory where the git tree is cloned to.
|
||||||
</para>
|
</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>rsync</quote>. If <emphasis>scmdata</emphasis> is set to <quote>keep</quote>, the <quote>.git</quote> directory will be available during compile-time.
|
<para>The Parameters are <emphasis>tag</emphasis>, <emphasis>protocol</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>rsync</quote>.
|
||||||
</para>
|
</para>
|
||||||
<para><screen><varname>SRC_URI</varname> = "git://git.oe.handhelds.org/git/vip.git;tag=version-1"
|
<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"
|
<varname>SRC_URI</varname> = "git://git.oe.handhelds.org/git/vip.git;protocol=http"
|
||||||
|
|||||||
@@ -28,41 +28,6 @@ if sys.version_info < (2, 6, 0):
|
|||||||
raise RuntimeError("Sorry, python 2.6.0 or later is required for this version of bitbake")
|
raise RuntimeError("Sorry, python 2.6.0 or later is required for this version of bitbake")
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import logging
|
|
||||||
import traceback
|
|
||||||
|
|
||||||
class NullHandler(logging.Handler):
|
|
||||||
def emit(self, record):
|
|
||||||
pass
|
|
||||||
|
|
||||||
Logger = logging.getLoggerClass()
|
|
||||||
class BBLogger(Logger):
|
|
||||||
def __init__(self, name):
|
|
||||||
if name.split(".")[0] == "BitBake":
|
|
||||||
self.debug = self.bbdebug
|
|
||||||
Logger.__init__(self, name)
|
|
||||||
|
|
||||||
def bbdebug(self, level, msg, *args, **kwargs):
|
|
||||||
return self.log(logging.DEBUG - level + 1, msg, *args, **kwargs)
|
|
||||||
|
|
||||||
def plain(self, msg, *args, **kwargs):
|
|
||||||
return self.log(logging.INFO + 1, msg, *args, **kwargs)
|
|
||||||
|
|
||||||
def verbose(self, msg, *args, **kwargs):
|
|
||||||
return self.log(logging.INFO - 1, msg, *args, **kwargs)
|
|
||||||
|
|
||||||
def exception(self, msg, *args, **kwargs):
|
|
||||||
return self.critical("%s\n%s" % (msg, traceback.format_exc()), *args, **kwargs)
|
|
||||||
|
|
||||||
logging.raiseExceptions = False
|
|
||||||
logging.setLoggerClass(BBLogger)
|
|
||||||
|
|
||||||
logger = logging.getLogger("BitBake")
|
|
||||||
logger.addHandler(NullHandler())
|
|
||||||
logger.setLevel(logging.INFO)
|
|
||||||
|
|
||||||
# This has to be imported after the setLoggerClass, as the import of bb.msg
|
|
||||||
# can result in construction of the various loggers.
|
|
||||||
import bb.msg
|
import bb.msg
|
||||||
|
|
||||||
if "BBDEBUG" in os.environ:
|
if "BBDEBUG" in os.environ:
|
||||||
@@ -70,29 +35,25 @@ if "BBDEBUG" in os.environ:
|
|||||||
if level:
|
if level:
|
||||||
bb.msg.set_debug_level(level)
|
bb.msg.set_debug_level(level)
|
||||||
|
|
||||||
if True or os.environ.get("BBFETCH2"):
|
|
||||||
from bb import fetch2 as fetch
|
|
||||||
sys.modules['bb.fetch'] = sys.modules['bb.fetch2']
|
|
||||||
|
|
||||||
# Messaging convenience functions
|
# Messaging convenience functions
|
||||||
def plain(*args):
|
def plain(*args):
|
||||||
logger.plain(''.join(args))
|
bb.msg.plain(''.join(args))
|
||||||
|
|
||||||
def debug(lvl, *args):
|
def debug(lvl, *args):
|
||||||
logger.debug(lvl, ''.join(args))
|
bb.msg.debug(lvl, None, ''.join(args))
|
||||||
|
|
||||||
def note(*args):
|
def note(*args):
|
||||||
logger.info(''.join(args))
|
bb.msg.note(1, None, ''.join(args))
|
||||||
|
|
||||||
def warn(*args):
|
def warn(*args):
|
||||||
logger.warn(''.join(args))
|
bb.msg.warn(None, ''.join(args))
|
||||||
|
|
||||||
def error(*args):
|
def error(*args):
|
||||||
logger.error(''.join(args))
|
bb.msg.error(None, ''.join(args))
|
||||||
|
|
||||||
def fatal(*args):
|
def fatal(*args):
|
||||||
logger.critical(''.join(args))
|
bb.msg.fatal(None, ''.join(args))
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
|
|
||||||
def deprecated(func, name = None, advice = ""):
|
def deprecated(func, name = None, advice = ""):
|
||||||
|
|||||||
@@ -25,20 +25,9 @@
|
|||||||
#
|
#
|
||||||
#Based on functions from the base bb module, Copyright 2003 Holger Schurig
|
#Based on functions from the base bb module, Copyright 2003 Holger Schurig
|
||||||
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
import logging
|
|
||||||
import bb
|
|
||||||
import bb.msg
|
|
||||||
import bb.process
|
|
||||||
from contextlib import nested
|
|
||||||
from bb import data, event, mkdirhier, utils
|
from bb import data, event, mkdirhier, utils
|
||||||
|
import bb, os, sys
|
||||||
bblogger = logging.getLogger('BitBake')
|
import bb.utils
|
||||||
logger = logging.getLogger('BitBake.Build')
|
|
||||||
|
|
||||||
NULL = open(os.devnull, 'r+')
|
|
||||||
|
|
||||||
|
|
||||||
# When we execute a python function we'd like certain things
|
# When we execute a python function we'd like certain things
|
||||||
# in all namespaces, hence we add them to __builtins__
|
# in all namespaces, hence we add them to __builtins__
|
||||||
@@ -47,22 +36,13 @@ NULL = open(os.devnull, 'r+')
|
|||||||
__builtins__['bb'] = bb
|
__builtins__['bb'] = bb
|
||||||
__builtins__['os'] = os
|
__builtins__['os'] = os
|
||||||
|
|
||||||
|
# events
|
||||||
class FuncFailed(Exception):
|
class FuncFailed(Exception):
|
||||||
def __init__(self, name = None, logfile = None):
|
"""
|
||||||
self.logfile = logfile
|
Executed function failed
|
||||||
self.name = name
|
First parameter a message
|
||||||
if name:
|
Second paramter is a logfile (optional)
|
||||||
self.msg = "Function '%s' failed" % name
|
"""
|
||||||
else:
|
|
||||||
self.msg = "Function failed"
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
if self.logfile and os.path.exists(self.logfile):
|
|
||||||
msg = ("%s (see %s for further information)" %
|
|
||||||
(self.msg, self.logfile))
|
|
||||||
else:
|
|
||||||
msg = self.msg
|
|
||||||
return msg
|
|
||||||
|
|
||||||
class TaskBase(event.Event):
|
class TaskBase(event.Event):
|
||||||
"""Base class for task events"""
|
"""Base class for task events"""
|
||||||
@@ -89,56 +69,38 @@ class TaskSucceeded(TaskBase):
|
|||||||
|
|
||||||
class TaskFailed(TaskBase):
|
class TaskFailed(TaskBase):
|
||||||
"""Task execution failed"""
|
"""Task execution failed"""
|
||||||
|
def __init__(self, msg, logfile, t, d ):
|
||||||
def __init__(self, task, logfile, metadata):
|
|
||||||
self.logfile = logfile
|
self.logfile = logfile
|
||||||
super(TaskFailed, self).__init__(task, metadata)
|
self.msg = msg
|
||||||
|
TaskBase.__init__(self, t, d)
|
||||||
|
|
||||||
class TaskInvalid(TaskBase):
|
class TaskInvalid(TaskBase):
|
||||||
|
"""Invalid Task"""
|
||||||
|
|
||||||
def __init__(self, task, metadata):
|
# functions
|
||||||
super(TaskInvalid, self).__init__(task, metadata)
|
|
||||||
self._message = "No such task '%s'" % task
|
|
||||||
|
|
||||||
|
|
||||||
class LogTee(object):
|
|
||||||
def __init__(self, logger, outfile):
|
|
||||||
self.outfile = outfile
|
|
||||||
self.logger = logger
|
|
||||||
self.name = self.outfile.name
|
|
||||||
|
|
||||||
def write(self, string):
|
|
||||||
self.logger.plain(string)
|
|
||||||
self.outfile.write(string)
|
|
||||||
|
|
||||||
def __enter__(self):
|
|
||||||
self.outfile.__enter__()
|
|
||||||
return self
|
|
||||||
|
|
||||||
def __exit__(self, *excinfo):
|
|
||||||
self.outfile.__exit__(*excinfo)
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
return '<LogTee {0}>'.format(self.name)
|
|
||||||
|
|
||||||
|
|
||||||
def exec_func(func, d, dirs = None):
|
def exec_func(func, d, dirs = None):
|
||||||
"""Execute an BB 'function'"""
|
"""Execute an BB 'function'"""
|
||||||
|
|
||||||
body = data.getVar(func, d)
|
body = data.getVar(func, d)
|
||||||
if not body:
|
if not body:
|
||||||
if body is None:
|
bb.warn("Function %s doesn't exist" % func)
|
||||||
logger.warn("Function %s doesn't exist", func)
|
|
||||||
return
|
return
|
||||||
|
|
||||||
flags = data.getVarFlags(func, d)
|
flags = data.getVarFlags(func, d)
|
||||||
cleandirs = flags.get('cleandirs')
|
for item in ['deps', 'check', 'interactive', 'python', 'cleandirs', 'dirs', 'lockfiles', 'fakeroot', 'task']:
|
||||||
|
if not item in flags:
|
||||||
|
flags[item] = None
|
||||||
|
|
||||||
|
ispython = flags['python']
|
||||||
|
|
||||||
|
cleandirs = flags['cleandirs']
|
||||||
if cleandirs:
|
if cleandirs:
|
||||||
for cdir in data.expand(cleandirs, d).split():
|
for cdir in data.expand(cleandirs, d).split():
|
||||||
bb.utils.remove(cdir, True)
|
os.system("rm -rf %s" % cdir)
|
||||||
|
|
||||||
if dirs is None:
|
if dirs is None:
|
||||||
dirs = flags.get('dirs')
|
dirs = flags['dirs']
|
||||||
if dirs:
|
if dirs:
|
||||||
dirs = data.expand(dirs, d).split()
|
dirs = data.expand(dirs, d).split()
|
||||||
|
|
||||||
@@ -148,254 +110,277 @@ def exec_func(func, d, dirs = None):
|
|||||||
adir = dirs[-1]
|
adir = dirs[-1]
|
||||||
else:
|
else:
|
||||||
adir = data.getVar('B', d, 1)
|
adir = data.getVar('B', d, 1)
|
||||||
if not os.path.exists(adir):
|
|
||||||
adir = None
|
|
||||||
|
|
||||||
ispython = flags.get('python')
|
# Save current directory
|
||||||
if flags.get('fakeroot') and not flags.get('task'):
|
try:
|
||||||
bb.fatal("Function %s specifies fakeroot but isn't a task?!" % func)
|
prevdir = os.getcwd()
|
||||||
|
except OSError:
|
||||||
|
prevdir = data.getVar('TOPDIR', d, True)
|
||||||
|
|
||||||
lockflag = flags.get('lockfiles')
|
# Setup scriptfile
|
||||||
if lockflag:
|
t = data.getVar('T', d, 1)
|
||||||
lockfiles = [data.expand(f, d) for f in lockflag.split()]
|
if not t:
|
||||||
else:
|
raise SystemExit("T variable not set, unable to build")
|
||||||
lockfiles = None
|
bb.utils.mkdirhier(t)
|
||||||
|
runfile = "%s/run.%s.%s" % (t, func, str(os.getpid()))
|
||||||
|
logfile = d.getVar("BB_LOGFILE", True)
|
||||||
|
|
||||||
tempdir = data.getVar('T', d, 1)
|
# Change to correct directory (if specified)
|
||||||
runfile = os.path.join(tempdir, 'run.{0}.{1}'.format(func, os.getpid()))
|
if adir and os.access(adir, os.F_OK):
|
||||||
|
os.chdir(adir)
|
||||||
|
|
||||||
with bb.utils.fileslocked(lockfiles):
|
locks = []
|
||||||
|
lockfiles = flags['lockfiles']
|
||||||
|
if lockfiles:
|
||||||
|
for lock in data.expand(lockfiles, d).split():
|
||||||
|
locks.append(bb.utils.lockfile(lock))
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Run the function
|
||||||
if ispython:
|
if ispython:
|
||||||
exec_func_python(func, d, runfile, cwd=adir)
|
exec_func_python(func, d, runfile, logfile)
|
||||||
else:
|
else:
|
||||||
exec_func_shell(func, d, runfile, cwd=adir)
|
exec_func_shell(func, d, runfile, logfile, flags)
|
||||||
|
|
||||||
_functionfmt = """
|
# Restore original directory
|
||||||
def {function}(d):
|
try:
|
||||||
{body}
|
os.chdir(prevdir)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
{function}(d)
|
finally:
|
||||||
"""
|
|
||||||
logformatter = bb.msg.BBLogFormatter("%(levelname)s: %(message)s")
|
# Unlock any lockfiles
|
||||||
def exec_func_python(func, d, runfile, cwd=None):
|
for lock in locks:
|
||||||
|
bb.utils.unlockfile(lock)
|
||||||
|
|
||||||
|
def exec_func_python(func, d, runfile, logfile):
|
||||||
"""Execute a python BB 'function'"""
|
"""Execute a python BB 'function'"""
|
||||||
|
|
||||||
bbfile = d.getVar('FILE', True)
|
bbfile = bb.data.getVar('FILE', d, 1)
|
||||||
try:
|
tmp = "def " + func + "(d):\n%s" % data.getVar(func, d)
|
||||||
olddir = os.getcwd()
|
tmp += '\n' + func + '(d)'
|
||||||
except OSError:
|
|
||||||
olddir = None
|
|
||||||
code = _functionfmt.format(function=func, body=d.getVar(func, True))
|
|
||||||
bb.utils.mkdirhier(os.path.dirname(runfile))
|
|
||||||
with open(runfile, 'w') as script:
|
|
||||||
script.write(code)
|
|
||||||
|
|
||||||
if cwd:
|
|
||||||
os.chdir(cwd)
|
|
||||||
|
|
||||||
|
f = open(runfile, "w")
|
||||||
|
f.write(tmp)
|
||||||
|
comp = utils.better_compile(tmp, func, bbfile)
|
||||||
try:
|
try:
|
||||||
comp = utils.better_compile(code, func, bbfile)
|
utils.better_exec(comp, {"d": d}, tmp, bbfile)
|
||||||
utils.better_exec(comp, {"d": d}, code, bbfile)
|
|
||||||
except:
|
except:
|
||||||
if sys.exc_info()[0] in (bb.parse.SkipPackage, bb.build.FuncFailed):
|
(t, value, tb) = sys.exc_info()
|
||||||
|
|
||||||
|
if t in [bb.parse.SkipPackage, bb.build.FuncFailed]:
|
||||||
raise
|
raise
|
||||||
|
raise FuncFailed("Function %s failed" % func, logfile)
|
||||||
|
|
||||||
raise FuncFailed(func, None)
|
|
||||||
finally:
|
|
||||||
if olddir:
|
|
||||||
os.chdir(olddir)
|
|
||||||
|
|
||||||
def exec_func_shell(function, d, runfile, cwd=None):
|
def exec_func_shell(func, d, runfile, logfile, flags):
|
||||||
"""Execute a shell function from the metadata
|
"""Execute a shell BB 'function' Returns true if execution was successful.
|
||||||
|
|
||||||
|
For this, it creates a bash shell script in the tmp dectory, writes the local
|
||||||
|
data into it and finally executes. The output of the shell will end in a log file and stdout.
|
||||||
|
|
||||||
Note on directory behavior. The 'dirs' varflag should contain a list
|
Note on directory behavior. The 'dirs' varflag should contain a list
|
||||||
of the directories you need created prior to execution. The last
|
of the directories you need created prior to execution. The last
|
||||||
item in the list is where we will chdir/cd to.
|
item in the list is where we will chdir/cd to.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Don't let the emitted shell script override PWD
|
deps = flags['deps']
|
||||||
d.delVarFlag('PWD', 'export')
|
check = flags['check']
|
||||||
|
if check in globals():
|
||||||
|
if globals()[check](func, deps):
|
||||||
|
return
|
||||||
|
|
||||||
with open(runfile, 'w') as script:
|
f = open(runfile, "w")
|
||||||
script.write('#!/bin/sh -e\n')
|
f.write("#!/bin/sh -e\n")
|
||||||
if logger.isEnabledFor(logging.DEBUG):
|
if bb.msg.debug_level['default'] > 0: f.write("set -x\n")
|
||||||
script.write("set -x\n")
|
data.emit_func(func, f, d)
|
||||||
data.emit_func(function, script, d)
|
|
||||||
if cwd:
|
|
||||||
script.write("cd %s\n" % cwd)
|
|
||||||
script.write("%s\n" % function)
|
|
||||||
os.fchmod(script.fileno(), 0775)
|
|
||||||
|
|
||||||
env = {
|
f.write("cd %s\n" % os.getcwd())
|
||||||
'PATH': d.getVar('PATH', True),
|
if func: f.write("%s\n" % func)
|
||||||
'LC_ALL': 'C',
|
f.close()
|
||||||
}
|
os.chmod(runfile, 0775)
|
||||||
|
if not func:
|
||||||
|
raise FuncFailed("Function not specified for exec_func_shell")
|
||||||
|
|
||||||
cmd = runfile
|
# execute function
|
||||||
|
if flags['fakeroot'] and not flags['task']:
|
||||||
|
bb.fatal("Function %s specifies fakeroot but isn't a task?!" % func)
|
||||||
|
|
||||||
if logger.isEnabledFor(logging.DEBUG):
|
lang_environment = "LC_ALL=C "
|
||||||
logfile = LogTee(logger, sys.stdout)
|
ret = os.system('%ssh -e %s' % (lang_environment, runfile))
|
||||||
else:
|
|
||||||
logfile = sys.stdout
|
|
||||||
|
|
||||||
try:
|
if ret == 0:
|
||||||
bb.process.run(cmd, env=env, shell=False, stdin=NULL, log=logfile)
|
return
|
||||||
except bb.process.CmdError:
|
|
||||||
logfn = d.getVar('BB_LOGFILE', True)
|
|
||||||
raise FuncFailed(function, logfn)
|
|
||||||
|
|
||||||
def _task_data(fn, task, d):
|
raise FuncFailed("function %s failed" % func, logfile)
|
||||||
localdata = data.createCopy(d)
|
|
||||||
localdata.setVar('BB_FILENAME', fn)
|
|
||||||
localdata.setVar('BB_CURRENTTASK', task[3:])
|
|
||||||
localdata.setVar('OVERRIDES', 'task-%s:%s' %
|
|
||||||
(task[3:], d.getVar('OVERRIDES', False)))
|
|
||||||
localdata.finalize()
|
|
||||||
data.expandKeys(localdata)
|
|
||||||
return localdata
|
|
||||||
|
|
||||||
def _exec_task(fn, task, d, quieterr):
|
|
||||||
"""Execute a BB 'task'
|
|
||||||
|
|
||||||
Execution of a task involves a bit more setup than executing a function,
|
def exec_task(fn, task, d):
|
||||||
running it with its own local metadata, and with some useful variables set.
|
"""Execute an BB 'task'
|
||||||
"""
|
|
||||||
|
The primary difference between executing a task versus executing
|
||||||
|
a function is that a task exists in the task digraph, and therefore
|
||||||
|
has dependencies amongst other tasks."""
|
||||||
|
|
||||||
|
# Check whther this is a valid task
|
||||||
if not data.getVarFlag(task, 'task', d):
|
if not data.getVarFlag(task, 'task', d):
|
||||||
event.fire(TaskInvalid(task, d), d)
|
event.fire(TaskInvalid(task, d), d)
|
||||||
logger.error("No such task: %s" % task)
|
bb.msg.error(bb.msg.domain.Build, "No such task: %s" % task)
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
logger.debug(1, "Executing task %s", task)
|
quieterr = False
|
||||||
|
if d.getVarFlag(task, "quieterrors") is not None:
|
||||||
|
quieterr = True
|
||||||
|
|
||||||
localdata = _task_data(fn, task, d)
|
try:
|
||||||
tempdir = localdata.getVar('T', True)
|
bb.msg.debug(1, bb.msg.domain.Build, "Executing task %s" % task)
|
||||||
if not tempdir:
|
old_overrides = data.getVar('OVERRIDES', d, 0)
|
||||||
bb.fatal("T variable not set, unable to build")
|
localdata = data.createCopy(d)
|
||||||
|
data.setVar('OVERRIDES', 'task-%s:%s' % (task[3:], old_overrides), localdata)
|
||||||
|
data.update_data(localdata)
|
||||||
|
data.expandKeys(localdata)
|
||||||
|
data.setVar('BB_FILENAME', fn, d)
|
||||||
|
data.setVar('BB_CURRENTTASK', task[3:], d)
|
||||||
|
event.fire(TaskStarted(task, localdata), localdata)
|
||||||
|
|
||||||
bb.utils.mkdirhier(tempdir)
|
# Setup logfiles
|
||||||
loglink = os.path.join(tempdir, 'log.{0}'.format(task))
|
t = data.getVar('T', d, 1)
|
||||||
logfn = os.path.join(tempdir, 'log.{0}.{1}'.format(task, os.getpid()))
|
if not t:
|
||||||
if loglink:
|
raise SystemExit("T variable not set, unable to build")
|
||||||
bb.utils.remove(loglink)
|
bb.utils.mkdirhier(t)
|
||||||
|
loglink = "%s/log.%s" % (t, task)
|
||||||
|
logfile = "%s/log.%s.%s" % (t, task, str(os.getpid()))
|
||||||
|
d.setVar("BB_LOGFILE", logfile)
|
||||||
|
|
||||||
|
# Even though the log file has not yet been opened, lets create the link
|
||||||
|
if loglink:
|
||||||
|
try:
|
||||||
|
os.remove(loglink)
|
||||||
|
except OSError as e:
|
||||||
|
pass
|
||||||
|
|
||||||
|
try:
|
||||||
|
os.symlink(logfile, loglink)
|
||||||
|
except OSError as e:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Handle logfiles
|
||||||
|
si = file('/dev/null', 'r')
|
||||||
try:
|
try:
|
||||||
os.symlink(logfn, loglink)
|
so = file(logfile, 'w')
|
||||||
except OSError:
|
except OSError as e:
|
||||||
pass
|
bb.msg.error(bb.msg.domain.Build, "opening log file: %s" % e)
|
||||||
|
pass
|
||||||
|
se = so
|
||||||
|
|
||||||
prefuncs = localdata.getVarFlag(task, 'prefuncs', expand=True)
|
# Dup the existing fds so we dont lose them
|
||||||
postfuncs = localdata.getVarFlag(task, 'postfuncs', expand=True)
|
osi = [os.dup(sys.stdin.fileno()), sys.stdin.fileno()]
|
||||||
|
oso = [os.dup(sys.stdout.fileno()), sys.stdout.fileno()]
|
||||||
|
ose = [os.dup(sys.stderr.fileno()), sys.stderr.fileno()]
|
||||||
|
|
||||||
# Handle logfiles
|
# Replace those fds with our own
|
||||||
si = file('/dev/null', 'r')
|
os.dup2(si.fileno(), osi[1])
|
||||||
try:
|
os.dup2(so.fileno(), oso[1])
|
||||||
logfile = file(logfn, 'w')
|
os.dup2(se.fileno(), ose[1])
|
||||||
except OSError:
|
|
||||||
logger.exception("Opening log file '%s'", logfn)
|
|
||||||
pass
|
|
||||||
|
|
||||||
# Dup the existing fds so we dont lose them
|
# Since we've remapped stdout and stderr, its safe for log messages to be printed there now
|
||||||
osi = [os.dup(sys.stdin.fileno()), sys.stdin.fileno()]
|
# exec_func can nest so we have to save state
|
||||||
oso = [os.dup(sys.stdout.fileno()), sys.stdout.fileno()]
|
origstdout = bb.event.useStdout
|
||||||
ose = [os.dup(sys.stderr.fileno()), sys.stderr.fileno()]
|
bb.event.useStdout = True
|
||||||
|
|
||||||
# Replace those fds with our own
|
|
||||||
os.dup2(si.fileno(), osi[1])
|
|
||||||
os.dup2(logfile.fileno(), oso[1])
|
|
||||||
os.dup2(logfile.fileno(), ose[1])
|
|
||||||
|
|
||||||
# Ensure python logging goes to the logfile
|
prefuncs = (data.getVarFlag(task, 'prefuncs', localdata) or "").split()
|
||||||
handler = logging.StreamHandler(logfile)
|
for func in prefuncs:
|
||||||
handler.setFormatter(logformatter)
|
|
||||||
bblogger.addHandler(handler)
|
|
||||||
|
|
||||||
localdata.setVar('BB_LOGFILE', logfn)
|
|
||||||
|
|
||||||
event.fire(TaskStarted(task, localdata), localdata)
|
|
||||||
try:
|
|
||||||
for func in (prefuncs or '').split():
|
|
||||||
exec_func(func, localdata)
|
exec_func(func, localdata)
|
||||||
exec_func(task, localdata)
|
exec_func(task, localdata)
|
||||||
for func in (postfuncs or '').split():
|
postfuncs = (data.getVarFlag(task, 'postfuncs', localdata) or "").split()
|
||||||
|
for func in postfuncs:
|
||||||
exec_func(func, localdata)
|
exec_func(func, localdata)
|
||||||
except FuncFailed as exc:
|
|
||||||
|
event.fire(TaskSucceeded(task, localdata), localdata)
|
||||||
|
|
||||||
|
# make stamp, or cause event and raise exception
|
||||||
|
if not data.getVarFlag(task, 'nostamp', d) and not data.getVarFlag(task, 'selfstamp', d):
|
||||||
|
make_stamp(task, d)
|
||||||
|
|
||||||
|
except FuncFailed as message:
|
||||||
|
# Try to extract the optional logfile
|
||||||
|
try:
|
||||||
|
(msg, logfile) = message
|
||||||
|
except:
|
||||||
|
logfile = None
|
||||||
|
msg = message
|
||||||
if not quieterr:
|
if not quieterr:
|
||||||
logger.error(str(exc))
|
bb.msg.error(bb.msg.domain.Build, "Task failed: %s" % message )
|
||||||
event.fire(TaskFailed(task, logfn, localdata), localdata)
|
failedevent = TaskFailed(msg, logfile, task, d)
|
||||||
|
event.fire(failedevent, d)
|
||||||
|
return 1
|
||||||
|
|
||||||
|
except Exception:
|
||||||
|
from traceback import format_exc
|
||||||
|
if not quieterr:
|
||||||
|
bb.msg.error(bb.msg.domain.Build, "Build of %s failed" % (task))
|
||||||
|
bb.msg.error(bb.msg.domain.Build, format_exc())
|
||||||
|
failedevent = TaskFailed("Task Failed", None, task, d)
|
||||||
|
event.fire(failedevent, d)
|
||||||
return 1
|
return 1
|
||||||
finally:
|
finally:
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
sys.stderr.flush()
|
sys.stderr.flush()
|
||||||
|
|
||||||
bblogger.removeHandler(handler)
|
bb.event.useStdout = origstdout
|
||||||
|
|
||||||
# Restore the backup fds
|
# Restore the backup fds
|
||||||
os.dup2(osi[0], osi[1])
|
os.dup2(osi[0], osi[1])
|
||||||
os.dup2(oso[0], oso[1])
|
os.dup2(oso[0], oso[1])
|
||||||
os.dup2(ose[0], ose[1])
|
os.dup2(ose[0], ose[1])
|
||||||
|
|
||||||
|
# Close our logs
|
||||||
|
si.close()
|
||||||
|
so.close()
|
||||||
|
se.close()
|
||||||
|
|
||||||
|
if logfile and os.path.exists(logfile) and os.path.getsize(logfile) == 0:
|
||||||
|
bb.msg.debug(2, bb.msg.domain.Build, "Zero size logfile %s, removing" % logfile)
|
||||||
|
os.remove(logfile)
|
||||||
|
try:
|
||||||
|
os.remove(loglink)
|
||||||
|
except OSError as e:
|
||||||
|
pass
|
||||||
|
|
||||||
# Close the backup fds
|
# Close the backup fds
|
||||||
os.close(osi[0])
|
os.close(osi[0])
|
||||||
os.close(oso[0])
|
os.close(oso[0])
|
||||||
os.close(ose[0])
|
os.close(ose[0])
|
||||||
si.close()
|
|
||||||
|
|
||||||
logfile.close()
|
|
||||||
if os.path.exists(logfn) and os.path.getsize(logfn) == 0:
|
|
||||||
logger.debug(2, "Zero size logfn %s, removing", logfn)
|
|
||||||
bb.utils.remove(logfn)
|
|
||||||
bb.utils.remove(loglink)
|
|
||||||
event.fire(TaskSucceeded(task, localdata), localdata)
|
|
||||||
|
|
||||||
if not localdata.getVarFlag(task, 'nostamp') and not localdata.getVarFlag(task, 'selfstamp'):
|
|
||||||
make_stamp(task, localdata)
|
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
def exec_task(fn, task, d):
|
def extract_stamp(d, fn):
|
||||||
try:
|
"""
|
||||||
quieterr = False
|
Extracts stamp format which is either a data dictionary (fn unset)
|
||||||
if d.getVarFlag(task, "quieterrors") is not None:
|
or a dataCache entry (fn set).
|
||||||
quieterr = True
|
"""
|
||||||
|
if fn:
|
||||||
|
return d.stamp[fn]
|
||||||
|
return data.getVar('STAMP', d, 1)
|
||||||
|
|
||||||
return _exec_task(fn, task, d, quieterr)
|
def stamp_internal(task, d, file_name):
|
||||||
except Exception:
|
|
||||||
from traceback import format_exc
|
|
||||||
if not quieterr:
|
|
||||||
logger.error("Build of %s failed" % (task))
|
|
||||||
logger.error(format_exc())
|
|
||||||
failedevent = TaskFailed(task, None, d)
|
|
||||||
event.fire(failedevent, d)
|
|
||||||
return 1
|
|
||||||
|
|
||||||
def stamp_internal(taskname, d, file_name):
|
|
||||||
"""
|
"""
|
||||||
Internal stamp helper function
|
Internal stamp helper function
|
||||||
|
Removes any stamp for the given task
|
||||||
Makes sure the stamp directory exists
|
Makes sure the stamp directory exists
|
||||||
Returns the stamp path+filename
|
Returns the stamp path+filename
|
||||||
|
|
||||||
In the bitbake core, d can be a CacheData and file_name will be set.
|
|
||||||
When called in task context, d will be a data store, file_name will not be set
|
|
||||||
"""
|
"""
|
||||||
taskflagname = taskname
|
stamp = extract_stamp(d, file_name)
|
||||||
if taskname.endswith("_setscene") and taskname != "do_setscene":
|
|
||||||
taskflagname = taskname.replace("_setscene", "")
|
|
||||||
|
|
||||||
if file_name:
|
|
||||||
stamp = d.stamp[file_name]
|
|
||||||
extrainfo = d.stamp_extrainfo[file_name].get(taskflagname) or ""
|
|
||||||
else:
|
|
||||||
stamp = d.getVar('STAMP', True)
|
|
||||||
file_name = d.getVar('BB_FILENAME', True)
|
|
||||||
extrainfo = d.getVarFlag(taskflagname, 'stamp-extra-info', True) or ""
|
|
||||||
|
|
||||||
if not stamp:
|
if not stamp:
|
||||||
return
|
return
|
||||||
|
stamp = "%s.%s" % (stamp, task)
|
||||||
stamp = bb.parse.siggen.stampfile(stamp, file_name, taskname, extrainfo)
|
|
||||||
|
|
||||||
bb.utils.mkdirhier(os.path.dirname(stamp))
|
bb.utils.mkdirhier(os.path.dirname(stamp))
|
||||||
|
# Remove the file and recreate to force timestamp
|
||||||
|
# change on broken NFS filesystems
|
||||||
|
if os.access(stamp, os.F_OK):
|
||||||
|
os.remove(stamp)
|
||||||
return stamp
|
return stamp
|
||||||
|
|
||||||
def make_stamp(task, d, file_name = None):
|
def make_stamp(task, d, file_name = None):
|
||||||
@@ -404,10 +389,7 @@ def make_stamp(task, d, file_name = None):
|
|||||||
(d can be a data dict or dataCache)
|
(d can be a data dict or dataCache)
|
||||||
"""
|
"""
|
||||||
stamp = stamp_internal(task, d, file_name)
|
stamp = stamp_internal(task, d, file_name)
|
||||||
# Remove the file and recreate to force timestamp
|
|
||||||
# change on broken NFS filesystems
|
|
||||||
if stamp:
|
if stamp:
|
||||||
bb.utils.remove(stamp)
|
|
||||||
f = open(stamp, "w")
|
f = open(stamp, "w")
|
||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
@@ -416,15 +398,7 @@ def del_stamp(task, d, file_name = None):
|
|||||||
Removes a stamp for a given task
|
Removes a stamp for a given task
|
||||||
(d can be a data dict or dataCache)
|
(d can be a data dict or dataCache)
|
||||||
"""
|
"""
|
||||||
stamp = stamp_internal(task, d, file_name)
|
stamp_internal(task, d, file_name)
|
||||||
bb.utils.remove(stamp)
|
|
||||||
|
|
||||||
def stampfile(taskname, d, file_name = None):
|
|
||||||
"""
|
|
||||||
Return the stamp for a given task
|
|
||||||
(d can be a data dict or dataCache)
|
|
||||||
"""
|
|
||||||
return stamp_internal(taskname, d, file_name)
|
|
||||||
|
|
||||||
def add_tasks(tasklist, d):
|
def add_tasks(tasklist, d):
|
||||||
task_deps = data.getVar('_task_deps', d)
|
task_deps = data.getVar('_task_deps', d)
|
||||||
@@ -455,7 +429,6 @@ def add_tasks(tasklist, d):
|
|||||||
getTask('recrdeptask')
|
getTask('recrdeptask')
|
||||||
getTask('nostamp')
|
getTask('nostamp')
|
||||||
getTask('fakeroot')
|
getTask('fakeroot')
|
||||||
getTask('noexec')
|
|
||||||
task_deps['parents'][task] = []
|
task_deps['parents'][task] = []
|
||||||
for dep in flags['deps']:
|
for dep in flags['deps']:
|
||||||
dep = data.expand(dep, d)
|
dep = data.expand(dep, d)
|
||||||
|
|||||||
@@ -29,165 +29,27 @@
|
|||||||
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import logging
|
|
||||||
from collections import defaultdict, namedtuple
|
|
||||||
import bb.data
|
import bb.data
|
||||||
import bb.utils
|
import bb.utils
|
||||||
|
|
||||||
logger = logging.getLogger("BitBake.Cache")
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import cPickle as pickle
|
import cPickle as pickle
|
||||||
except ImportError:
|
except ImportError:
|
||||||
import pickle
|
import pickle
|
||||||
logger.info("Importing cPickle failed. "
|
bb.msg.note(1, bb.msg.domain.Cache, "Importing cPickle failed. Falling back to a very slow implementation.")
|
||||||
"Falling back to a very slow implementation.")
|
|
||||||
|
|
||||||
__cache_version__ = "138"
|
__cache_version__ = "132"
|
||||||
|
|
||||||
recipe_fields = (
|
class Cache:
|
||||||
'pn',
|
|
||||||
'pv',
|
|
||||||
'pr',
|
|
||||||
'pe',
|
|
||||||
'defaultpref',
|
|
||||||
'depends',
|
|
||||||
'provides',
|
|
||||||
'task_deps',
|
|
||||||
'stamp',
|
|
||||||
'stamp_extrainfo',
|
|
||||||
'broken',
|
|
||||||
'not_world',
|
|
||||||
'skipped',
|
|
||||||
'timestamp',
|
|
||||||
'packages',
|
|
||||||
'packages_dynamic',
|
|
||||||
'rdepends',
|
|
||||||
'rdepends_pkg',
|
|
||||||
'rprovides',
|
|
||||||
'rprovides_pkg',
|
|
||||||
'rrecommends',
|
|
||||||
'rrecommends_pkg',
|
|
||||||
'nocache',
|
|
||||||
'variants',
|
|
||||||
'file_depends',
|
|
||||||
'tasks',
|
|
||||||
'basetaskhashes',
|
|
||||||
'hashfilename',
|
|
||||||
'inherits',
|
|
||||||
'summary',
|
|
||||||
'license',
|
|
||||||
'section',
|
|
||||||
'fakerootenv',
|
|
||||||
'fakerootdirs'
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class RecipeInfo(namedtuple('RecipeInfo', recipe_fields)):
|
|
||||||
__slots__ = ()
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def listvar(cls, var, metadata):
|
|
||||||
return cls.getvar(var, metadata).split()
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def intvar(cls, var, metadata):
|
|
||||||
return int(cls.getvar(var, metadata) or 0)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def depvar(cls, var, metadata):
|
|
||||||
return bb.utils.explode_deps(cls.getvar(var, metadata))
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def pkgvar(cls, var, packages, metadata):
|
|
||||||
return dict((pkg, cls.depvar("%s_%s" % (var, pkg), metadata))
|
|
||||||
for pkg in packages)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def taskvar(cls, var, tasks, metadata):
|
|
||||||
return dict((task, cls.getvar("%s_task-%s" % (var, task), metadata))
|
|
||||||
for task in tasks)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def flaglist(cls, flag, varlist, metadata):
|
|
||||||
return dict((var, metadata.getVarFlag(var, flag, True))
|
|
||||||
for var in varlist)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def getvar(cls, var, metadata):
|
|
||||||
return metadata.getVar(var, True) or ''
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def make_optional(cls, default=None, **kwargs):
|
|
||||||
"""Construct the namedtuple from the specified keyword arguments,
|
|
||||||
with every value considered optional, using the default value if
|
|
||||||
it was not specified."""
|
|
||||||
for field in cls._fields:
|
|
||||||
kwargs[field] = kwargs.get(field, default)
|
|
||||||
return cls(**kwargs)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def from_metadata(cls, filename, metadata):
|
|
||||||
if cls.getvar('__SKIPPED', metadata):
|
|
||||||
return cls.make_optional(skipped=True)
|
|
||||||
|
|
||||||
tasks = metadata.getVar('__BBTASKS', False)
|
|
||||||
|
|
||||||
pn = cls.getvar('PN', metadata)
|
|
||||||
packages = cls.listvar('PACKAGES', metadata)
|
|
||||||
if not pn in packages:
|
|
||||||
packages.append(pn)
|
|
||||||
|
|
||||||
return RecipeInfo(
|
|
||||||
tasks = tasks,
|
|
||||||
basetaskhashes = cls.taskvar('BB_BASEHASH', tasks, metadata),
|
|
||||||
hashfilename = cls.getvar('BB_HASHFILENAME', metadata),
|
|
||||||
|
|
||||||
file_depends = metadata.getVar('__depends', False),
|
|
||||||
task_deps = metadata.getVar('_task_deps', False) or
|
|
||||||
{'tasks': [], 'parents': {}},
|
|
||||||
variants = cls.listvar('__VARIANTS', metadata) + [''],
|
|
||||||
|
|
||||||
skipped = False,
|
|
||||||
timestamp = bb.parse.cached_mtime(filename),
|
|
||||||
packages = cls.listvar('PACKAGES', metadata),
|
|
||||||
pn = pn,
|
|
||||||
pe = cls.getvar('PE', metadata),
|
|
||||||
pv = cls.getvar('PV', metadata),
|
|
||||||
pr = cls.getvar('PR', metadata),
|
|
||||||
nocache = cls.getvar('__BB_DONT_CACHE', metadata),
|
|
||||||
defaultpref = cls.intvar('DEFAULT_PREFERENCE', metadata),
|
|
||||||
broken = cls.getvar('BROKEN', metadata),
|
|
||||||
not_world = cls.getvar('EXCLUDE_FROM_WORLD', metadata),
|
|
||||||
stamp = cls.getvar('STAMP', metadata),
|
|
||||||
stamp_extrainfo = cls.flaglist('stamp-extra-info', tasks, metadata),
|
|
||||||
packages_dynamic = cls.listvar('PACKAGES_DYNAMIC', metadata),
|
|
||||||
depends = cls.depvar('DEPENDS', metadata),
|
|
||||||
provides = cls.depvar('PROVIDES', metadata),
|
|
||||||
rdepends = cls.depvar('RDEPENDS', metadata),
|
|
||||||
rprovides = cls.depvar('RPROVIDES', metadata),
|
|
||||||
rrecommends = cls.depvar('RRECOMMENDS', metadata),
|
|
||||||
rprovides_pkg = cls.pkgvar('RPROVIDES', packages, metadata),
|
|
||||||
rdepends_pkg = cls.pkgvar('RDEPENDS', packages, metadata),
|
|
||||||
rrecommends_pkg = cls.pkgvar('RRECOMMENDS', packages, metadata),
|
|
||||||
inherits = cls.getvar('__inherit_cache', metadata),
|
|
||||||
summary = cls.getvar('SUMMARY', metadata),
|
|
||||||
license = cls.getvar('LICENSE', metadata),
|
|
||||||
section = cls.getvar('SECTION', metadata),
|
|
||||||
fakerootenv = cls.getvar('FAKEROOTENV', metadata),
|
|
||||||
fakerootdirs = cls.getvar('FAKEROOTDIRS', metadata),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class Cache(object):
|
|
||||||
"""
|
"""
|
||||||
BitBake Cache implementation
|
BitBake Cache implementation
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, data):
|
def __init__(self, data):
|
||||||
|
|
||||||
|
|
||||||
self.cachedir = bb.data.getVar("CACHE", data, True)
|
self.cachedir = bb.data.getVar("CACHE", data, True)
|
||||||
self.clean = set()
|
self.clean = {}
|
||||||
self.checked = set()
|
self.checked = {}
|
||||||
self.depends_cache = {}
|
self.depends_cache = {}
|
||||||
self.data = None
|
self.data = None
|
||||||
self.data_fn = None
|
self.data_fn = None
|
||||||
@@ -195,74 +57,92 @@ class Cache(object):
|
|||||||
|
|
||||||
if self.cachedir in [None, '']:
|
if self.cachedir in [None, '']:
|
||||||
self.has_cache = False
|
self.has_cache = False
|
||||||
logger.info("Not using a cache. "
|
bb.msg.note(1, bb.msg.domain.Cache, "Not using a cache. Set CACHE = <directory> to enable.")
|
||||||
"Set CACHE = <directory> to enable.")
|
|
||||||
return
|
return
|
||||||
|
|
||||||
self.has_cache = True
|
self.has_cache = True
|
||||||
self.cachefile = os.path.join(self.cachedir, "bb_cache.dat")
|
self.cachefile = os.path.join(self.cachedir, "bb_cache.dat")
|
||||||
|
|
||||||
logger.debug(1, "Using cache in '%s'", self.cachedir)
|
bb.msg.debug(1, bb.msg.domain.Cache, "Using cache in '%s'" % self.cachedir)
|
||||||
bb.utils.mkdirhier(self.cachedir)
|
bb.utils.mkdirhier(self.cachedir)
|
||||||
|
|
||||||
# If any of configuration.data's dependencies are newer than the
|
# If any of configuration.data's dependencies are newer than the
|
||||||
# cache there isn't even any point in loading it...
|
# cache there isn't even any point in loading it...
|
||||||
newest_mtime = 0
|
newest_mtime = 0
|
||||||
deps = bb.data.getVar("__base_depends", data)
|
deps = bb.data.getVar("__depends", data)
|
||||||
|
|
||||||
old_mtimes = [old_mtime for _, old_mtime in deps]
|
old_mtimes = [old_mtime for f, old_mtime in deps]
|
||||||
old_mtimes.append(newest_mtime)
|
old_mtimes.append(newest_mtime)
|
||||||
newest_mtime = max(old_mtimes)
|
newest_mtime = max(old_mtimes)
|
||||||
|
|
||||||
if bb.parse.cached_mtime_noerror(self.cachefile) >= newest_mtime:
|
if bb.parse.cached_mtime_noerror(self.cachefile) >= newest_mtime:
|
||||||
self.load_cachefile()
|
|
||||||
elif os.path.isfile(self.cachefile):
|
|
||||||
logger.info("Out of date cache found, rebuilding...")
|
|
||||||
|
|
||||||
def load_cachefile(self):
|
|
||||||
with open(self.cachefile, "rb") as cachefile:
|
|
||||||
pickled = pickle.Unpickler(cachefile)
|
|
||||||
try:
|
try:
|
||||||
cache_ver = pickled.load()
|
p = pickle.Unpickler(file(self.cachefile, "rb"))
|
||||||
bitbake_ver = pickled.load()
|
self.depends_cache, version_data = p.load()
|
||||||
except Exception:
|
if version_data['CACHE_VER'] != __cache_version__:
|
||||||
logger.info('Invalid cache, rebuilding...')
|
raise ValueError('Cache Version Mismatch')
|
||||||
return
|
if version_data['BITBAKE_VER'] != bb.__version__:
|
||||||
|
raise ValueError('Bitbake Version Mismatch')
|
||||||
|
except EOFError:
|
||||||
|
bb.msg.note(1, bb.msg.domain.Cache, "Truncated cache found, rebuilding...")
|
||||||
|
self.depends_cache = {}
|
||||||
|
except:
|
||||||
|
bb.msg.note(1, bb.msg.domain.Cache, "Invalid cache found, rebuilding...")
|
||||||
|
self.depends_cache = {}
|
||||||
|
else:
|
||||||
|
if os.path.isfile(self.cachefile):
|
||||||
|
bb.msg.note(1, bb.msg.domain.Cache, "Out of date cache found, rebuilding...")
|
||||||
|
|
||||||
if cache_ver != __cache_version__:
|
def getVar(self, var, fn, exp = 0):
|
||||||
logger.info('Cache version mismatch, rebuilding...')
|
"""
|
||||||
return
|
Gets the value of a variable
|
||||||
elif bitbake_ver != bb.__version__:
|
(similar to getVar in the data class)
|
||||||
logger.info('Bitbake version mismatch, rebuilding...')
|
|
||||||
return
|
|
||||||
|
|
||||||
cachesize = os.fstat(cachefile.fileno()).st_size
|
There are two scenarios:
|
||||||
bb.event.fire(bb.event.CacheLoadStarted(cachesize), self.data)
|
1. We have cached data - serve from depends_cache[fn]
|
||||||
|
2. We're learning what data to cache - serve from data
|
||||||
|
backend but add a copy of the data to the cache.
|
||||||
|
"""
|
||||||
|
if fn in self.clean:
|
||||||
|
return self.depends_cache[fn][var]
|
||||||
|
|
||||||
previous_percent = 0
|
self.depends_cache.setdefault(fn, {})
|
||||||
while cachefile:
|
|
||||||
try:
|
|
||||||
key = pickled.load()
|
|
||||||
value = pickled.load()
|
|
||||||
except Exception:
|
|
||||||
break
|
|
||||||
|
|
||||||
self.depends_cache[key] = value
|
if fn != self.data_fn:
|
||||||
|
# We're trying to access data in the cache which doesn't exist
|
||||||
|
# yet setData hasn't been called to setup the right access. Very bad.
|
||||||
|
bb.msg.error(bb.msg.domain.Cache, "Parsing error data_fn %s and fn %s don't match" % (self.data_fn, fn))
|
||||||
|
|
||||||
# only fire events on even percentage boundaries
|
self.cacheclean = False
|
||||||
current_progress = cachefile.tell()
|
result = bb.data.getVar(var, self.data, exp)
|
||||||
current_percent = 100 * current_progress / cachesize
|
self.depends_cache[fn][var] = result
|
||||||
if current_percent > previous_percent:
|
return result
|
||||||
previous_percent = current_percent
|
|
||||||
bb.event.fire(bb.event.CacheLoadProgress(current_progress),
|
|
||||||
self.data)
|
|
||||||
|
|
||||||
bb.event.fire(bb.event.CacheLoadCompleted(cachesize,
|
def setData(self, virtualfn, fn, data):
|
||||||
len(self.depends_cache)),
|
"""
|
||||||
self.data)
|
Called to prime bb_cache ready to learn which variables to cache.
|
||||||
|
Will be followed by calls to self.getVar which aren't cached
|
||||||
|
but can be fulfilled from self.data.
|
||||||
|
"""
|
||||||
|
self.data_fn = virtualfn
|
||||||
|
self.data = data
|
||||||
|
|
||||||
@staticmethod
|
# Make sure __depends makes the depends_cache
|
||||||
def virtualfn2realfn(virtualfn):
|
# If we're a virtual class we need to make sure all our depends are appended
|
||||||
|
# to the depends of fn.
|
||||||
|
depends = self.getVar("__depends", virtualfn) or set()
|
||||||
|
self.depends_cache.setdefault(fn, {})
|
||||||
|
if "__depends" not in self.depends_cache[fn] or not self.depends_cache[fn]["__depends"]:
|
||||||
|
self.depends_cache[fn]["__depends"] = depends
|
||||||
|
else:
|
||||||
|
self.depends_cache[fn]["__depends"].update(depends)
|
||||||
|
|
||||||
|
# Make sure the variants always make it into the cache too
|
||||||
|
self.getVar('__VARIANTS', virtualfn, True)
|
||||||
|
|
||||||
|
self.depends_cache[virtualfn]["CACHETIMESTAMP"] = bb.parse.cached_mtime(fn)
|
||||||
|
|
||||||
|
def virtualfn2realfn(self, virtualfn):
|
||||||
"""
|
"""
|
||||||
Convert a virtual file name to a real one + the associated subclass keyword
|
Convert a virtual file name to a real one + the associated subclass keyword
|
||||||
"""
|
"""
|
||||||
@@ -272,94 +152,79 @@ class Cache(object):
|
|||||||
if virtualfn.startswith('virtual:'):
|
if virtualfn.startswith('virtual:'):
|
||||||
cls = virtualfn.split(':', 2)[1]
|
cls = virtualfn.split(':', 2)[1]
|
||||||
fn = virtualfn.replace('virtual:' + cls + ':', '')
|
fn = virtualfn.replace('virtual:' + cls + ':', '')
|
||||||
|
#bb.msg.debug(2, bb.msg.domain.Cache, "virtualfn2realfn %s to %s %s" % (virtualfn, fn, cls))
|
||||||
return (fn, cls)
|
return (fn, cls)
|
||||||
|
|
||||||
@staticmethod
|
def realfn2virtual(self, realfn, cls):
|
||||||
def realfn2virtual(realfn, cls):
|
|
||||||
"""
|
"""
|
||||||
Convert a real filename + the associated subclass keyword to a virtual filename
|
Convert a real filename + the associated subclass keyword to a virtual filename
|
||||||
"""
|
"""
|
||||||
if cls == "":
|
if cls == "":
|
||||||
|
#bb.msg.debug(2, bb.msg.domain.Cache, "realfn2virtual %s and '%s' to %s" % (realfn, cls, realfn))
|
||||||
return realfn
|
return realfn
|
||||||
|
#bb.msg.debug(2, bb.msg.domain.Cache, "realfn2virtual %s and %s to %s" % (realfn, cls, "virtual:" + cls + ":" + realfn))
|
||||||
return "virtual:" + cls + ":" + realfn
|
return "virtual:" + cls + ":" + realfn
|
||||||
|
|
||||||
@classmethod
|
def loadDataFull(self, virtualfn, appends, cfgData):
|
||||||
def loadDataFull(cls, virtualfn, appends, cfgData):
|
|
||||||
"""
|
"""
|
||||||
Return a complete set of data for fn.
|
Return a complete set of data for fn.
|
||||||
To do this, we need to parse the file.
|
To do this, we need to parse the file.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
(fn, virtual) = cls.virtualfn2realfn(virtualfn)
|
(fn, cls) = self.virtualfn2realfn(virtualfn)
|
||||||
|
|
||||||
logger.debug(1, "Parsing %s (full)", fn)
|
bb.msg.debug(1, bb.msg.domain.Cache, "Parsing %s (full)" % fn)
|
||||||
|
|
||||||
bb_data = cls.load_bbfile(fn, appends, cfgData)
|
bb_data = self.load_bbfile(fn, appends, cfgData)
|
||||||
return bb_data[virtual]
|
return bb_data[cls]
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def parse(cls, filename, appends, configdata):
|
|
||||||
"""Parse the specified filename, returning the recipe information"""
|
|
||||||
infos = []
|
|
||||||
datastores = cls.load_bbfile(filename, appends, configdata)
|
|
||||||
depends = set()
|
|
||||||
for variant, data in sorted(datastores.iteritems(),
|
|
||||||
key=lambda i: i[0],
|
|
||||||
reverse=True):
|
|
||||||
virtualfn = cls.realfn2virtual(filename, variant)
|
|
||||||
depends |= (data.getVar("__depends", False) or set())
|
|
||||||
if depends and not variant:
|
|
||||||
data.setVar("__depends", depends)
|
|
||||||
info = RecipeInfo.from_metadata(filename, data)
|
|
||||||
infos.append((virtualfn, info))
|
|
||||||
return infos
|
|
||||||
|
|
||||||
def load(self, filename, appends, configdata):
|
|
||||||
"""Obtain the recipe information for the specified filename,
|
|
||||||
using cached values if available, otherwise parsing.
|
|
||||||
|
|
||||||
Note that if it does parse to obtain the info, it will not
|
|
||||||
automatically add the information to the cache or to your
|
|
||||||
CacheData. Use the add or add_info method to do so after
|
|
||||||
running this, or use loadData instead."""
|
|
||||||
cached = self.cacheValid(filename)
|
|
||||||
if cached:
|
|
||||||
infos = []
|
|
||||||
info = self.depends_cache[filename]
|
|
||||||
for variant in info.variants:
|
|
||||||
virtualfn = self.realfn2virtual(filename, variant)
|
|
||||||
infos.append((virtualfn, self.depends_cache[virtualfn]))
|
|
||||||
else:
|
|
||||||
logger.debug(1, "Parsing %s", filename)
|
|
||||||
return self.parse(filename, appends, configdata)
|
|
||||||
|
|
||||||
return cached, infos
|
|
||||||
|
|
||||||
def loadData(self, fn, appends, cfgData, cacheData):
|
def loadData(self, fn, appends, cfgData, cacheData):
|
||||||
"""Load the recipe info for the specified filename,
|
"""
|
||||||
parsing and adding to the cache if necessary, and adding
|
Load a subset of data for fn.
|
||||||
the recipe information to the supplied CacheData instance."""
|
If the cached data is valid we do nothing,
|
||||||
skipped, virtuals = 0, 0
|
To do this, we need to parse the file and set the system
|
||||||
|
to record the variables accessed.
|
||||||
|
Return the cache status and whether the file was skipped when parsed
|
||||||
|
"""
|
||||||
|
skipped = 0
|
||||||
|
virtuals = 0
|
||||||
|
|
||||||
cached, infos = self.load(fn, appends, cfgData)
|
if fn not in self.checked:
|
||||||
for virtualfn, info in infos:
|
self.cacheValidUpdate(fn)
|
||||||
if info.skipped:
|
|
||||||
logger.debug(1, "Skipping %s", virtualfn)
|
if self.cacheValid(fn):
|
||||||
skipped += 1
|
multi = self.getVar('__VARIANTS', fn, True)
|
||||||
else:
|
for cls in (multi or "").split() + [""]:
|
||||||
self.add_info(virtualfn, info, cacheData, not cached)
|
virtualfn = self.realfn2virtual(fn, cls)
|
||||||
|
if self.depends_cache[virtualfn]["__SKIPPED"]:
|
||||||
|
skipped += 1
|
||||||
|
bb.msg.debug(1, bb.msg.domain.Cache, "Skipping %s" % virtualfn)
|
||||||
|
continue
|
||||||
|
self.handle_data(virtualfn, cacheData)
|
||||||
virtuals += 1
|
virtuals += 1
|
||||||
|
return True, skipped, virtuals
|
||||||
|
|
||||||
|
bb.msg.debug(1, bb.msg.domain.Cache, "Parsing %s" % fn)
|
||||||
|
|
||||||
|
bb_data = self.load_bbfile(fn, appends, cfgData)
|
||||||
|
|
||||||
|
for data in bb_data:
|
||||||
|
virtualfn = self.realfn2virtual(fn, data)
|
||||||
|
self.setData(virtualfn, fn, bb_data[data])
|
||||||
|
if self.getVar("__SKIPPED", virtualfn):
|
||||||
|
skipped += 1
|
||||||
|
bb.msg.debug(1, bb.msg.domain.Cache, "Skipping %s" % virtualfn)
|
||||||
|
else:
|
||||||
|
self.handle_data(virtualfn, cacheData)
|
||||||
|
virtuals += 1
|
||||||
|
return False, skipped, virtuals
|
||||||
|
|
||||||
return cached, skipped, virtuals
|
|
||||||
|
|
||||||
def cacheValid(self, fn):
|
def cacheValid(self, fn):
|
||||||
"""
|
"""
|
||||||
Is the cache valid for fn?
|
Is the cache valid for fn?
|
||||||
Fast version, no timestamps checked.
|
Fast version, no timestamps checked.
|
||||||
"""
|
"""
|
||||||
if fn not in self.checked:
|
|
||||||
self.cacheValidUpdate(fn)
|
|
||||||
|
|
||||||
# Is cache enabled?
|
# Is cache enabled?
|
||||||
if not self.has_cache:
|
if not self.has_cache:
|
||||||
return False
|
return False
|
||||||
@@ -376,67 +241,70 @@ class Cache(object):
|
|||||||
if not self.has_cache:
|
if not self.has_cache:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
self.checked.add(fn)
|
self.checked[fn] = ""
|
||||||
|
|
||||||
|
# Pretend we're clean so getVar works
|
||||||
|
self.clean[fn] = ""
|
||||||
|
|
||||||
# File isn't in depends_cache
|
# File isn't in depends_cache
|
||||||
if not fn in self.depends_cache:
|
if not fn in self.depends_cache:
|
||||||
logger.debug(2, "Cache: %s is not cached", fn)
|
bb.msg.debug(2, bb.msg.domain.Cache, "Cache: %s is not cached" % fn)
|
||||||
|
self.remove(fn)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
mtime = bb.parse.cached_mtime_noerror(fn)
|
mtime = bb.parse.cached_mtime_noerror(fn)
|
||||||
|
|
||||||
# Check file still exists
|
# Check file still exists
|
||||||
if mtime == 0:
|
if mtime == 0:
|
||||||
logger.debug(2, "Cache: %s no longer exists", fn)
|
bb.msg.debug(2, bb.msg.domain.Cache, "Cache: %s no longer exists" % fn)
|
||||||
self.remove(fn)
|
self.remove(fn)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
info = self.depends_cache[fn]
|
|
||||||
# Check the file's timestamp
|
# Check the file's timestamp
|
||||||
if mtime != info.timestamp:
|
if mtime != self.getVar("CACHETIMESTAMP", fn, True):
|
||||||
logger.debug(2, "Cache: %s changed", fn)
|
bb.msg.debug(2, bb.msg.domain.Cache, "Cache: %s changed" % fn)
|
||||||
self.remove(fn)
|
self.remove(fn)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# Check dependencies are still valid
|
# Check dependencies are still valid
|
||||||
depends = info.file_depends
|
depends = self.getVar("__depends", fn, True)
|
||||||
if depends:
|
if depends:
|
||||||
for f, old_mtime in depends:
|
for f, old_mtime in depends:
|
||||||
fmtime = bb.parse.cached_mtime_noerror(f)
|
fmtime = bb.parse.cached_mtime_noerror(f)
|
||||||
# Check if file still exists
|
# Check if file still exists
|
||||||
if old_mtime != 0 and fmtime == 0:
|
if old_mtime != 0 and fmtime == 0:
|
||||||
logger.debug(2, "Cache: %s's dependency %s was removed",
|
|
||||||
fn, f)
|
|
||||||
self.remove(fn)
|
self.remove(fn)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if (fmtime != old_mtime):
|
if (fmtime != old_mtime):
|
||||||
logger.debug(2, "Cache: %s's dependency %s changed",
|
bb.msg.debug(2, bb.msg.domain.Cache, "Cache: %s's dependency %s changed" % (fn, f))
|
||||||
fn, f)
|
|
||||||
self.remove(fn)
|
self.remove(fn)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
#bb.msg.debug(2, bb.msg.domain.Cache, "Depends Cache: %s is clean" % fn)
|
||||||
|
if not fn in self.clean:
|
||||||
|
self.clean[fn] = ""
|
||||||
|
|
||||||
invalid = False
|
invalid = False
|
||||||
for cls in info.variants:
|
# Mark extended class data as clean too
|
||||||
|
multi = self.getVar('__VARIANTS', fn, True)
|
||||||
|
for cls in (multi or "").split():
|
||||||
virtualfn = self.realfn2virtual(fn, cls)
|
virtualfn = self.realfn2virtual(fn, cls)
|
||||||
self.clean.add(virtualfn)
|
self.clean[virtualfn] = ""
|
||||||
if virtualfn not in self.depends_cache:
|
if not virtualfn in self.depends_cache:
|
||||||
logger.debug(2, "Cache: %s is not cached", virtualfn)
|
bb.msg.debug(2, bb.msg.domain.Cache, "Cache: %s is not cached" % virtualfn)
|
||||||
invalid = True
|
invalid = True
|
||||||
|
|
||||||
# If any one of the variants is not present, mark as invalid for all
|
# If any one of the varients is not present, mark cache as invalid for all
|
||||||
if invalid:
|
if invalid:
|
||||||
for cls in info.variants:
|
for cls in (multi or "").split():
|
||||||
virtualfn = self.realfn2virtual(fn, cls)
|
virtualfn = self.realfn2virtual(fn, cls)
|
||||||
if virtualfn in self.clean:
|
bb.msg.debug(2, bb.msg.domain.Cache, "Cache: Removing %s from cache" % virtualfn)
|
||||||
logger.debug(2, "Cache: Removing %s from cache", virtualfn)
|
del self.clean[virtualfn]
|
||||||
self.clean.remove(virtualfn)
|
bb.msg.debug(2, bb.msg.domain.Cache, "Cache: Removing %s from cache" % fn)
|
||||||
if fn in self.clean:
|
del self.clean[fn]
|
||||||
logger.debug(2, "Cache: Marking %s as not clean", fn)
|
|
||||||
self.clean.remove(fn)
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
self.clean.add(fn)
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def remove(self, fn):
|
def remove(self, fn):
|
||||||
@@ -444,61 +312,154 @@ class Cache(object):
|
|||||||
Remove a fn from the cache
|
Remove a fn from the cache
|
||||||
Called from the parser in error cases
|
Called from the parser in error cases
|
||||||
"""
|
"""
|
||||||
|
bb.msg.debug(1, bb.msg.domain.Cache, "Removing %s from cache" % fn)
|
||||||
if fn in self.depends_cache:
|
if fn in self.depends_cache:
|
||||||
logger.debug(1, "Removing %s from cache", fn)
|
|
||||||
del self.depends_cache[fn]
|
del self.depends_cache[fn]
|
||||||
if fn in self.clean:
|
if fn in self.clean:
|
||||||
logger.debug(1, "Marking %s as unclean", fn)
|
del self.clean[fn]
|
||||||
self.clean.remove(fn)
|
|
||||||
|
|
||||||
def sync(self):
|
def sync(self):
|
||||||
"""
|
"""
|
||||||
Save the cache
|
Save the cache
|
||||||
Called from the parser when complete (or exiting)
|
Called from the parser when complete (or exiting)
|
||||||
"""
|
"""
|
||||||
|
import copy
|
||||||
|
|
||||||
if not self.has_cache:
|
if not self.has_cache:
|
||||||
return
|
return
|
||||||
|
|
||||||
if self.cacheclean:
|
if self.cacheclean:
|
||||||
logger.debug(2, "Cache is clean, not saving.")
|
bb.msg.note(1, bb.msg.domain.Cache, "Cache is clean, not saving.")
|
||||||
return
|
return
|
||||||
|
|
||||||
with open(self.cachefile, "wb") as cachefile:
|
version_data = {}
|
||||||
pickler = pickle.Pickler(cachefile, pickle.HIGHEST_PROTOCOL)
|
version_data['CACHE_VER'] = __cache_version__
|
||||||
pickler.dump(__cache_version__)
|
version_data['BITBAKE_VER'] = bb.__version__
|
||||||
pickler.dump(bb.__version__)
|
|
||||||
for key, value in self.depends_cache.iteritems():
|
|
||||||
pickler.dump(key)
|
|
||||||
pickler.dump(value)
|
|
||||||
|
|
||||||
del self.depends_cache
|
cache_data = copy.copy(self.depends_cache)
|
||||||
|
for fn in self.depends_cache:
|
||||||
|
if '__BB_DONT_CACHE' in self.depends_cache[fn] and self.depends_cache[fn]['__BB_DONT_CACHE']:
|
||||||
|
bb.msg.debug(2, bb.msg.domain.Cache, "Not caching %s, marked as not cacheable" % fn)
|
||||||
|
del cache_data[fn]
|
||||||
|
elif 'PV' in self.depends_cache[fn] and 'SRCREVINACTION' in self.depends_cache[fn]['PV']:
|
||||||
|
bb.msg.error(bb.msg.domain.Cache, "Not caching %s as it had SRCREVINACTION in PV. Please report this bug" % fn)
|
||||||
|
del cache_data[fn]
|
||||||
|
|
||||||
@staticmethod
|
p = pickle.Pickler(file(self.cachefile, "wb" ), -1 )
|
||||||
def mtime(cachefile):
|
p.dump([cache_data, version_data])
|
||||||
|
|
||||||
|
def mtime(self, cachefile):
|
||||||
return bb.parse.cached_mtime_noerror(cachefile)
|
return bb.parse.cached_mtime_noerror(cachefile)
|
||||||
|
|
||||||
def add_info(self, filename, info, cacheData, parsed=None):
|
def handle_data(self, file_name, cacheData):
|
||||||
cacheData.add_from_recipeinfo(filename, info)
|
|
||||||
if not self.has_cache:
|
|
||||||
return
|
|
||||||
|
|
||||||
if 'SRCREVINACTION' not in info.pv and not info.nocache:
|
|
||||||
if parsed:
|
|
||||||
self.cacheclean = False
|
|
||||||
self.depends_cache[filename] = info
|
|
||||||
|
|
||||||
def add(self, file_name, data, cacheData, parsed=None):
|
|
||||||
"""
|
"""
|
||||||
Save data we need into the cache
|
Save data we need into the cache
|
||||||
"""
|
"""
|
||||||
|
|
||||||
realfn = self.virtualfn2realfn(file_name)[0]
|
pn = self.getVar('PN', file_name, True)
|
||||||
info = RecipeInfo.from_metadata(realfn, data)
|
pe = self.getVar('PE', file_name, True) or "0"
|
||||||
self.add_info(file_name, info, cacheData, parsed)
|
pv = self.getVar('PV', file_name, True)
|
||||||
|
if 'SRCREVINACTION' in pv:
|
||||||
|
bb.msg.note(1, bb.msg.domain.Cache, "Found SRCREVINACTION in PV (%s) or %s. Please report this bug." % (pv, file_name))
|
||||||
|
pr = self.getVar('PR', file_name, True)
|
||||||
|
dp = int(self.getVar('DEFAULT_PREFERENCE', file_name, True) or "0")
|
||||||
|
depends = bb.utils.explode_deps(self.getVar("DEPENDS", file_name, True) or "")
|
||||||
|
packages = (self.getVar('PACKAGES', file_name, True) or "").split()
|
||||||
|
packages_dynamic = (self.getVar('PACKAGES_DYNAMIC', file_name, True) or "").split()
|
||||||
|
rprovides = (self.getVar("RPROVIDES", file_name, True) or "").split()
|
||||||
|
|
||||||
@staticmethod
|
cacheData.task_deps[file_name] = self.getVar("_task_deps", file_name)
|
||||||
def load_bbfile(bbfile, appends, config):
|
|
||||||
|
# build PackageName to FileName lookup table
|
||||||
|
if pn not in cacheData.pkg_pn:
|
||||||
|
cacheData.pkg_pn[pn] = []
|
||||||
|
cacheData.pkg_pn[pn].append(file_name)
|
||||||
|
|
||||||
|
cacheData.stamp[file_name] = self.getVar('STAMP', file_name, True)
|
||||||
|
|
||||||
|
cacheData.tasks[file_name] = self.getVar('__BBTASKS', file_name, True)
|
||||||
|
for t in cacheData.tasks[file_name]:
|
||||||
|
cacheData.basetaskhash[file_name + "." + t] = self.getVar("BB_BASEHASH_task-%s" % t, file_name, True)
|
||||||
|
|
||||||
|
# build FileName to PackageName lookup table
|
||||||
|
cacheData.pkg_fn[file_name] = pn
|
||||||
|
cacheData.pkg_pepvpr[file_name] = (pe, pv, pr)
|
||||||
|
cacheData.pkg_dp[file_name] = dp
|
||||||
|
|
||||||
|
provides = [pn]
|
||||||
|
for provide in (self.getVar("PROVIDES", file_name, True) or "").split():
|
||||||
|
if provide not in provides:
|
||||||
|
provides.append(provide)
|
||||||
|
|
||||||
|
# Build forward and reverse provider hashes
|
||||||
|
# Forward: virtual -> [filenames]
|
||||||
|
# Reverse: PN -> [virtuals]
|
||||||
|
if pn not in cacheData.pn_provides:
|
||||||
|
cacheData.pn_provides[pn] = []
|
||||||
|
|
||||||
|
cacheData.fn_provides[file_name] = provides
|
||||||
|
for provide in provides:
|
||||||
|
if provide not in cacheData.providers:
|
||||||
|
cacheData.providers[provide] = []
|
||||||
|
cacheData.providers[provide].append(file_name)
|
||||||
|
if not provide in cacheData.pn_provides[pn]:
|
||||||
|
cacheData.pn_provides[pn].append(provide)
|
||||||
|
|
||||||
|
cacheData.deps[file_name] = []
|
||||||
|
for dep in depends:
|
||||||
|
if not dep in cacheData.deps[file_name]:
|
||||||
|
cacheData.deps[file_name].append(dep)
|
||||||
|
if not dep in cacheData.all_depends:
|
||||||
|
cacheData.all_depends.append(dep)
|
||||||
|
|
||||||
|
# Build reverse hash for PACKAGES, so runtime dependencies
|
||||||
|
# can be be resolved (RDEPENDS, RRECOMMENDS etc.)
|
||||||
|
for package in packages:
|
||||||
|
if not package in cacheData.packages:
|
||||||
|
cacheData.packages[package] = []
|
||||||
|
cacheData.packages[package].append(file_name)
|
||||||
|
rprovides += (self.getVar("RPROVIDES_%s" % package, file_name, 1) or "").split()
|
||||||
|
|
||||||
|
for package in packages_dynamic:
|
||||||
|
if not package in cacheData.packages_dynamic:
|
||||||
|
cacheData.packages_dynamic[package] = []
|
||||||
|
cacheData.packages_dynamic[package].append(file_name)
|
||||||
|
|
||||||
|
for rprovide in rprovides:
|
||||||
|
if not rprovide in cacheData.rproviders:
|
||||||
|
cacheData.rproviders[rprovide] = []
|
||||||
|
cacheData.rproviders[rprovide].append(file_name)
|
||||||
|
|
||||||
|
# Build hash of runtime depends and rececommends
|
||||||
|
|
||||||
|
if not file_name in cacheData.rundeps:
|
||||||
|
cacheData.rundeps[file_name] = {}
|
||||||
|
if not file_name in cacheData.runrecs:
|
||||||
|
cacheData.runrecs[file_name] = {}
|
||||||
|
|
||||||
|
rdepends = self.getVar('RDEPENDS', file_name, True) or ""
|
||||||
|
rrecommends = self.getVar('RRECOMMENDS', file_name, True) or ""
|
||||||
|
for package in packages + [pn]:
|
||||||
|
if not package in cacheData.rundeps[file_name]:
|
||||||
|
cacheData.rundeps[file_name][package] = []
|
||||||
|
if not package in cacheData.runrecs[file_name]:
|
||||||
|
cacheData.runrecs[file_name][package] = []
|
||||||
|
|
||||||
|
cacheData.rundeps[file_name][package] = rdepends + " " + (self.getVar("RDEPENDS_%s" % package, file_name, True) or "")
|
||||||
|
cacheData.runrecs[file_name][package] = rrecommends + " " + (self.getVar("RRECOMMENDS_%s" % package, file_name, True) or "")
|
||||||
|
|
||||||
|
# Collect files we may need for possible world-dep
|
||||||
|
# calculations
|
||||||
|
if not self.getVar('BROKEN', file_name, True) and not self.getVar('EXCLUDE_FROM_WORLD', file_name, True):
|
||||||
|
cacheData.possible_world.append(file_name)
|
||||||
|
|
||||||
|
cacheData.hashfn[file_name] = self.getVar('BB_HASHFILENAME', file_name, True)
|
||||||
|
|
||||||
|
# Touch this to make sure its in the cache
|
||||||
|
self.getVar('__BB_DONT_CACHE', file_name, True)
|
||||||
|
self.getVar('__VARIANTS', file_name, True)
|
||||||
|
|
||||||
|
def load_bbfile(self, bbfile, appends, config):
|
||||||
"""
|
"""
|
||||||
Load and parse one .bb build file
|
Load and parse one .bb build file
|
||||||
Return the data and whether parsing resulted in the file being skipped
|
Return the data and whether parsing resulted in the file being skipped
|
||||||
@@ -524,16 +485,13 @@ class Cache(object):
|
|||||||
try:
|
try:
|
||||||
if appends:
|
if appends:
|
||||||
data.setVar('__BBAPPEND', " ".join(appends), bb_data)
|
data.setVar('__BBAPPEND', " ".join(appends), bb_data)
|
||||||
bb_data = parse.handle(bbfile, bb_data)
|
bb_data = parse.handle(bbfile, bb_data) # read .bb data
|
||||||
if chdir_back:
|
if chdir_back: os.chdir(oldpath)
|
||||||
os.chdir(oldpath)
|
|
||||||
return bb_data
|
return bb_data
|
||||||
except:
|
except:
|
||||||
if chdir_back:
|
if chdir_back: os.chdir(oldpath)
|
||||||
os.chdir(oldpath)
|
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
|
||||||
def init(cooker):
|
def init(cooker):
|
||||||
"""
|
"""
|
||||||
The Objective: Cache the minimum amount of data possible yet get to the
|
The Objective: Cache the minimum amount of data possible yet get to the
|
||||||
@@ -554,104 +512,48 @@ def init(cooker):
|
|||||||
return Cache(cooker.configuration.data)
|
return Cache(cooker.configuration.data)
|
||||||
|
|
||||||
|
|
||||||
class CacheData(object):
|
|
||||||
|
#============================================================================#
|
||||||
|
# CacheData
|
||||||
|
#============================================================================#
|
||||||
|
class CacheData:
|
||||||
"""
|
"""
|
||||||
The data structures we compile from the cached data
|
The data structures we compile from the cached data
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
# Direct cache variables
|
"""
|
||||||
self.providers = defaultdict(list)
|
Direct cache variables
|
||||||
self.rproviders = defaultdict(list)
|
(from Cache.handle_data)
|
||||||
self.packages = defaultdict(list)
|
"""
|
||||||
self.packages_dynamic = defaultdict(list)
|
self.providers = {}
|
||||||
|
self.rproviders = {}
|
||||||
|
self.packages = {}
|
||||||
|
self.packages_dynamic = {}
|
||||||
self.possible_world = []
|
self.possible_world = []
|
||||||
self.pkg_pn = defaultdict(list)
|
self.pkg_pn = {}
|
||||||
self.pkg_fn = {}
|
self.pkg_fn = {}
|
||||||
self.pkg_pepvpr = {}
|
self.pkg_pepvpr = {}
|
||||||
self.pkg_dp = {}
|
self.pkg_dp = {}
|
||||||
self.pn_provides = defaultdict(list)
|
self.pn_provides = {}
|
||||||
self.fn_provides = {}
|
self.fn_provides = {}
|
||||||
self.all_depends = []
|
self.all_depends = []
|
||||||
self.deps = defaultdict(list)
|
self.deps = {}
|
||||||
self.rundeps = defaultdict(lambda: defaultdict(list))
|
self.rundeps = {}
|
||||||
self.runrecs = defaultdict(lambda: defaultdict(list))
|
self.runrecs = {}
|
||||||
self.task_queues = {}
|
self.task_queues = {}
|
||||||
self.task_deps = {}
|
self.task_deps = {}
|
||||||
self.stamp = {}
|
self.stamp = {}
|
||||||
self.stamp_extrainfo = {}
|
|
||||||
self.preferred = {}
|
self.preferred = {}
|
||||||
self.tasks = {}
|
self.tasks = {}
|
||||||
self.basetaskhash = {}
|
self.basetaskhash = {}
|
||||||
self.hashfn = {}
|
self.hashfn = {}
|
||||||
self.inherits = {}
|
|
||||||
self.summary = {}
|
|
||||||
self.license = {}
|
|
||||||
self.section = {}
|
|
||||||
self.fakerootenv = {}
|
|
||||||
self.fakerootdirs = {}
|
|
||||||
|
|
||||||
# Indirect Cache variables (set elsewhere)
|
"""
|
||||||
|
Indirect Cache variables
|
||||||
|
(set elsewhere)
|
||||||
|
"""
|
||||||
self.ignored_dependencies = []
|
self.ignored_dependencies = []
|
||||||
self.world_target = set()
|
self.world_target = set()
|
||||||
self.bbfile_priority = {}
|
self.bbfile_priority = {}
|
||||||
self.bbfile_config_priorities = []
|
self.bbfile_config_priorities = []
|
||||||
|
|
||||||
def add_from_recipeinfo(self, fn, info):
|
|
||||||
self.task_deps[fn] = info.task_deps
|
|
||||||
self.pkg_fn[fn] = info.pn
|
|
||||||
self.pkg_pn[info.pn].append(fn)
|
|
||||||
self.pkg_pepvpr[fn] = (info.pe, info.pv, info.pr)
|
|
||||||
self.pkg_dp[fn] = info.defaultpref
|
|
||||||
self.stamp[fn] = info.stamp
|
|
||||||
self.stamp_extrainfo[fn] = info.stamp_extrainfo
|
|
||||||
|
|
||||||
provides = [info.pn]
|
|
||||||
for provide in info.provides:
|
|
||||||
if provide not in provides:
|
|
||||||
provides.append(provide)
|
|
||||||
self.fn_provides[fn] = provides
|
|
||||||
|
|
||||||
for provide in provides:
|
|
||||||
self.providers[provide].append(fn)
|
|
||||||
if provide not in self.pn_provides[info.pn]:
|
|
||||||
self.pn_provides[info.pn].append(provide)
|
|
||||||
|
|
||||||
for dep in info.depends:
|
|
||||||
if dep not in self.deps[fn]:
|
|
||||||
self.deps[fn].append(dep)
|
|
||||||
if dep not in self.all_depends:
|
|
||||||
self.all_depends.append(dep)
|
|
||||||
|
|
||||||
rprovides = info.rprovides
|
|
||||||
for package in info.packages:
|
|
||||||
self.packages[package].append(fn)
|
|
||||||
rprovides += info.rprovides_pkg[package]
|
|
||||||
|
|
||||||
for rprovide in rprovides:
|
|
||||||
self.rproviders[rprovide].append(fn)
|
|
||||||
|
|
||||||
for package in info.packages_dynamic:
|
|
||||||
self.packages_dynamic[package].append(fn)
|
|
||||||
|
|
||||||
# Build hash of runtime depends and rececommends
|
|
||||||
for package in info.packages + [info.pn]:
|
|
||||||
self.rundeps[fn][package] = list(info.rdepends) + info.rdepends_pkg[package]
|
|
||||||
self.runrecs[fn][package] = list(info.rrecommends) + info.rrecommends_pkg[package]
|
|
||||||
|
|
||||||
# Collect files we may need for possible world-dep
|
|
||||||
# calculations
|
|
||||||
if not info.broken and not info.not_world:
|
|
||||||
self.possible_world.append(fn)
|
|
||||||
|
|
||||||
self.hashfn[fn] = info.hashfilename
|
|
||||||
for task, taskhash in info.basetaskhashes.iteritems():
|
|
||||||
identifier = '%s.%s' % (fn, task)
|
|
||||||
self.basetaskhash[identifier] = taskhash
|
|
||||||
|
|
||||||
self.inherits[fn] = info.inherits
|
|
||||||
self.summary[fn] = info.summary
|
|
||||||
self.license[fn] = info.license
|
|
||||||
self.section[fn] = info.section
|
|
||||||
self.fakerootenv[fn] = info.fakerootenv
|
|
||||||
self.fakerootdirs[fn] = info.fakerootdirs
|
|
||||||
|
|||||||
@@ -1,21 +1,16 @@
|
|||||||
|
from pysh import pyshyacc, pyshlex
|
||||||
|
from itertools import chain
|
||||||
|
from bb import msg, utils
|
||||||
import ast
|
import ast
|
||||||
import codegen
|
import codegen
|
||||||
import logging
|
|
||||||
import os.path
|
|
||||||
import bb.utils, bb.data
|
|
||||||
from itertools import chain
|
|
||||||
from pysh import pyshyacc, pyshlex, sherrors
|
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger('BitBake.CodeParser')
|
|
||||||
PARSERCACHE_VERSION = 2
|
PARSERCACHE_VERSION = 2
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import cPickle as pickle
|
import cPickle as pickle
|
||||||
except ImportError:
|
except ImportError:
|
||||||
import pickle
|
import pickle
|
||||||
logger.info('Importing cPickle failed. Falling back to a very slow implementation.')
|
bb.msg.note(1, bb.msg.domain.Cache, "Importing cPickle failed. Falling back to a very slow implementation.")
|
||||||
|
|
||||||
|
|
||||||
def check_indent(codestr):
|
def check_indent(codestr):
|
||||||
"""If the code is indented, add a top level piece of code to 'remove' the indentation"""
|
"""If the code is indented, add a top level piece of code to 'remove' the indentation"""
|
||||||
@@ -36,18 +31,15 @@ pythonparsecache = {}
|
|||||||
shellparsecache = {}
|
shellparsecache = {}
|
||||||
|
|
||||||
def parser_cachefile(d):
|
def parser_cachefile(d):
|
||||||
cachedir = (bb.data.getVar("PERSISTENT_DIR", d, True) or
|
cachedir = bb.data.getVar("PERSISTENT_DIR", d, True) or bb.data.getVar("CACHE", d, True)
|
||||||
bb.data.getVar("CACHE", d, True))
|
|
||||||
if cachedir in [None, '']:
|
if cachedir in [None, '']:
|
||||||
return None
|
return None
|
||||||
bb.utils.mkdirhier(cachedir)
|
bb.utils.mkdirhier(cachedir)
|
||||||
cachefile = os.path.join(cachedir, "bb_codeparser.dat")
|
cachefile = os.path.join(cachedir, "bb_codeparser.dat")
|
||||||
logger.debug(1, "Using cache in '%s' for codeparser cache", cachefile)
|
bb.msg.debug(1, bb.msg.domain.Cache, "Using cache in '%s' for codeparser cache" % cachefile)
|
||||||
return cachefile
|
return cachefile
|
||||||
|
|
||||||
def parser_cache_init(d):
|
def parser_cache_init(d):
|
||||||
global pythonparsecache
|
|
||||||
global shellparsecache
|
|
||||||
|
|
||||||
cachefile = parser_cachefile(d)
|
cachefile = parser_cachefile(d)
|
||||||
if not cachefile:
|
if not cachefile:
|
||||||
@@ -62,16 +54,17 @@ def parser_cache_init(d):
|
|||||||
if version != PARSERCACHE_VERSION:
|
if version != PARSERCACHE_VERSION:
|
||||||
return
|
return
|
||||||
|
|
||||||
pythonparsecache = data[0]
|
bb.codeparser.pythonparsecache = data[0]
|
||||||
shellparsecache = data[1]
|
bb.codeparser.shellparsecache = data[1]
|
||||||
|
|
||||||
def parser_cache_save(d):
|
def parser_cache_save(d):
|
||||||
|
|
||||||
cachefile = parser_cachefile(d)
|
cachefile = parser_cachefile(d)
|
||||||
if not cachefile:
|
if not cachefile:
|
||||||
return
|
return
|
||||||
|
|
||||||
p = pickle.Pickler(file(cachefile, "wb"), -1)
|
p = pickle.Pickler(file(cachefile, "wb"), -1)
|
||||||
p.dump([[pythonparsecache, shellparsecache], PARSERCACHE_VERSION])
|
p.dump([[bb.codeparser.pythonparsecache, bb.codeparser.shellparsecache], PARSERCACHE_VERSION])
|
||||||
|
|
||||||
class PythonParser():
|
class PythonParser():
|
||||||
class ValueVisitor():
|
class ValueVisitor():
|
||||||
@@ -136,10 +129,10 @@ class PythonParser():
|
|||||||
funcstr = codegen.to_source(func)
|
funcstr = codegen.to_source(func)
|
||||||
argstr = codegen.to_source(arg)
|
argstr = codegen.to_source(arg)
|
||||||
except TypeError:
|
except TypeError:
|
||||||
logger.debug(2, 'Failed to convert function and argument to source form')
|
msg.debug(2, None, "Failed to convert function and argument to source form")
|
||||||
else:
|
else:
|
||||||
logger.debug(1, "Warning: in call to '%s', argument '%s' is "
|
msg.debug(1, None, "Warning: in call to '%s', argument '%s' is not a literal" %
|
||||||
"not a literal", funcstr, argstr)
|
(funcstr, argstr))
|
||||||
|
|
||||||
def visit_Call(self, node):
|
def visit_Call(self, node):
|
||||||
if self.compare_name(self.getvars, node.func):
|
if self.compare_name(self.getvars, node.func):
|
||||||
@@ -227,7 +220,7 @@ class ShellParser():
|
|||||||
try:
|
try:
|
||||||
tokens, _ = pyshyacc.parse(value, eof=True, debug=False)
|
tokens, _ = pyshyacc.parse(value, eof=True, debug=False)
|
||||||
except pyshlex.NeedMore:
|
except pyshlex.NeedMore:
|
||||||
raise sherrors.ShellSyntaxError("Unexpected EOF")
|
raise ShellSyntaxError("Unexpected EOF")
|
||||||
|
|
||||||
for token in tokens:
|
for token in tokens:
|
||||||
self.process_tokens(token)
|
self.process_tokens(token)
|
||||||
@@ -326,11 +319,11 @@ class ShellParser():
|
|||||||
|
|
||||||
cmd = word[1]
|
cmd = word[1]
|
||||||
if cmd.startswith("$"):
|
if cmd.startswith("$"):
|
||||||
logger.debug(1, "Warning: execution of non-literal "
|
msg.debug(1, None, "Warning: execution of non-literal command '%s'" % cmd)
|
||||||
"command '%s'", cmd)
|
|
||||||
elif cmd == "eval":
|
elif cmd == "eval":
|
||||||
command = " ".join(word for _, word in words[1:])
|
command = " ".join(word for _, word in words[1:])
|
||||||
self.parse_shell(command)
|
self.parse_shell(command)
|
||||||
else:
|
else:
|
||||||
self.allexecs.add(cmd)
|
self.allexecs.add(cmd)
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|||||||
@@ -35,25 +35,12 @@ import bb.data
|
|||||||
async_cmds = {}
|
async_cmds = {}
|
||||||
sync_cmds = {}
|
sync_cmds = {}
|
||||||
|
|
||||||
|
|
||||||
class CommandCompleted(bb.event.Event):
|
|
||||||
pass
|
|
||||||
|
|
||||||
class CommandExit(bb.event.Event):
|
|
||||||
def __init__(self, exitcode):
|
|
||||||
bb.event.Event.__init__(self)
|
|
||||||
self.exitcode = int(exitcode)
|
|
||||||
|
|
||||||
class CommandFailed(CommandExit):
|
|
||||||
def __init__(self, message):
|
|
||||||
self.error = message
|
|
||||||
CommandExit.__init__(self, 1)
|
|
||||||
|
|
||||||
class Command:
|
class Command:
|
||||||
"""
|
"""
|
||||||
A queue of asynchronous commands for bitbake
|
A queue of asynchronous commands for bitbake
|
||||||
"""
|
"""
|
||||||
def __init__(self, cooker):
|
def __init__(self, cooker):
|
||||||
|
|
||||||
self.cooker = cooker
|
self.cooker = cooker
|
||||||
self.cmds_sync = CommandsSync()
|
self.cmds_sync = CommandsSync()
|
||||||
self.cmds_async = CommandsAsync()
|
self.cmds_async = CommandsAsync()
|
||||||
@@ -94,8 +81,7 @@ class Command:
|
|||||||
(command, options) = self.currentAsyncCommand
|
(command, options) = self.currentAsyncCommand
|
||||||
commandmethod = getattr(CommandsAsync, command)
|
commandmethod = getattr(CommandsAsync, command)
|
||||||
needcache = getattr( commandmethod, "needcache" )
|
needcache = getattr( commandmethod, "needcache" )
|
||||||
if (needcache and self.cooker.state in
|
if needcache and self.cooker.cookerState != bb.cooker.cookerParsed:
|
||||||
(bb.cooker.state.initial, bb.cooker.state.parsing)):
|
|
||||||
self.cooker.updateCache()
|
self.cooker.updateCache()
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
@@ -118,13 +104,11 @@ class Command:
|
|||||||
self.finishAsyncCommand(traceback.format_exc())
|
self.finishAsyncCommand(traceback.format_exc())
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def finishAsyncCommand(self, msg=None, code=None):
|
def finishAsyncCommand(self, error = None):
|
||||||
if msg:
|
if error:
|
||||||
bb.event.fire(CommandFailed(msg), self.cooker.configuration.event_data)
|
bb.event.fire(CookerCommandFailed(error), self.cooker.configuration.event_data)
|
||||||
elif code:
|
|
||||||
bb.event.fire(CommandExit(code), self.cooker.configuration.event_data)
|
|
||||||
else:
|
else:
|
||||||
bb.event.fire(CommandCompleted(), self.cooker.configuration.event_data)
|
bb.event.fire(CookerCommandCompleted(), self.cooker.configuration.event_data)
|
||||||
self.currentAsyncCommand = None
|
self.currentAsyncCommand = None
|
||||||
|
|
||||||
|
|
||||||
@@ -139,13 +123,13 @@ class CommandsSync:
|
|||||||
"""
|
"""
|
||||||
Trigger cooker 'shutdown' mode
|
Trigger cooker 'shutdown' mode
|
||||||
"""
|
"""
|
||||||
command.cooker.shutdown()
|
command.cooker.cookerAction = bb.cooker.cookerShutdown
|
||||||
|
|
||||||
def stateStop(self, command, params):
|
def stateStop(self, command, params):
|
||||||
"""
|
"""
|
||||||
Stop the cooker
|
Stop the cooker
|
||||||
"""
|
"""
|
||||||
command.cooker.stop()
|
command.cooker.cookerAction = bb.cooker.cookerStop
|
||||||
|
|
||||||
def getCmdLineAction(self, command, params):
|
def getCmdLineAction(self, command, params):
|
||||||
"""
|
"""
|
||||||
@@ -222,27 +206,6 @@ class CommandsAsync:
|
|||||||
command.finishAsyncCommand()
|
command.finishAsyncCommand()
|
||||||
generateDotGraph.needcache = True
|
generateDotGraph.needcache = True
|
||||||
|
|
||||||
def generateTargetsTree(self, command, params):
|
|
||||||
"""
|
|
||||||
Generate a tree of all buildable targets.
|
|
||||||
"""
|
|
||||||
klass = params[0]
|
|
||||||
|
|
||||||
command.cooker.generateTargetsTree(klass)
|
|
||||||
command.finishAsyncCommand()
|
|
||||||
generateTargetsTree.needcache = True
|
|
||||||
|
|
||||||
def findConfigFiles(self, command, params):
|
|
||||||
"""
|
|
||||||
Find config files which provide appropriate values
|
|
||||||
for the passed configuration variable. i.e. MACHINE
|
|
||||||
"""
|
|
||||||
varname = params[0]
|
|
||||||
|
|
||||||
command.cooker.findConfigFiles(varname)
|
|
||||||
command.finishAsyncCommand()
|
|
||||||
findConfigFiles.needcache = True
|
|
||||||
|
|
||||||
def showVersions(self, command, params):
|
def showVersions(self, command, params):
|
||||||
"""
|
"""
|
||||||
Show the currently selected versions
|
Show the currently selected versions
|
||||||
@@ -285,8 +248,33 @@ class CommandsAsync:
|
|||||||
"""
|
"""
|
||||||
Parse the .bb files
|
Parse the .bb files
|
||||||
"""
|
"""
|
||||||
if bb.fetch.fetcher_compare_revisions(command.cooker.configuration.data):
|
command.cooker.compareRevisions()
|
||||||
command.finishAsyncCommand(code=1)
|
command.finishAsyncCommand()
|
||||||
else:
|
|
||||||
command.finishAsyncCommand()
|
|
||||||
compareRevisions.needcache = True
|
compareRevisions.needcache = True
|
||||||
|
|
||||||
|
#
|
||||||
|
# Events
|
||||||
|
#
|
||||||
|
class CookerCommandCompleted(bb.event.Event):
|
||||||
|
"""
|
||||||
|
Cooker command completed
|
||||||
|
"""
|
||||||
|
def __init__(self):
|
||||||
|
bb.event.Event.__init__(self)
|
||||||
|
|
||||||
|
|
||||||
|
class CookerCommandFailed(bb.event.Event):
|
||||||
|
"""
|
||||||
|
Cooker command completed
|
||||||
|
"""
|
||||||
|
def __init__(self, error):
|
||||||
|
bb.event.Event.__init__(self)
|
||||||
|
self.error = error
|
||||||
|
|
||||||
|
class CookerCommandSetExitCode(bb.event.Event):
|
||||||
|
"""
|
||||||
|
Set the exit code for a cooker command
|
||||||
|
"""
|
||||||
|
def __init__(self, exitcode):
|
||||||
|
bb.event.Event.__init__(self)
|
||||||
|
self.exitcode = int(exitcode)
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -161,12 +161,10 @@ def expandKeys(alterdata, readdata = None):
|
|||||||
|
|
||||||
def inheritFromOS(d):
|
def inheritFromOS(d):
|
||||||
"""Inherit variables from the environment."""
|
"""Inherit variables from the environment."""
|
||||||
exportlist = bb.utils.preserved_envvars_exported()
|
|
||||||
for s in os.environ.keys():
|
for s in os.environ.keys():
|
||||||
try:
|
try:
|
||||||
setVar(s, os.environ[s], d)
|
setVar(s, os.environ[s], d)
|
||||||
if s in exportlist:
|
setVarFlag(s, "export", True, d)
|
||||||
setVarFlag(s, "export", True, d)
|
|
||||||
except TypeError:
|
except TypeError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -192,8 +190,7 @@ def emit_var(var, o=sys.__stdout__, d = init(), all=False):
|
|||||||
return 0
|
return 0
|
||||||
|
|
||||||
if all:
|
if all:
|
||||||
commentVal = re.sub('\n', '\n#', str(oval))
|
o.write('# %s=%s\n' % (var, oval))
|
||||||
o.write('# %s=%s\n' % (var, commentVal))
|
|
||||||
|
|
||||||
if (var.find("-") != -1 or var.find(".") != -1 or var.find('{') != -1 or var.find('}') != -1 or var.find('+') != -1) and not all:
|
if (var.find("-") != -1 or var.find(".") != -1 or var.find('{') != -1 or var.find('}') != -1 or var.find('+') != -1) and not all:
|
||||||
return 0
|
return 0
|
||||||
@@ -202,7 +199,7 @@ def emit_var(var, o=sys.__stdout__, d = init(), all=False):
|
|||||||
|
|
||||||
if unexport:
|
if unexport:
|
||||||
o.write('unset %s\n' % varExpanded)
|
o.write('unset %s\n' % varExpanded)
|
||||||
return 0
|
return 1
|
||||||
|
|
||||||
if not val:
|
if not val:
|
||||||
return 0
|
return 0
|
||||||
@@ -220,9 +217,8 @@ def emit_var(var, o=sys.__stdout__, d = init(), all=False):
|
|||||||
# if we're going to output this within doublequotes,
|
# if we're going to output this within doublequotes,
|
||||||
# to a shell, we need to escape the quotes in the var
|
# to a shell, we need to escape the quotes in the var
|
||||||
alter = re.sub('"', '\\"', val.strip())
|
alter = re.sub('"', '\\"', val.strip())
|
||||||
alter = re.sub('\n', ' \\\n', alter)
|
|
||||||
o.write('%s="%s"\n' % (varExpanded, alter))
|
o.write('%s="%s"\n' % (varExpanded, alter))
|
||||||
return 0
|
return 1
|
||||||
|
|
||||||
def emit_env(o=sys.__stdout__, d = init(), all=False):
|
def emit_env(o=sys.__stdout__, d = init(), all=False):
|
||||||
"""Emits all items in the data store in a format such that it can be sourced by a shell."""
|
"""Emits all items in the data store in a format such that it can be sourced by a shell."""
|
||||||
@@ -248,12 +244,6 @@ def export_vars(d):
|
|||||||
pass
|
pass
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def export_envvars(v, d):
|
|
||||||
for s in os.environ.keys():
|
|
||||||
if s not in v:
|
|
||||||
v[s] = os.environ[s]
|
|
||||||
return v
|
|
||||||
|
|
||||||
def emit_func(func, o=sys.__stdout__, d = init()):
|
def emit_func(func, o=sys.__stdout__, d = init()):
|
||||||
"""Emits all items in the data store in a format such that it can be sourced by a shell."""
|
"""Emits all items in the data store in a format such that it can be sourced by a shell."""
|
||||||
|
|
||||||
@@ -298,8 +288,7 @@ def build_dependencies(key, keys, shelldeps, d):
|
|||||||
parser = d.expandWithRefs(d.getVar(key, False), key)
|
parser = d.expandWithRefs(d.getVar(key, False), key)
|
||||||
deps |= parser.references
|
deps |= parser.references
|
||||||
deps = deps | (keys & parser.execs)
|
deps = deps | (keys & parser.execs)
|
||||||
deps |= set((d.getVarFlag(key, "vardeps", True) or "").split())
|
deps |= set((d.getVarFlag(key, "vardeps") or "").split())
|
||||||
deps -= set((d.getVarFlag(key, "vardepsexclude", True) or "").split())
|
|
||||||
except:
|
except:
|
||||||
bb.note("Error expanding variable %s" % key)
|
bb.note("Error expanding variable %s" % key)
|
||||||
raise
|
raise
|
||||||
@@ -313,10 +302,12 @@ def generate_dependencies(d):
|
|||||||
shelldeps = set(key for key in keys if d.getVarFlag(key, "export") and not d.getVarFlag(key, "unexport"))
|
shelldeps = set(key for key in keys if d.getVarFlag(key, "export") and not d.getVarFlag(key, "unexport"))
|
||||||
|
|
||||||
deps = {}
|
deps = {}
|
||||||
|
taskdeps = {}
|
||||||
|
|
||||||
tasklist = bb.data.getVar('__BBTASKS', d) or []
|
tasklist = bb.data.getVar('__BBTASKS', d) or []
|
||||||
for task in tasklist:
|
for task in tasklist:
|
||||||
deps[task] = build_dependencies(task, keys, shelldeps, d)
|
deps[task] = build_dependencies(task, keys, shelldeps, d)
|
||||||
|
|
||||||
newdeps = deps[task]
|
newdeps = deps[task]
|
||||||
seen = set()
|
seen = set()
|
||||||
while newdeps:
|
while newdeps:
|
||||||
@@ -328,8 +319,9 @@ def generate_dependencies(d):
|
|||||||
deps[dep] = build_dependencies(dep, keys, shelldeps, d)
|
deps[dep] = build_dependencies(dep, keys, shelldeps, d)
|
||||||
newdeps |= deps[dep]
|
newdeps |= deps[dep]
|
||||||
newdeps -= seen
|
newdeps -= seen
|
||||||
|
taskdeps[task] = seen | newdeps
|
||||||
#print "For %s: %s" % (task, str(taskdeps[task]))
|
#print "For %s: %s" % (task, str(taskdeps[task]))
|
||||||
return tasklist, deps
|
return taskdeps, deps
|
||||||
|
|
||||||
def inherits_class(klass, d):
|
def inherits_class(klass, d):
|
||||||
val = getVar('__inherit_cache', d) or []
|
val = getVar('__inherit_cache', d) or []
|
||||||
|
|||||||
@@ -28,21 +28,17 @@ BitBake build tools.
|
|||||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
# Based on functions from the base bb module, Copyright 2003 Holger Schurig
|
# Based on functions from the base bb module, Copyright 2003 Holger Schurig
|
||||||
|
|
||||||
import copy, re
|
import copy, re, sys
|
||||||
from collections import MutableMapping
|
import bb
|
||||||
import logging
|
|
||||||
import bb, bb.codeparser
|
|
||||||
from bb import utils
|
from bb import utils
|
||||||
from bb.COW import COWDictBase
|
from bb.COW import COWDictBase
|
||||||
|
|
||||||
logger = logging.getLogger("BitBake.Data")
|
|
||||||
|
|
||||||
__setvar_keyword__ = ["_append", "_prepend"]
|
__setvar_keyword__ = ["_append", "_prepend"]
|
||||||
__setvar_regexp__ = re.compile('(?P<base>.*?)(?P<keyword>_append|_prepend)(_(?P<add>.*))?')
|
__setvar_regexp__ = re.compile('(?P<base>.*?)(?P<keyword>_append|_prepend)(_(?P<add>.*))?')
|
||||||
__expand_var_regexp__ = re.compile(r"\${[^{}]+}")
|
__expand_var_regexp__ = re.compile(r"\${[^{}]+}")
|
||||||
__expand_python_regexp__ = re.compile(r"\${@.+?}")
|
__expand_python_regexp__ = re.compile(r"\${@.+?}")
|
||||||
|
|
||||||
|
|
||||||
class VariableParse:
|
class VariableParse:
|
||||||
def __init__(self, varname, d, val = None):
|
def __init__(self, varname, d, val = None):
|
||||||
self.varname = varname
|
self.varname = varname
|
||||||
@@ -73,35 +69,11 @@ class VariableParse:
|
|||||||
self.references |= parser.references
|
self.references |= parser.references
|
||||||
self.execs |= parser.execs
|
self.execs |= parser.execs
|
||||||
|
|
||||||
value = utils.better_eval(codeobj, DataContext(self.d))
|
value = utils.better_eval(codeobj, {"d": self.d})
|
||||||
return str(value)
|
return str(value)
|
||||||
|
|
||||||
|
|
||||||
class DataContext(dict):
|
class DataSmart:
|
||||||
def __init__(self, metadata, **kwargs):
|
|
||||||
self.metadata = metadata
|
|
||||||
dict.__init__(self, **kwargs)
|
|
||||||
self['d'] = metadata
|
|
||||||
|
|
||||||
def __missing__(self, key):
|
|
||||||
value = self.metadata.getVar(key, True)
|
|
||||||
if value is None or self.metadata.getVarFlag(key, 'func'):
|
|
||||||
raise KeyError(key)
|
|
||||||
else:
|
|
||||||
return value
|
|
||||||
|
|
||||||
class ExpansionError(Exception):
|
|
||||||
def __init__(self, varname, expression, exception):
|
|
||||||
self.expression = expression
|
|
||||||
self.variablename = varname
|
|
||||||
self.exception = exception
|
|
||||||
self.msg = "Failure expanding variable %s, expression was %s which triggered exception %s: %s" % (varname, expression, type(exception).__name__, exception)
|
|
||||||
Exception.__init__(self, self.msg)
|
|
||||||
self.args = (varname, expression, exception)
|
|
||||||
def __str__(self):
|
|
||||||
return self.msg
|
|
||||||
|
|
||||||
class DataSmart(MutableMapping):
|
|
||||||
def __init__(self, special = COWDictBase.copy(), seen = COWDictBase.copy() ):
|
def __init__(self, special = COWDictBase.copy(), seen = COWDictBase.copy() ):
|
||||||
self.dict = {}
|
self.dict = {}
|
||||||
|
|
||||||
@@ -128,10 +100,11 @@ class DataSmart(MutableMapping):
|
|||||||
s = __expand_python_regexp__.sub(varparse.python_sub, s)
|
s = __expand_python_regexp__.sub(varparse.python_sub, s)
|
||||||
if s == olds:
|
if s == olds:
|
||||||
break
|
break
|
||||||
except ExpansionError:
|
except KeyboardInterrupt:
|
||||||
|
raise
|
||||||
|
except:
|
||||||
|
bb.msg.note(1, bb.msg.domain.Data, "%s:%s while evaluating:\n%s" % (sys.exc_info()[0], sys.exc_info()[1], s))
|
||||||
raise
|
raise
|
||||||
except Exception as exc:
|
|
||||||
raise ExpansionError(varname, s, exc)
|
|
||||||
|
|
||||||
varparse.value = s
|
varparse.value = s
|
||||||
|
|
||||||
@@ -176,34 +149,39 @@ class DataSmart(MutableMapping):
|
|||||||
for var in vars:
|
for var in vars:
|
||||||
name = var[:-l]
|
name = var[:-l]
|
||||||
try:
|
try:
|
||||||
self.setVar(name, self.getVar(var, False))
|
self[name] = self[var]
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.info("Untracked delVar")
|
bb.msg.note(1, bb.msg.domain.Data, "Untracked delVar")
|
||||||
|
|
||||||
# now on to the appends and prepends
|
# now on to the appends and prepends
|
||||||
for op in __setvar_keyword__:
|
if "_append" in self._special_values:
|
||||||
if op in self._special_values:
|
appends = self._special_values["_append"] or []
|
||||||
appends = self._special_values[op] or []
|
for append in appends:
|
||||||
for append in appends:
|
for (a, o) in self.getVarFlag(append, "_append") or []:
|
||||||
keep = []
|
# maybe the OVERRIDE was not yet added so keep the append
|
||||||
for (a, o) in self.getVarFlag(append, op) or []:
|
if (o and o in overrides) or not o:
|
||||||
if o and not o in overrides:
|
self.delVarFlag(append, "_append")
|
||||||
keep.append((a ,o))
|
if o and not o in overrides:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if op is "_append":
|
sval = self.getVar(append, False) or ""
|
||||||
sval = self.getVar(append, False) or ""
|
sval += a
|
||||||
sval += a
|
self.setVar(append, sval)
|
||||||
self.setVar(append, sval)
|
|
||||||
elif op is "_prepend":
|
|
||||||
sval = a + (self.getVar(append, False) or "")
|
|
||||||
self.setVar(append, sval)
|
|
||||||
|
|
||||||
# We save overrides that may be applied at some later stage
|
|
||||||
if keep:
|
if "_prepend" in self._special_values:
|
||||||
self.setVarFlag(append, op, keep)
|
prepends = self._special_values["_prepend"] or []
|
||||||
else:
|
|
||||||
self.delVarFlag(append, op)
|
for prepend in prepends:
|
||||||
|
for (a, o) in self.getVarFlag(prepend, "_prepend") or []:
|
||||||
|
# maybe the OVERRIDE was not yet added so keep the prepend
|
||||||
|
if (o and o in overrides) or not o:
|
||||||
|
self.delVarFlag(prepend, "_prepend")
|
||||||
|
if o and not o in overrides:
|
||||||
|
continue
|
||||||
|
|
||||||
|
sval = a + (self.getVar(prepend, False) or "")
|
||||||
|
self.setVar(prepend, sval)
|
||||||
|
|
||||||
def initVar(self, var):
|
def initVar(self, var):
|
||||||
self.expand_cache = {}
|
self.expand_cache = {}
|
||||||
@@ -304,17 +282,12 @@ class DataSmart(MutableMapping):
|
|||||||
self._makeShadowCopy(var)
|
self._makeShadowCopy(var)
|
||||||
self.dict[var][flag] = flagvalue
|
self.dict[var][flag] = flagvalue
|
||||||
|
|
||||||
def getVarFlag(self, var, flag, expand=False):
|
def getVarFlag(self, var, flag):
|
||||||
local_var = self._findVar(var)
|
local_var = self._findVar(var)
|
||||||
value = None
|
|
||||||
if local_var:
|
if local_var:
|
||||||
if flag in local_var:
|
if flag in local_var:
|
||||||
value = copy.copy(local_var[flag])
|
return copy.copy(local_var[flag])
|
||||||
elif flag == "content" and "defaultval" in local_var:
|
return None
|
||||||
value = copy.copy(local_var["defaultval"])
|
|
||||||
if expand and value:
|
|
||||||
value = self.expand(value, None)
|
|
||||||
return value
|
|
||||||
|
|
||||||
def delVarFlag(self, var, flag):
|
def delVarFlag(self, var, flag):
|
||||||
local_var = self._findVar(var)
|
local_var = self._findVar(var)
|
||||||
@@ -376,53 +349,23 @@ class DataSmart(MutableMapping):
|
|||||||
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def expandVarref(self, variable, parents=False):
|
# Dictionary Methods
|
||||||
"""Find all references to variable in the data and expand it
|
def keys(self):
|
||||||
in place, optionally descending to parent datastores."""
|
def _keys(d, mykey):
|
||||||
|
|
||||||
if parents:
|
|
||||||
keys = iter(self)
|
|
||||||
else:
|
|
||||||
keys = self.localkeys()
|
|
||||||
|
|
||||||
ref = '${%s}' % variable
|
|
||||||
value = self.getVar(variable, False)
|
|
||||||
for key in keys:
|
|
||||||
referrervalue = self.getVar(key, False)
|
|
||||||
if referrervalue and ref in referrervalue:
|
|
||||||
self.setVar(key, referrervalue.replace(ref, value))
|
|
||||||
|
|
||||||
def localkeys(self):
|
|
||||||
for key in self.dict:
|
|
||||||
if key != '_data':
|
|
||||||
yield key
|
|
||||||
|
|
||||||
def __iter__(self):
|
|
||||||
seen = set()
|
|
||||||
def _keys(d):
|
|
||||||
if "_data" in d:
|
if "_data" in d:
|
||||||
for key in _keys(d["_data"]):
|
_keys(d["_data"], mykey)
|
||||||
yield key
|
|
||||||
|
|
||||||
for key in d:
|
for key in d.keys():
|
||||||
if key != "_data":
|
if key != "_data":
|
||||||
if not key in seen:
|
mykey[key] = None
|
||||||
seen.add(key)
|
keytab = {}
|
||||||
yield key
|
_keys(self.dict, keytab)
|
||||||
return _keys(self.dict)
|
return keytab.keys()
|
||||||
|
|
||||||
def __len__(self):
|
|
||||||
return len(frozenset(self))
|
|
||||||
|
|
||||||
def __getitem__(self, item):
|
def __getitem__(self, item):
|
||||||
value = self.getVar(item, False)
|
#print "Warning deprecated"
|
||||||
if value is None:
|
return self.getVar(item, False)
|
||||||
raise KeyError(item)
|
|
||||||
else:
|
|
||||||
return value
|
|
||||||
|
|
||||||
def __setitem__(self, var, value):
|
def __setitem__(self, var, data):
|
||||||
self.setVar(var, value)
|
#print "Warning deprecated"
|
||||||
|
self.setVar(var, data)
|
||||||
def __delitem__(self, var):
|
|
||||||
self.delVar(var)
|
|
||||||
|
|||||||
@@ -24,20 +24,16 @@ BitBake build tools.
|
|||||||
|
|
||||||
import os, sys
|
import os, sys
|
||||||
import warnings
|
import warnings
|
||||||
try:
|
|
||||||
import cPickle as pickle
|
|
||||||
except ImportError:
|
|
||||||
import pickle
|
|
||||||
import logging
|
|
||||||
import atexit
|
|
||||||
import bb.utils
|
import bb.utils
|
||||||
|
import pickle
|
||||||
|
|
||||||
# This is the pid for which we should generate the event. This is set when
|
# This is the pid for which we should generate the event. This is set when
|
||||||
# the runqueue forks off.
|
# the runqueue forks off.
|
||||||
worker_pid = 0
|
worker_pid = 0
|
||||||
worker_pipe = None
|
worker_pipe = None
|
||||||
|
useStdout = True
|
||||||
|
|
||||||
class Event(object):
|
class Event:
|
||||||
"""Base class for events"""
|
"""Base class for events"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@@ -59,7 +55,8 @@ bb.utils._context["NotHandled"] = NotHandled
|
|||||||
bb.utils._context["Handled"] = Handled
|
bb.utils._context["Handled"] = Handled
|
||||||
|
|
||||||
def fire_class_handlers(event, d):
|
def fire_class_handlers(event, d):
|
||||||
if isinstance(event, logging.LogRecord):
|
import bb.msg
|
||||||
|
if isinstance(event, bb.msg.MsgBase):
|
||||||
return
|
return
|
||||||
|
|
||||||
for handler in _handlers:
|
for handler in _handlers:
|
||||||
@@ -76,28 +73,7 @@ def fire_class_handlers(event, d):
|
|||||||
h(event)
|
h(event)
|
||||||
del event.data
|
del event.data
|
||||||
|
|
||||||
ui_queue = []
|
|
||||||
@atexit.register
|
|
||||||
def print_ui_queue():
|
|
||||||
"""If we're exiting before a UI has been spawned, display any queued
|
|
||||||
LogRecords to the console."""
|
|
||||||
logger = logging.getLogger("BitBake")
|
|
||||||
if not _ui_handlers:
|
|
||||||
from bb.msg import BBLogFormatter
|
|
||||||
console = logging.StreamHandler(sys.stdout)
|
|
||||||
console.setFormatter(BBLogFormatter("%(levelname)s: %(message)s"))
|
|
||||||
logger.handlers = [console]
|
|
||||||
while ui_queue:
|
|
||||||
event = ui_queue.pop()
|
|
||||||
if isinstance(event, logging.LogRecord):
|
|
||||||
logger.handle(event)
|
|
||||||
|
|
||||||
def fire_ui_handlers(event, d):
|
def fire_ui_handlers(event, d):
|
||||||
if not _ui_handlers:
|
|
||||||
# No UI handlers registered yet, queue up the messages
|
|
||||||
ui_queue.append(event)
|
|
||||||
return
|
|
||||||
|
|
||||||
errors = []
|
errors = []
|
||||||
for h in _ui_handlers:
|
for h in _ui_handlers:
|
||||||
#print "Sending event %s" % event
|
#print "Sending event %s" % event
|
||||||
@@ -128,11 +104,13 @@ def fire(event, d):
|
|||||||
def worker_fire(event, d):
|
def worker_fire(event, d):
|
||||||
data = "<event>" + pickle.dumps(event) + "</event>"
|
data = "<event>" + pickle.dumps(event) + "</event>"
|
||||||
worker_pipe.write(data)
|
worker_pipe.write(data)
|
||||||
|
worker_pipe.flush()
|
||||||
|
|
||||||
def fire_from_worker(event, d):
|
def fire_from_worker(event, d):
|
||||||
if not event.startswith("<event>") or not event.endswith("</event>"):
|
if not event.startswith("<event>") or not event.endswith("</event>"):
|
||||||
print("Error, not an event %s" % event)
|
print("Error, not an event %s" % event)
|
||||||
return
|
return
|
||||||
|
#print "Got event %s" % event
|
||||||
event = pickle.loads(event[7:-8])
|
event = pickle.loads(event[7:-8])
|
||||||
fire_ui_handlers(event, d)
|
fire_ui_handlers(event, d)
|
||||||
|
|
||||||
@@ -145,7 +123,7 @@ def register(name, handler):
|
|||||||
|
|
||||||
if handler is not None:
|
if handler is not None:
|
||||||
# handle string containing python code
|
# handle string containing python code
|
||||||
if isinstance(handler, basestring):
|
if type(handler).__name__ == "str":
|
||||||
tmp = "def tmpHandler(e):\n%s" % handler
|
tmp = "def tmpHandler(e):\n%s" % handler
|
||||||
comp = bb.utils.better_compile(tmp, "tmpHandler(e)", "bb.event._registerCode")
|
comp = bb.utils.better_compile(tmp, "tmpHandler(e)", "bb.event._registerCode")
|
||||||
_handlers[name] = comp
|
_handlers[name] = comp
|
||||||
@@ -161,6 +139,7 @@ def remove(name, handler):
|
|||||||
def register_UIHhandler(handler):
|
def register_UIHhandler(handler):
|
||||||
bb.event._ui_handler_seq = bb.event._ui_handler_seq + 1
|
bb.event._ui_handler_seq = bb.event._ui_handler_seq + 1
|
||||||
_ui_handlers[_ui_handler_seq] = handler
|
_ui_handlers[_ui_handler_seq] = handler
|
||||||
|
bb.event.useStdout = False
|
||||||
return _ui_handler_seq
|
return _ui_handler_seq
|
||||||
|
|
||||||
def unregister_UIHhandler(handlerNum):
|
def unregister_UIHhandler(handlerNum):
|
||||||
@@ -295,14 +274,10 @@ class MultipleProviders(Event):
|
|||||||
"""
|
"""
|
||||||
return self._candidates
|
return self._candidates
|
||||||
|
|
||||||
class ParseStarted(Event):
|
class ParseProgress(Event):
|
||||||
"""Recipe parsing for the runqueue has begun"""
|
"""
|
||||||
def __init__(self, total):
|
Parsing Progress Event
|
||||||
Event.__init__(self)
|
"""
|
||||||
self.total = total
|
|
||||||
|
|
||||||
class ParseCompleted(Event):
|
|
||||||
"""Recipe parsing for the runqueue has completed"""
|
|
||||||
|
|
||||||
def __init__(self, cached, parsed, skipped, masked, virtuals, errors, total):
|
def __init__(self, cached, parsed, skipped, masked, virtuals, errors, total):
|
||||||
Event.__init__(self)
|
Event.__init__(self)
|
||||||
@@ -315,32 +290,6 @@ class ParseCompleted(Event):
|
|||||||
self.sofar = cached + parsed
|
self.sofar = cached + parsed
|
||||||
self.total = total
|
self.total = total
|
||||||
|
|
||||||
class ParseProgress(Event):
|
|
||||||
"""Recipe parsing progress"""
|
|
||||||
|
|
||||||
def __init__(self, current):
|
|
||||||
self.current = current
|
|
||||||
|
|
||||||
class CacheLoadStarted(Event):
|
|
||||||
"""Loading of the dependency cache has begun"""
|
|
||||||
def __init__(self, total):
|
|
||||||
Event.__init__(self)
|
|
||||||
self.total = total
|
|
||||||
|
|
||||||
class CacheLoadProgress(Event):
|
|
||||||
"""Cache loading progress"""
|
|
||||||
def __init__(self, current):
|
|
||||||
Event.__init__(self)
|
|
||||||
self.current = current
|
|
||||||
|
|
||||||
class CacheLoadCompleted(Event):
|
|
||||||
"""Cache loading is complete"""
|
|
||||||
def __init__(self, total, num_entries):
|
|
||||||
Event.__init__(self)
|
|
||||||
self.total = total
|
|
||||||
self.num_entries = num_entries
|
|
||||||
|
|
||||||
|
|
||||||
class DepTreeGenerated(Event):
|
class DepTreeGenerated(Event):
|
||||||
"""
|
"""
|
||||||
Event when a dependency tree has been generated
|
Event when a dependency tree has been generated
|
||||||
@@ -349,55 +298,3 @@ class DepTreeGenerated(Event):
|
|||||||
def __init__(self, depgraph):
|
def __init__(self, depgraph):
|
||||||
Event.__init__(self)
|
Event.__init__(self)
|
||||||
self._depgraph = depgraph
|
self._depgraph = depgraph
|
||||||
|
|
||||||
class TargetsTreeGenerated(Event):
|
|
||||||
"""
|
|
||||||
Event when a set of buildable targets has been generated
|
|
||||||
"""
|
|
||||||
def __init__(self, model):
|
|
||||||
Event.__init__(self)
|
|
||||||
self._model = model
|
|
||||||
|
|
||||||
class ConfigFilesFound(Event):
|
|
||||||
"""
|
|
||||||
Event when a list of appropriate config files has been generated
|
|
||||||
"""
|
|
||||||
def __init__(self, variable, values):
|
|
||||||
Event.__init__(self)
|
|
||||||
self._variable = variable
|
|
||||||
self._values = values
|
|
||||||
|
|
||||||
class MsgBase(Event):
|
|
||||||
"""Base class for messages"""
|
|
||||||
|
|
||||||
def __init__(self, msg):
|
|
||||||
self._message = msg
|
|
||||||
Event.__init__(self)
|
|
||||||
|
|
||||||
class MsgDebug(MsgBase):
|
|
||||||
"""Debug Message"""
|
|
||||||
|
|
||||||
class MsgNote(MsgBase):
|
|
||||||
"""Note Message"""
|
|
||||||
|
|
||||||
class MsgWarn(MsgBase):
|
|
||||||
"""Warning Message"""
|
|
||||||
|
|
||||||
class MsgError(MsgBase):
|
|
||||||
"""Error Message"""
|
|
||||||
|
|
||||||
class MsgFatal(MsgBase):
|
|
||||||
"""Fatal Message"""
|
|
||||||
|
|
||||||
class MsgPlain(MsgBase):
|
|
||||||
"""General output"""
|
|
||||||
|
|
||||||
class LogHandler(logging.Handler):
|
|
||||||
"""Dispatch logging messages as bitbake events"""
|
|
||||||
|
|
||||||
def emit(self, record):
|
|
||||||
fire(record, None)
|
|
||||||
|
|
||||||
def filter(self, record):
|
|
||||||
record.taskpid = worker_pid
|
|
||||||
return True
|
|
||||||
|
|||||||
@@ -27,15 +27,9 @@ BitBake build tools.
|
|||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
import os, re
|
import os, re
|
||||||
import logging
|
|
||||||
import bb
|
import bb
|
||||||
from bb import data
|
from bb import data
|
||||||
from bb import persist_data
|
from bb import persist_data
|
||||||
from bb import utils
|
|
||||||
|
|
||||||
__version__ = "1"
|
|
||||||
|
|
||||||
logger = logging.getLogger("BitBake.Fetch")
|
|
||||||
|
|
||||||
class MalformedUrl(Exception):
|
class MalformedUrl(Exception):
|
||||||
"""Exception raised when encountering an invalid url"""
|
"""Exception raised when encountering an invalid url"""
|
||||||
@@ -123,8 +117,9 @@ def encodeurl(decoded):
|
|||||||
return url
|
return url
|
||||||
|
|
||||||
def uri_replace(uri, uri_find, uri_replace, d):
|
def uri_replace(uri, uri_find, uri_replace, d):
|
||||||
|
# bb.msg.note(1, bb.msg.domain.Fetcher, "uri_replace: operating on %s" % uri)
|
||||||
if not uri or not uri_find or not uri_replace:
|
if not uri or not uri_find or not uri_replace:
|
||||||
logger.debug(1, "uri_replace: passed an undefined value, not replacing")
|
bb.msg.debug(1, bb.msg.domain.Fetcher, "uri_replace: passed an undefined value, not replacing")
|
||||||
uri_decoded = list(decodeurl(uri))
|
uri_decoded = list(decodeurl(uri))
|
||||||
uri_find_decoded = list(decodeurl(uri_find))
|
uri_find_decoded = list(decodeurl(uri_find))
|
||||||
uri_replace_decoded = list(decodeurl(uri_replace))
|
uri_replace_decoded = list(decodeurl(uri_replace))
|
||||||
@@ -139,32 +134,38 @@ def uri_replace(uri, uri_find, uri_replace, d):
|
|||||||
if d:
|
if d:
|
||||||
localfn = bb.fetch.localpath(uri, d)
|
localfn = bb.fetch.localpath(uri, d)
|
||||||
if localfn:
|
if localfn:
|
||||||
result_decoded[loc] = os.path.join(os.path.dirname(result_decoded[loc]), os.path.basename(bb.fetch.localpath(uri, d)))
|
result_decoded[loc] = os.path.dirname(result_decoded[loc]) + "/" + os.path.basename(bb.fetch.localpath(uri, d))
|
||||||
|
# bb.msg.note(1, bb.msg.domain.Fetcher, "uri_replace: matching %s against %s and replacing with %s" % (i, uri_decoded[loc], uri_replace_decoded[loc]))
|
||||||
else:
|
else:
|
||||||
|
# bb.msg.note(1, bb.msg.domain.Fetcher, "uri_replace: no match")
|
||||||
return uri
|
return uri
|
||||||
|
# else:
|
||||||
|
# for j in i:
|
||||||
|
# FIXME: apply replacements against options
|
||||||
return encodeurl(result_decoded)
|
return encodeurl(result_decoded)
|
||||||
|
|
||||||
methods = []
|
methods = []
|
||||||
urldata_cache = {}
|
urldata_cache = {}
|
||||||
saved_headrevs = {}
|
saved_headrevs = {}
|
||||||
|
persistent_database_connection = {}
|
||||||
|
|
||||||
def fetcher_init(d):
|
def fetcher_init(d):
|
||||||
"""
|
"""
|
||||||
Called to initialize the fetchers once the configuration data is known.
|
Called to initialize the fetchers once the configuration data is known.
|
||||||
Calls before this must not hit the cache.
|
Calls before this must not hit the cache.
|
||||||
"""
|
"""
|
||||||
pd = persist_data.persist(d)
|
pd = persist_data.PersistData(d, persistent_database_connection)
|
||||||
# When to drop SCM head revisions controlled by user policy
|
# When to drop SCM head revisions controlled by user policy
|
||||||
srcrev_policy = bb.data.getVar('BB_SRCREV_POLICY', d, 1) or "clear"
|
srcrev_policy = bb.data.getVar('BB_SRCREV_POLICY', d, 1) or "clear"
|
||||||
if srcrev_policy == "cache":
|
if srcrev_policy == "cache":
|
||||||
logger.debug(1, "Keeping SRCREV cache due to cache policy of: %s", srcrev_policy)
|
bb.msg.debug(1, bb.msg.domain.Fetcher, "Keeping SRCREV cache due to cache policy of: %s" % srcrev_policy)
|
||||||
elif srcrev_policy == "clear":
|
elif srcrev_policy == "clear":
|
||||||
logger.debug(1, "Clearing SRCREV cache due to cache policy of: %s", srcrev_policy)
|
bb.msg.debug(1, bb.msg.domain.Fetcher, "Clearing SRCREV cache due to cache policy of: %s" % srcrev_policy)
|
||||||
try:
|
try:
|
||||||
bb.fetch.saved_headrevs = pd['BB_URI_HEADREVS'].items()
|
bb.fetch.saved_headrevs = pd.getKeyValues("BB_URI_HEADREVS")
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
del pd['BB_URI_HEADREVS']
|
pd.delDomain("BB_URI_HEADREVS")
|
||||||
else:
|
else:
|
||||||
raise FetchError("Invalid SRCREV cache policy of: %s" % srcrev_policy)
|
raise FetchError("Invalid SRCREV cache policy of: %s" % srcrev_policy)
|
||||||
|
|
||||||
@@ -172,24 +173,28 @@ def fetcher_init(d):
|
|||||||
if hasattr(m, "init"):
|
if hasattr(m, "init"):
|
||||||
m.init(d)
|
m.init(d)
|
||||||
|
|
||||||
def fetcher_compare_revisions(d):
|
# Make sure our domains exist
|
||||||
|
pd.addDomain("BB_URI_HEADREVS")
|
||||||
|
pd.addDomain("BB_URI_LOCALCOUNT")
|
||||||
|
|
||||||
|
def fetcher_compare_revisons(d):
|
||||||
"""
|
"""
|
||||||
Compare the revisions in the persistant cache with current values and
|
Compare the revisions in the persistant cache with current values and
|
||||||
return true/false on whether they've changed.
|
return true/false on whether they've changed.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
pd = persist_data.persist(d)
|
pd = persist_data.PersistData(d, persistent_database_connection)
|
||||||
data = pd['BB_URI_HEADREVS'].items()
|
data = pd.getKeyValues("BB_URI_HEADREVS")
|
||||||
data2 = bb.fetch.saved_headrevs
|
data2 = bb.fetch.saved_headrevs
|
||||||
|
|
||||||
changed = False
|
changed = False
|
||||||
for key in data:
|
for key in data:
|
||||||
if key not in data2 or data2[key] != data[key]:
|
if key not in data2 or data2[key] != data[key]:
|
||||||
logger.debug(1, "%s changed", key)
|
bb.msg.debug(1, bb.msg.domain.Fetcher, "%s changed" % key)
|
||||||
changed = True
|
changed = True
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
logger.debug(2, "%s did not change", key)
|
bb.msg.debug(2, bb.msg.domain.Fetcher, "%s did not change" % key)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# Function call order is usually:
|
# Function call order is usually:
|
||||||
@@ -220,41 +225,11 @@ def init(urls, d, setup = True):
|
|||||||
def mirror_from_string(data):
|
def mirror_from_string(data):
|
||||||
return [ i.split() for i in (data or "").replace('\\n','\n').split('\n') if i ]
|
return [ i.split() for i in (data or "").replace('\\n','\n').split('\n') if i ]
|
||||||
|
|
||||||
def verify_checksum(u, ud, d):
|
def removefile(f):
|
||||||
"""
|
try:
|
||||||
verify the MD5 and SHA256 checksum for downloaded src
|
os.remove(f)
|
||||||
|
except:
|
||||||
return value:
|
pass
|
||||||
- True: checksum matched
|
|
||||||
- False: checksum unmatched
|
|
||||||
|
|
||||||
if checksum is missing in recipes file, "BB_STRICT_CHECKSUM" decide the return value.
|
|
||||||
if BB_STRICT_CHECKSUM = "1" then return false as unmatched, otherwise return true as
|
|
||||||
matched
|
|
||||||
"""
|
|
||||||
|
|
||||||
if not ud.type in ["http", "https", "ftp", "ftps"]:
|
|
||||||
return
|
|
||||||
|
|
||||||
md5data = bb.utils.md5_file(ud.localpath)
|
|
||||||
sha256data = bb.utils.sha256_file(ud.localpath)
|
|
||||||
|
|
||||||
if (ud.md5_expected == None or ud.sha256_expected == None):
|
|
||||||
logger.warn('Missing SRC_URI checksum for %s, consider adding to the recipe:\n'
|
|
||||||
'SRC_URI[%s] = "%s"\nSRC_URI[%s] = "%s"',
|
|
||||||
ud.localpath, ud.md5_name, md5data,
|
|
||||||
ud.sha256_name, sha256data)
|
|
||||||
if bb.data.getVar("BB_STRICT_CHECKSUM", d, True) == "1":
|
|
||||||
raise FetchError("No checksum specified for %s." % u)
|
|
||||||
return
|
|
||||||
|
|
||||||
if (ud.md5_expected != md5data or ud.sha256_expected != sha256data):
|
|
||||||
logger.error('The checksums for "%s" did not match.\n'
|
|
||||||
' MD5: expected "%s", got "%s"\n'
|
|
||||||
' SHA256: expected "%s", got "%s"\n',
|
|
||||||
ud.localpath, ud.md5_expected, md5data,
|
|
||||||
ud.sha256_expected, sha256data)
|
|
||||||
raise FetchError("%s checksum mismatch." % u)
|
|
||||||
|
|
||||||
def go(d, urls = None):
|
def go(d, urls = None):
|
||||||
"""
|
"""
|
||||||
@@ -290,7 +265,7 @@ def go(d, urls = None):
|
|||||||
localpath = ud.localpath
|
localpath = ud.localpath
|
||||||
except FetchError:
|
except FetchError:
|
||||||
# Remove any incomplete file
|
# Remove any incomplete file
|
||||||
bb.utils.remove(ud.localpath)
|
removefile(ud.localpath)
|
||||||
# Finally, try fetching uri, u, from MIRRORS
|
# Finally, try fetching uri, u, from MIRRORS
|
||||||
mirrors = mirror_from_string(bb.data.getVar('MIRRORS', d, True))
|
mirrors = mirror_from_string(bb.data.getVar('MIRRORS', d, True))
|
||||||
localpath = try_mirrors (d, u, mirrors)
|
localpath = try_mirrors (d, u, mirrors)
|
||||||
@@ -298,7 +273,6 @@ def go(d, urls = None):
|
|||||||
raise FetchError("Unable to fetch URL %s from any source." % u)
|
raise FetchError("Unable to fetch URL %s from any source." % u)
|
||||||
|
|
||||||
ud.localpath = localpath
|
ud.localpath = localpath
|
||||||
|
|
||||||
if os.path.exists(ud.md5):
|
if os.path.exists(ud.md5):
|
||||||
# Touch the md5 file to show active use of the download
|
# Touch the md5 file to show active use of the download
|
||||||
try:
|
try:
|
||||||
@@ -307,26 +281,21 @@ def go(d, urls = None):
|
|||||||
# Errors aren't fatal here
|
# Errors aren't fatal here
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
# Only check the checksums if we've not seen this item before
|
|
||||||
verify_checksum(u, ud, d)
|
|
||||||
Fetch.write_md5sum(u, ud, d)
|
Fetch.write_md5sum(u, ud, d)
|
||||||
|
|
||||||
bb.utils.unlockfile(lf)
|
bb.utils.unlockfile(lf)
|
||||||
|
|
||||||
def checkstatus(d, urls = None):
|
def checkstatus(d):
|
||||||
"""
|
"""
|
||||||
Check all urls exist upstream
|
Check all urls exist upstream
|
||||||
init must have previously been called
|
init must have previously been called
|
||||||
"""
|
"""
|
||||||
urldata = init([], d, True)
|
urldata = init([], d, True)
|
||||||
|
|
||||||
if not urls:
|
for u in urldata:
|
||||||
urls = urldata
|
|
||||||
|
|
||||||
for u in urls:
|
|
||||||
ud = urldata[u]
|
ud = urldata[u]
|
||||||
m = ud.method
|
m = ud.method
|
||||||
logger.debug(1, "Testing URL %s", u)
|
bb.msg.debug(1, bb.msg.domain.Fetcher, "Testing URL %s" % u)
|
||||||
# First try checking uri, u, from PREMIRRORS
|
# First try checking uri, u, from PREMIRRORS
|
||||||
mirrors = mirror_from_string(bb.data.getVar('PREMIRRORS', d, True))
|
mirrors = mirror_from_string(bb.data.getVar('PREMIRRORS', d, True))
|
||||||
ret = try_mirrors(d, u, mirrors, True)
|
ret = try_mirrors(d, u, mirrors, True)
|
||||||
@@ -357,9 +326,6 @@ def localpaths(d):
|
|||||||
|
|
||||||
srcrev_internal_call = False
|
srcrev_internal_call = False
|
||||||
|
|
||||||
def get_autorev(d):
|
|
||||||
return get_srcrev(d)
|
|
||||||
|
|
||||||
def get_srcrev(d):
|
def get_srcrev(d):
|
||||||
"""
|
"""
|
||||||
Return the version string for the current package
|
Return the version string for the current package
|
||||||
@@ -383,17 +349,17 @@ def get_srcrev(d):
|
|||||||
|
|
||||||
scms = []
|
scms = []
|
||||||
|
|
||||||
# Only call setup_localpath on URIs which supports_srcrev()
|
# Only call setup_localpath on URIs which suppports_srcrev()
|
||||||
urldata = init(bb.data.getVar('SRC_URI', d, 1).split(), d, False)
|
urldata = init(bb.data.getVar('SRC_URI', d, 1).split(), d, False)
|
||||||
for u in urldata:
|
for u in urldata:
|
||||||
ud = urldata[u]
|
ud = urldata[u]
|
||||||
if ud.method.supports_srcrev():
|
if ud.method.suppports_srcrev():
|
||||||
if not ud.setup:
|
if not ud.setup:
|
||||||
ud.setup_localpath(d)
|
ud.setup_localpath(d)
|
||||||
scms.append(u)
|
scms.append(u)
|
||||||
|
|
||||||
if len(scms) == 0:
|
if len(scms) == 0:
|
||||||
logger.error("SRCREV was used yet no valid SCM was found in SRC_URI")
|
bb.msg.error(bb.msg.domain.Fetcher, "SRCREV was used yet no valid SCM was found in SRC_URI")
|
||||||
raise ParameterError
|
raise ParameterError
|
||||||
|
|
||||||
if bb.data.getVar('BB_SRCREV_POLICY', d, True) != "cache":
|
if bb.data.getVar('BB_SRCREV_POLICY', d, True) != "cache":
|
||||||
@@ -407,7 +373,7 @@ def get_srcrev(d):
|
|||||||
#
|
#
|
||||||
format = bb.data.getVar('SRCREV_FORMAT', d, 1)
|
format = bb.data.getVar('SRCREV_FORMAT', d, 1)
|
||||||
if not format:
|
if not format:
|
||||||
logger.error("The SRCREV_FORMAT variable must be set when multiple SCMs are used.")
|
bb.msg.error(bb.msg.domain.Fetcher, "The SRCREV_FORMAT variable must be set when multiple SCMs are used.")
|
||||||
raise ParameterError
|
raise ParameterError
|
||||||
|
|
||||||
for scm in scms:
|
for scm in scms:
|
||||||
@@ -442,14 +408,14 @@ def runfetchcmd(cmd, d, quiet = False):
|
|||||||
exportvars = ['PATH', 'GIT_PROXY_COMMAND', 'GIT_PROXY_HOST',
|
exportvars = ['PATH', 'GIT_PROXY_COMMAND', 'GIT_PROXY_HOST',
|
||||||
'GIT_PROXY_PORT', 'GIT_CONFIG', 'http_proxy', 'ftp_proxy',
|
'GIT_PROXY_PORT', 'GIT_CONFIG', 'http_proxy', 'ftp_proxy',
|
||||||
'https_proxy', 'no_proxy', 'ALL_PROXY', 'all_proxy',
|
'https_proxy', 'no_proxy', 'ALL_PROXY', 'all_proxy',
|
||||||
'KRB5CCNAME', 'SSH_AUTH_SOCK', 'SSH_AGENT_PID', 'HOME']
|
'SSH_AUTH_SOCK', 'SSH_AGENT_PID', 'HOME']
|
||||||
|
|
||||||
for var in exportvars:
|
for var in exportvars:
|
||||||
val = data.getVar(var, d, True)
|
val = data.getVar(var, d, True)
|
||||||
if val:
|
if val:
|
||||||
cmd = 'export ' + var + '=\"%s\"; %s' % (val, cmd)
|
cmd = 'export ' + var + '=\"%s\"; %s' % (val, cmd)
|
||||||
|
|
||||||
logger.debug(1, "Running %s", cmd)
|
bb.msg.debug(1, bb.msg.domain.Fetcher, "Running %s" % cmd)
|
||||||
|
|
||||||
# redirect stderr to stdout
|
# redirect stderr to stdout
|
||||||
stdout_handle = os.popen(cmd + " 2>&1", "r")
|
stdout_handle = os.popen(cmd + " 2>&1", "r")
|
||||||
@@ -485,7 +451,7 @@ def try_mirrors(d, uri, mirrors, check = False, force = False):
|
|||||||
"""
|
"""
|
||||||
fpath = os.path.join(data.getVar("DL_DIR", d, 1), os.path.basename(uri))
|
fpath = os.path.join(data.getVar("DL_DIR", d, 1), os.path.basename(uri))
|
||||||
if not check and os.access(fpath, os.R_OK) and not force:
|
if not check and os.access(fpath, os.R_OK) and not force:
|
||||||
logger.debug(1, "%s already exists, skipping checkout.", fpath)
|
bb.msg.debug(1, bb.msg.domain.Fetcher, "%s already exists, skipping checkout." % fpath)
|
||||||
return fpath
|
return fpath
|
||||||
|
|
||||||
ld = d.createCopy()
|
ld = d.createCopy()
|
||||||
@@ -495,26 +461,24 @@ def try_mirrors(d, uri, mirrors, check = False, force = False):
|
|||||||
try:
|
try:
|
||||||
ud = FetchData(newuri, ld)
|
ud = FetchData(newuri, ld)
|
||||||
except bb.fetch.NoMethodError:
|
except bb.fetch.NoMethodError:
|
||||||
logger.debug(1, "No method for %s", uri)
|
bb.msg.debug(1, bb.msg.domain.Fetcher, "No method for %s" % uri)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
ud.setup_localpath(ld)
|
ud.setup_localpath(ld)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if check:
|
if check:
|
||||||
found = ud.method.checkstatus(newuri, ud, ld)
|
ud.method.checkstatus(newuri, ud, ld)
|
||||||
if found:
|
|
||||||
return found
|
|
||||||
else:
|
else:
|
||||||
ud.method.go(newuri, ud, ld)
|
ud.method.go(newuri, ud, ld)
|
||||||
return ud.localpath
|
return ud.localpath
|
||||||
except (bb.fetch.MissingParameterError,
|
except (bb.fetch.MissingParameterError,
|
||||||
bb.fetch.FetchError,
|
bb.fetch.FetchError,
|
||||||
bb.fetch.MD5SumError):
|
bb.fetch.MD5SumError):
|
||||||
import sys
|
import sys
|
||||||
(type, value, traceback) = sys.exc_info()
|
(type, value, traceback) = sys.exc_info()
|
||||||
logger.debug(2, "Mirror fetch failure: %s", value)
|
bb.msg.debug(2, bb.msg.domain.Fetcher, "Mirror fetch failure: %s" % value)
|
||||||
bb.utils.remove(ud.localpath)
|
removefile(ud.localpath)
|
||||||
continue
|
continue
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@@ -533,16 +497,6 @@ class FetchData(object):
|
|||||||
if not self.pswd and "pswd" in self.parm:
|
if not self.pswd and "pswd" in self.parm:
|
||||||
self.pswd = self.parm["pswd"]
|
self.pswd = self.parm["pswd"]
|
||||||
self.setup = False
|
self.setup = False
|
||||||
|
|
||||||
if "name" in self.parm:
|
|
||||||
self.md5_name = "%s.md5sum" % self.parm["name"]
|
|
||||||
self.sha256_name = "%s.sha256sum" % self.parm["name"]
|
|
||||||
else:
|
|
||||||
self.md5_name = "md5sum"
|
|
||||||
self.sha256_name = "sha256sum"
|
|
||||||
self.md5_expected = bb.data.getVarFlag("SRC_URI", self.md5_name, d)
|
|
||||||
self.sha256_expected = bb.data.getVarFlag("SRC_URI", self.sha256_name, d)
|
|
||||||
|
|
||||||
for m in methods:
|
for m in methods:
|
||||||
if m.supports(url, self, d):
|
if m.supports(url, self, d):
|
||||||
self.method = m
|
self.method = m
|
||||||
@@ -605,13 +559,6 @@ class Fetch(object):
|
|||||||
and duplicate code execution)
|
and duplicate code execution)
|
||||||
"""
|
"""
|
||||||
return url
|
return url
|
||||||
def _strip_leading_slashes(self, relpath):
|
|
||||||
"""
|
|
||||||
Remove leading slash as os.path.join can't cope
|
|
||||||
"""
|
|
||||||
while os.path.isabs(relpath):
|
|
||||||
relpath = relpath[1:]
|
|
||||||
return relpath
|
|
||||||
|
|
||||||
def setUrls(self, urls):
|
def setUrls(self, urls):
|
||||||
self.__urls = urls
|
self.__urls = urls
|
||||||
@@ -627,7 +574,7 @@ class Fetch(object):
|
|||||||
"""
|
"""
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def supports_srcrev(self):
|
def suppports_srcrev(self):
|
||||||
"""
|
"""
|
||||||
The fetcher supports auto source revisions (SRCREV)
|
The fetcher supports auto source revisions (SRCREV)
|
||||||
"""
|
"""
|
||||||
@@ -656,7 +603,7 @@ class Fetch(object):
|
|||||||
Check the status of a URL
|
Check the status of a URL
|
||||||
Assumes localpath was called first
|
Assumes localpath was called first
|
||||||
"""
|
"""
|
||||||
logger.info("URL %s could not be checked for status since no method exists.", url)
|
bb.msg.note(1, bb.msg.domain.Fetcher, "URL %s could not be checked for status since no method exists." % url)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def getSRCDate(urldata, d):
|
def getSRCDate(urldata, d):
|
||||||
@@ -704,7 +651,7 @@ class Fetch(object):
|
|||||||
raise InvalidSRCREV("Please set SRCREV to a valid value")
|
raise InvalidSRCREV("Please set SRCREV to a valid value")
|
||||||
if not rev:
|
if not rev:
|
||||||
return False
|
return False
|
||||||
if rev == "SRCREVINACTION":
|
if rev is "SRCREVINACTION":
|
||||||
return True
|
return True
|
||||||
return rev
|
return rev
|
||||||
|
|
||||||
@@ -731,7 +678,9 @@ class Fetch(object):
|
|||||||
"""
|
"""
|
||||||
Verify the md5sum we wanted with the one we got
|
Verify the md5sum we wanted with the one we got
|
||||||
"""
|
"""
|
||||||
wanted_sum = ud.parm.get('md5sum')
|
wanted_sum = None
|
||||||
|
if 'md5sum' in ud.parm:
|
||||||
|
wanted_sum = ud.parm['md5sum']
|
||||||
if not wanted_sum:
|
if not wanted_sum:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@@ -756,14 +705,14 @@ class Fetch(object):
|
|||||||
if not hasattr(self, "_latest_revision"):
|
if not hasattr(self, "_latest_revision"):
|
||||||
raise ParameterError
|
raise ParameterError
|
||||||
|
|
||||||
pd = persist_data.persist(d)
|
pd = persist_data.PersistData(d, persistent_database_connection)
|
||||||
revs = pd['BB_URI_HEADREVS']
|
|
||||||
key = self.generate_revision_key(url, ud, d)
|
key = self.generate_revision_key(url, ud, d)
|
||||||
rev = revs[key]
|
rev = pd.getValue("BB_URI_HEADREVS", key)
|
||||||
if rev != None:
|
if rev != None:
|
||||||
return str(rev)
|
return str(rev)
|
||||||
|
|
||||||
revs[key] = rev = self._latest_revision(url, ud, d)
|
rev = self._latest_revision(url, ud, d)
|
||||||
|
pd.setValue("BB_URI_HEADREVS", key, rev)
|
||||||
return rev
|
return rev
|
||||||
|
|
||||||
def sortable_revision(self, url, ud, d):
|
def sortable_revision(self, url, ud, d):
|
||||||
@@ -773,18 +722,17 @@ class Fetch(object):
|
|||||||
if hasattr(self, "_sortable_revision"):
|
if hasattr(self, "_sortable_revision"):
|
||||||
return self._sortable_revision(url, ud, d)
|
return self._sortable_revision(url, ud, d)
|
||||||
|
|
||||||
pd = persist_data.persist(d)
|
pd = persist_data.PersistData(d, persistent_database_connection)
|
||||||
localcounts = pd['BB_URI_LOCALCOUNT']
|
|
||||||
key = self.generate_revision_key(url, ud, d)
|
key = self.generate_revision_key(url, ud, d)
|
||||||
|
|
||||||
latest_rev = self._build_revision(url, ud, d)
|
latest_rev = self._build_revision(url, ud, d)
|
||||||
last_rev = localcounts[key + '_rev']
|
last_rev = pd.getValue("BB_URI_LOCALCOUNT", key + "_rev")
|
||||||
uselocalcount = bb.data.getVar("BB_LOCALCOUNT_OVERRIDE", d, True) or False
|
uselocalcount = bb.data.getVar("BB_LOCALCOUNT_OVERRIDE", d, True) or False
|
||||||
count = None
|
count = None
|
||||||
if uselocalcount:
|
if uselocalcount:
|
||||||
count = Fetch.localcount_internal_helper(ud, d)
|
count = Fetch.localcount_internal_helper(ud, d)
|
||||||
if count is None:
|
if count is None:
|
||||||
count = localcounts[key + '_count']
|
count = pd.getValue("BB_URI_LOCALCOUNT", key + "_count")
|
||||||
|
|
||||||
if last_rev == latest_rev:
|
if last_rev == latest_rev:
|
||||||
return str(count + "+" + latest_rev)
|
return str(count + "+" + latest_rev)
|
||||||
@@ -800,8 +748,8 @@ class Fetch(object):
|
|||||||
else:
|
else:
|
||||||
count = str(int(count) + 1)
|
count = str(int(count) + 1)
|
||||||
|
|
||||||
localcounts[key + '_rev'] = latest_rev
|
pd.setValue("BB_URI_LOCALCOUNT", key + "_rev", latest_rev)
|
||||||
localcounts[key + '_count'] = count
|
pd.setValue("BB_URI_LOCALCOUNT", key + "_count", count)
|
||||||
|
|
||||||
return str(count + "+" + latest_rev)
|
return str(count + "+" + latest_rev)
|
||||||
|
|
||||||
|
|||||||
@@ -25,10 +25,11 @@ BitBake 'Fetch' implementation for bzr.
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import logging
|
|
||||||
import bb
|
import bb
|
||||||
from bb import data
|
from bb import data
|
||||||
from bb.fetch import Fetch, FetchError, runfetchcmd, logger
|
from bb.fetch import Fetch
|
||||||
|
from bb.fetch import FetchError
|
||||||
|
from bb.fetch import runfetchcmd
|
||||||
|
|
||||||
class Bzr(Fetch):
|
class Bzr(Fetch):
|
||||||
def supports(self, url, ud, d):
|
def supports(self, url, ud, d):
|
||||||
@@ -37,7 +38,10 @@ class Bzr(Fetch):
|
|||||||
def localpath (self, url, ud, d):
|
def localpath (self, url, ud, d):
|
||||||
|
|
||||||
# Create paths to bzr checkouts
|
# Create paths to bzr checkouts
|
||||||
relpath = self._strip_leading_slashes(ud.path)
|
relpath = ud.path
|
||||||
|
if relpath.startswith('/'):
|
||||||
|
# Remove leading slash as os.path.join can't cope
|
||||||
|
relpath = relpath[1:]
|
||||||
ud.pkgdir = os.path.join(data.expand('${BZRDIR}', d), ud.host, relpath)
|
ud.pkgdir = os.path.join(data.expand('${BZRDIR}', d), ud.host, relpath)
|
||||||
|
|
||||||
revision = Fetch.srcrev_internal_helper(ud, d)
|
revision = Fetch.srcrev_internal_helper(ud, d)
|
||||||
@@ -61,7 +65,9 @@ class Bzr(Fetch):
|
|||||||
|
|
||||||
basecmd = data.expand('${FETCHCMD_bzr}', d)
|
basecmd = data.expand('${FETCHCMD_bzr}', d)
|
||||||
|
|
||||||
proto = ud.parm.get('proto', 'http')
|
proto = "http"
|
||||||
|
if "proto" in ud.parm:
|
||||||
|
proto = ud.parm["proto"]
|
||||||
|
|
||||||
bzrroot = ud.host + ud.path
|
bzrroot = ud.host + ud.path
|
||||||
|
|
||||||
@@ -87,29 +93,22 @@ class Bzr(Fetch):
|
|||||||
|
|
||||||
if os.access(os.path.join(ud.pkgdir, os.path.basename(ud.pkgdir), '.bzr'), os.R_OK):
|
if os.access(os.path.join(ud.pkgdir, os.path.basename(ud.pkgdir), '.bzr'), os.R_OK):
|
||||||
bzrcmd = self._buildbzrcommand(ud, d, "update")
|
bzrcmd = self._buildbzrcommand(ud, d, "update")
|
||||||
logger.debug(1, "BZR Update %s", loc)
|
bb.msg.debug(1, bb.msg.domain.Fetcher, "BZR Update %s" % loc)
|
||||||
os.chdir(os.path.join (ud.pkgdir, os.path.basename(ud.path)))
|
os.chdir(os.path.join (ud.pkgdir, os.path.basename(ud.path)))
|
||||||
runfetchcmd(bzrcmd, d)
|
runfetchcmd(bzrcmd, d)
|
||||||
else:
|
else:
|
||||||
bb.utils.remove(os.path.join(ud.pkgdir, os.path.basename(ud.pkgdir)), True)
|
os.system("rm -rf %s" % os.path.join(ud.pkgdir, os.path.basename(ud.pkgdir)))
|
||||||
bzrcmd = self._buildbzrcommand(ud, d, "fetch")
|
bzrcmd = self._buildbzrcommand(ud, d, "fetch")
|
||||||
logger.debug(1, "BZR Checkout %s", loc)
|
bb.msg.debug(1, bb.msg.domain.Fetcher, "BZR Checkout %s" % loc)
|
||||||
bb.utils.mkdirhier(ud.pkgdir)
|
bb.mkdirhier(ud.pkgdir)
|
||||||
os.chdir(ud.pkgdir)
|
os.chdir(ud.pkgdir)
|
||||||
logger.debug(1, "Running %s", bzrcmd)
|
bb.msg.debug(1, bb.msg.domain.Fetcher, "Running %s" % bzrcmd)
|
||||||
runfetchcmd(bzrcmd, d)
|
runfetchcmd(bzrcmd, d)
|
||||||
|
|
||||||
os.chdir(ud.pkgdir)
|
os.chdir(ud.pkgdir)
|
||||||
|
|
||||||
scmdata = ud.parm.get("scmdata", "")
|
|
||||||
if scmdata == "keep":
|
|
||||||
tar_flags = ""
|
|
||||||
else:
|
|
||||||
tar_flags = "--exclude '.bzr' --exclude '.bzrtags'"
|
|
||||||
|
|
||||||
# tar them up to a defined filename
|
# tar them up to a defined filename
|
||||||
try:
|
try:
|
||||||
runfetchcmd("tar %s -czf %s %s" % (tar_flags, ud.localpath, os.path.basename(ud.pkgdir)), d)
|
runfetchcmd("tar -czf %s %s" % (ud.localpath, os.path.basename(ud.pkgdir)), d)
|
||||||
except:
|
except:
|
||||||
t, v, tb = sys.exc_info()
|
t, v, tb = sys.exc_info()
|
||||||
try:
|
try:
|
||||||
@@ -118,7 +117,7 @@ class Bzr(Fetch):
|
|||||||
pass
|
pass
|
||||||
raise t, v, tb
|
raise t, v, tb
|
||||||
|
|
||||||
def supports_srcrev(self):
|
def suppports_srcrev(self):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def _revision_key(self, url, ud, d):
|
def _revision_key(self, url, ud, d):
|
||||||
@@ -131,7 +130,7 @@ class Bzr(Fetch):
|
|||||||
"""
|
"""
|
||||||
Return the latest upstream revision number
|
Return the latest upstream revision number
|
||||||
"""
|
"""
|
||||||
logger.debug(2, "BZR fetcher hitting network for %s", url)
|
bb.msg.debug(2, bb.msg.domain.Fetcher, "BZR fetcher hitting network for %s" % url)
|
||||||
|
|
||||||
output = runfetchcmd(self._buildbzrcommand(ud, d, "revno"), d, True)
|
output = runfetchcmd(self._buildbzrcommand(ud, d, "revno"), d, True)
|
||||||
|
|
||||||
|
|||||||
@@ -27,10 +27,11 @@ BitBake build tools.
|
|||||||
#
|
#
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import logging
|
|
||||||
import bb
|
import bb
|
||||||
from bb import data
|
from bb import data
|
||||||
from bb.fetch import Fetch, FetchError, MissingParameterError, logger
|
from bb.fetch import Fetch
|
||||||
|
from bb.fetch import FetchError
|
||||||
|
from bb.fetch import MissingParameterError
|
||||||
|
|
||||||
class Cvs(Fetch):
|
class Cvs(Fetch):
|
||||||
"""
|
"""
|
||||||
@@ -47,7 +48,9 @@ class Cvs(Fetch):
|
|||||||
raise MissingParameterError("cvs method needs a 'module' parameter")
|
raise MissingParameterError("cvs method needs a 'module' parameter")
|
||||||
ud.module = ud.parm["module"]
|
ud.module = ud.parm["module"]
|
||||||
|
|
||||||
ud.tag = ud.parm.get('tag', "")
|
ud.tag = ""
|
||||||
|
if 'tag' in ud.parm:
|
||||||
|
ud.tag = ud.parm['tag']
|
||||||
|
|
||||||
# Override the default date in certain cases
|
# Override the default date in certain cases
|
||||||
if 'date' in ud.parm:
|
if 'date' in ud.parm:
|
||||||
@@ -74,9 +77,17 @@ class Cvs(Fetch):
|
|||||||
|
|
||||||
def go(self, loc, ud, d):
|
def go(self, loc, ud, d):
|
||||||
|
|
||||||
method = ud.parm.get('method', 'pserver')
|
method = "pserver"
|
||||||
localdir = ud.parm.get('localdir', ud.module)
|
if "method" in ud.parm:
|
||||||
cvs_port = ud.parm.get('port', '')
|
method = ud.parm["method"]
|
||||||
|
|
||||||
|
localdir = ud.module
|
||||||
|
if "localdir" in ud.parm:
|
||||||
|
localdir = ud.parm["localdir"]
|
||||||
|
|
||||||
|
cvs_port = ""
|
||||||
|
if "port" in ud.parm:
|
||||||
|
cvs_port = ud.parm["port"]
|
||||||
|
|
||||||
cvs_rsh = None
|
cvs_rsh = None
|
||||||
if method == "ext":
|
if method == "ext":
|
||||||
@@ -125,21 +136,21 @@ class Cvs(Fetch):
|
|||||||
cvsupdatecmd = "CVS_RSH=\"%s\" %s" % (cvs_rsh, cvsupdatecmd)
|
cvsupdatecmd = "CVS_RSH=\"%s\" %s" % (cvs_rsh, cvsupdatecmd)
|
||||||
|
|
||||||
# create module directory
|
# create module directory
|
||||||
logger.debug(2, "Fetch: checking for module directory")
|
bb.msg.debug(2, bb.msg.domain.Fetcher, "Fetch: checking for module directory")
|
||||||
pkg = data.expand('${PN}', d)
|
pkg = data.expand('${PN}', d)
|
||||||
pkgdir = os.path.join(data.expand('${CVSDIR}', localdata), pkg)
|
pkgdir = os.path.join(data.expand('${CVSDIR}', localdata), pkg)
|
||||||
moddir = os.path.join(pkgdir, localdir)
|
moddir = os.path.join(pkgdir, localdir)
|
||||||
if os.access(os.path.join(moddir, 'CVS'), os.R_OK):
|
if os.access(os.path.join(moddir, 'CVS'), os.R_OK):
|
||||||
logger.info("Update " + loc)
|
bb.msg.note(1, bb.msg.domain.Fetcher, "Update " + loc)
|
||||||
# update sources there
|
# update sources there
|
||||||
os.chdir(moddir)
|
os.chdir(moddir)
|
||||||
myret = os.system(cvsupdatecmd)
|
myret = os.system(cvsupdatecmd)
|
||||||
else:
|
else:
|
||||||
logger.info("Fetch " + loc)
|
bb.msg.note(1, bb.msg.domain.Fetcher, "Fetch " + loc)
|
||||||
# check out sources there
|
# check out sources there
|
||||||
bb.utils.mkdirhier(pkgdir)
|
bb.mkdirhier(pkgdir)
|
||||||
os.chdir(pkgdir)
|
os.chdir(pkgdir)
|
||||||
logger.debug(1, "Running %s", cvscmd)
|
bb.msg.debug(1, bb.msg.domain.Fetcher, "Running %s" % cvscmd)
|
||||||
myret = os.system(cvscmd)
|
myret = os.system(cvscmd)
|
||||||
|
|
||||||
if myret != 0 or not os.access(moddir, os.R_OK):
|
if myret != 0 or not os.access(moddir, os.R_OK):
|
||||||
@@ -149,20 +160,14 @@ class Cvs(Fetch):
|
|||||||
pass
|
pass
|
||||||
raise FetchError(ud.module)
|
raise FetchError(ud.module)
|
||||||
|
|
||||||
scmdata = ud.parm.get("scmdata", "")
|
|
||||||
if scmdata == "keep":
|
|
||||||
tar_flags = ""
|
|
||||||
else:
|
|
||||||
tar_flags = "--exclude 'CVS'"
|
|
||||||
|
|
||||||
# tar them up to a defined filename
|
# tar them up to a defined filename
|
||||||
if 'fullpath' in ud.parm:
|
if 'fullpath' in ud.parm:
|
||||||
os.chdir(pkgdir)
|
os.chdir(pkgdir)
|
||||||
myret = os.system("tar %s -czf %s %s" % (tar_flags, ud.localpath, localdir))
|
myret = os.system("tar -czf %s %s" % (ud.localpath, localdir))
|
||||||
else:
|
else:
|
||||||
os.chdir(moddir)
|
os.chdir(moddir)
|
||||||
os.chdir('..')
|
os.chdir('..')
|
||||||
myret = os.system("tar %s -czf %s %s" % (tar_flags, ud.localpath, os.path.basename(moddir)))
|
myret = os.system("tar -czf %s %s" % (ud.localpath, os.path.basename(moddir)))
|
||||||
|
|
||||||
if myret != 0:
|
if myret != 0:
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -22,11 +22,9 @@ BitBake 'Fetch' git implementation
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
import bb
|
import bb
|
||||||
import bb.persist_data
|
|
||||||
from bb import data
|
from bb import data
|
||||||
from bb.fetch import Fetch
|
from bb.fetch import Fetch
|
||||||
from bb.fetch import runfetchcmd
|
from bb.fetch import runfetchcmd
|
||||||
from bb.fetch import logger
|
|
||||||
|
|
||||||
class Git(Fetch):
|
class Git(Fetch):
|
||||||
"""Class to fetch a module or modules from git repositories"""
|
"""Class to fetch a module or modules from git repositories"""
|
||||||
@@ -118,7 +116,6 @@ class Git(Fetch):
|
|||||||
|
|
||||||
repofile = os.path.join(data.getVar("DL_DIR", d, 1), ud.mirrortarball)
|
repofile = os.path.join(data.getVar("DL_DIR", d, 1), ud.mirrortarball)
|
||||||
|
|
||||||
|
|
||||||
coname = '%s' % (ud.tag)
|
coname = '%s' % (ud.tag)
|
||||||
codir = os.path.join(ud.clonedir, coname)
|
codir = os.path.join(ud.clonedir, coname)
|
||||||
|
|
||||||
@@ -131,7 +128,7 @@ class Git(Fetch):
|
|||||||
|
|
||||||
# If the checkout doesn't exist and the mirror tarball does, extract it
|
# If the checkout doesn't exist and the mirror tarball does, extract it
|
||||||
if not os.path.exists(ud.clonedir) and os.path.exists(repofile):
|
if not os.path.exists(ud.clonedir) and os.path.exists(repofile):
|
||||||
bb.utils.mkdirhier(ud.clonedir)
|
bb.mkdirhier(ud.clonedir)
|
||||||
os.chdir(ud.clonedir)
|
os.chdir(ud.clonedir)
|
||||||
runfetchcmd("tar -xzf %s" % (repofile), d)
|
runfetchcmd("tar -xzf %s" % (repofile), d)
|
||||||
|
|
||||||
@@ -156,7 +153,7 @@ class Git(Fetch):
|
|||||||
os.chdir(ud.clonedir)
|
os.chdir(ud.clonedir)
|
||||||
mirror_tarballs = data.getVar("BB_GENERATE_MIRROR_TARBALLS", d, True)
|
mirror_tarballs = data.getVar("BB_GENERATE_MIRROR_TARBALLS", d, True)
|
||||||
if mirror_tarballs != "0" or 'fullclone' in ud.parm:
|
if mirror_tarballs != "0" or 'fullclone' in ud.parm:
|
||||||
logger.info("Creating tarball of git repository")
|
bb.msg.note(1, bb.msg.domain.Fetcher, "Creating tarball of git repository")
|
||||||
runfetchcmd("tar -czf %s %s" % (repofile, os.path.join(".", ".git", "*") ), d)
|
runfetchcmd("tar -czf %s %s" % (repofile, os.path.join(".", ".git", "*") ), d)
|
||||||
|
|
||||||
if 'fullclone' in ud.parm:
|
if 'fullclone' in ud.parm:
|
||||||
@@ -182,25 +179,19 @@ class Git(Fetch):
|
|||||||
readpathspec = ""
|
readpathspec = ""
|
||||||
coprefix = os.path.join(codir, "git", "")
|
coprefix = os.path.join(codir, "git", "")
|
||||||
|
|
||||||
scmdata = ud.parm.get("scmdata", "")
|
bb.mkdirhier(codir)
|
||||||
if scmdata == "keep":
|
os.chdir(ud.clonedir)
|
||||||
runfetchcmd("%s clone -n %s %s" % (ud.basecmd, ud.clonedir, coprefix), d)
|
runfetchcmd("%s read-tree %s%s" % (ud.basecmd, ud.tag, readpathspec), d)
|
||||||
os.chdir(coprefix)
|
runfetchcmd("%s checkout-index -q -f --prefix=%s -a" % (ud.basecmd, coprefix), d)
|
||||||
runfetchcmd("%s checkout -q -f %s%s" % (ud.basecmd, ud.tag, readpathspec), d)
|
|
||||||
else:
|
|
||||||
bb.utils.mkdirhier(codir)
|
|
||||||
os.chdir(ud.clonedir)
|
|
||||||
runfetchcmd("%s read-tree %s%s" % (ud.basecmd, ud.tag, readpathspec), d)
|
|
||||||
runfetchcmd("%s checkout-index -q -f --prefix=%s -a" % (ud.basecmd, coprefix), d)
|
|
||||||
|
|
||||||
os.chdir(codir)
|
os.chdir(codir)
|
||||||
logger.info("Creating tarball of git checkout")
|
bb.msg.note(1, bb.msg.domain.Fetcher, "Creating tarball of git checkout")
|
||||||
runfetchcmd("tar -czf %s %s" % (ud.localpath, os.path.join(".", "*") ), d)
|
runfetchcmd("tar -czf %s %s" % (ud.localpath, os.path.join(".", "*") ), d)
|
||||||
|
|
||||||
os.chdir(ud.clonedir)
|
os.chdir(ud.clonedir)
|
||||||
bb.utils.prunedir(codir)
|
bb.utils.prunedir(codir)
|
||||||
|
|
||||||
def supports_srcrev(self):
|
def suppports_srcrev(self):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def _contains_ref(self, tag, d):
|
def _contains_ref(self, tag, d):
|
||||||
@@ -208,19 +199,11 @@ class Git(Fetch):
|
|||||||
output = runfetchcmd("%s log --pretty=oneline -n 1 %s -- 2> /dev/null | wc -l" % (basecmd, tag), d, quiet=True)
|
output = runfetchcmd("%s log --pretty=oneline -n 1 %s -- 2> /dev/null | wc -l" % (basecmd, tag), d, quiet=True)
|
||||||
return output.split()[0] != "0"
|
return output.split()[0] != "0"
|
||||||
|
|
||||||
def _revision_key(self, url, ud, d, branch=False):
|
def _revision_key(self, url, ud, d):
|
||||||
"""
|
"""
|
||||||
Return a unique key for the url
|
Return a unique key for the url
|
||||||
"""
|
"""
|
||||||
key = 'git:' + ud.host + ud.path.replace('/', '.')
|
return "git:" + ud.host + ud.path.replace('/', '.') + ud.branch
|
||||||
if branch:
|
|
||||||
return key + ud.branch
|
|
||||||
else:
|
|
||||||
return key
|
|
||||||
|
|
||||||
def generate_revision_key(self, url, ud, d, branch=False):
|
|
||||||
key = self._revision_key(url, ud, d, branch)
|
|
||||||
return "%s-%s" % (key, bb.data.getVar("PN", d, True) or "")
|
|
||||||
|
|
||||||
def _latest_revision(self, url, ud, d):
|
def _latest_revision(self, url, ud, d):
|
||||||
"""
|
"""
|
||||||
@@ -238,74 +221,6 @@ class Git(Fetch):
|
|||||||
raise bb.fetch.FetchError("Fetch command %s gave empty output\n" % (cmd))
|
raise bb.fetch.FetchError("Fetch command %s gave empty output\n" % (cmd))
|
||||||
return output.split()[0]
|
return output.split()[0]
|
||||||
|
|
||||||
def latest_revision(self, url, ud, d):
|
|
||||||
"""
|
|
||||||
Look in the cache for the latest revision, if not present ask the SCM.
|
|
||||||
"""
|
|
||||||
persisted = bb.persist_data.persist(d)
|
|
||||||
revs = persisted['BB_URI_HEADREVS']
|
|
||||||
|
|
||||||
key = self.generate_revision_key(url, ud, d, branch=True)
|
|
||||||
rev = revs[key]
|
|
||||||
if rev is None:
|
|
||||||
# Compatibility with old key format, no branch included
|
|
||||||
oldkey = self.generate_revision_key(url, ud, d, branch=False)
|
|
||||||
rev = revs[oldkey]
|
|
||||||
if rev is not None:
|
|
||||||
del revs[oldkey]
|
|
||||||
else:
|
|
||||||
rev = self._latest_revision(url, ud, d)
|
|
||||||
revs[key] = rev
|
|
||||||
|
|
||||||
return str(rev)
|
|
||||||
|
|
||||||
def sortable_revision(self, url, ud, d):
|
|
||||||
"""
|
|
||||||
|
|
||||||
"""
|
|
||||||
pd = bb.persist_data.persist(d)
|
|
||||||
localcounts = pd['BB_URI_LOCALCOUNT']
|
|
||||||
key = self.generate_revision_key(url, ud, d, branch=True)
|
|
||||||
oldkey = self.generate_revision_key(url, ud, d, branch=False)
|
|
||||||
|
|
||||||
latest_rev = self._build_revision(url, ud, d)
|
|
||||||
last_rev = localcounts[key + '_rev']
|
|
||||||
if last_rev is None:
|
|
||||||
last_rev = localcounts[oldkey + '_rev']
|
|
||||||
if last_rev is not None:
|
|
||||||
del localcounts[oldkey + '_rev']
|
|
||||||
localcounts[key + '_rev'] = last_rev
|
|
||||||
|
|
||||||
uselocalcount = bb.data.getVar("BB_LOCALCOUNT_OVERRIDE", d, True) or False
|
|
||||||
count = None
|
|
||||||
if uselocalcount:
|
|
||||||
count = Fetch.localcount_internal_helper(ud, d)
|
|
||||||
if count is None:
|
|
||||||
count = localcounts[key + '_count']
|
|
||||||
if count is None:
|
|
||||||
count = localcounts[oldkey + '_count']
|
|
||||||
if count is not None:
|
|
||||||
del localcounts[oldkey + '_count']
|
|
||||||
localcounts[key + '_count'] = count
|
|
||||||
|
|
||||||
if last_rev == latest_rev:
|
|
||||||
return str(count + "+" + latest_rev)
|
|
||||||
|
|
||||||
buildindex_provided = hasattr(self, "_sortable_buildindex")
|
|
||||||
if buildindex_provided:
|
|
||||||
count = self._sortable_buildindex(url, ud, d, latest_rev)
|
|
||||||
if count is None:
|
|
||||||
count = "0"
|
|
||||||
elif uselocalcount or buildindex_provided:
|
|
||||||
count = str(count)
|
|
||||||
else:
|
|
||||||
count = str(int(count) + 1)
|
|
||||||
|
|
||||||
localcounts[key + '_rev'] = latest_rev
|
|
||||||
localcounts[key + '_count'] = count
|
|
||||||
|
|
||||||
return str(count + "+" + latest_rev)
|
|
||||||
|
|
||||||
def _build_revision(self, url, ud, d):
|
def _build_revision(self, url, ud, d):
|
||||||
return ud.tag
|
return ud.tag
|
||||||
|
|
||||||
@@ -323,7 +238,7 @@ class Git(Fetch):
|
|||||||
print("no repo")
|
print("no repo")
|
||||||
self.go(None, ud, d)
|
self.go(None, ud, d)
|
||||||
if not os.path.exists(ud.clonedir):
|
if not os.path.exists(ud.clonedir):
|
||||||
logger.error("GIT repository for %s doesn't exist in %s, cannot get sortable buildnumber, using old value", url, ud.clonedir)
|
bb.msg.error(bb.msg.domain.Fetcher, "GIT repository for %s doesn't exist in %s, cannot get sortable buildnumber, using old value" % (url, ud.clonedir))
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
@@ -335,5 +250,5 @@ class Git(Fetch):
|
|||||||
os.chdir(cwd)
|
os.chdir(cwd)
|
||||||
|
|
||||||
buildindex = "%s" % output.split()[0]
|
buildindex = "%s" % output.split()[0]
|
||||||
logger.debug(1, "GIT repository for %s in %s is returning %s revisions in rev-list before %s", url, ud.clonedir, buildindex, rev)
|
bb.msg.debug(1, bb.msg.domain.Fetcher, "GIT repository for %s in %s is returning %s revisions in rev-list before %s" % (url, ud.clonedir, buildindex, rev))
|
||||||
return buildindex
|
return buildindex
|
||||||
|
|||||||
@@ -26,27 +26,21 @@ BitBake 'Fetch' implementation for mercurial DRCS (hg).
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import logging
|
|
||||||
import bb
|
import bb
|
||||||
from bb import data
|
from bb import data
|
||||||
from bb.fetch import Fetch
|
from bb.fetch import Fetch
|
||||||
from bb.fetch import FetchError
|
from bb.fetch import FetchError
|
||||||
from bb.fetch import MissingParameterError
|
from bb.fetch import MissingParameterError
|
||||||
from bb.fetch import runfetchcmd
|
from bb.fetch import runfetchcmd
|
||||||
from bb.fetch import logger
|
|
||||||
|
|
||||||
class Hg(Fetch):
|
class Hg(Fetch):
|
||||||
"""Class to fetch from mercurial repositories"""
|
"""Class to fetch a from mercurial repositories"""
|
||||||
def supports(self, url, ud, d):
|
def supports(self, url, ud, d):
|
||||||
"""
|
"""
|
||||||
Check to see if a given url can be fetched with mercurial.
|
Check to see if a given url can be fetched with mercurial.
|
||||||
"""
|
"""
|
||||||
return ud.type in ['hg']
|
return ud.type in ['hg']
|
||||||
|
|
||||||
def forcefetch(self, url, ud, d):
|
|
||||||
revTag = ud.parm.get('rev', 'tip')
|
|
||||||
return revTag == "tip"
|
|
||||||
|
|
||||||
def localpath(self, url, ud, d):
|
def localpath(self, url, ud, d):
|
||||||
if not "module" in ud.parm:
|
if not "module" in ud.parm:
|
||||||
raise MissingParameterError("hg method needs a 'module' parameter")
|
raise MissingParameterError("hg method needs a 'module' parameter")
|
||||||
@@ -54,7 +48,10 @@ class Hg(Fetch):
|
|||||||
ud.module = ud.parm["module"]
|
ud.module = ud.parm["module"]
|
||||||
|
|
||||||
# Create paths to mercurial checkouts
|
# Create paths to mercurial checkouts
|
||||||
relpath = self._strip_leading_slashes(ud.path)
|
relpath = ud.path
|
||||||
|
if relpath.startswith('/'):
|
||||||
|
# Remove leading slash as os.path.join can't cope
|
||||||
|
relpath = relpath[1:]
|
||||||
ud.pkgdir = os.path.join(data.expand('${HGDIR}', d), ud.host, relpath)
|
ud.pkgdir = os.path.join(data.expand('${HGDIR}', d), ud.host, relpath)
|
||||||
ud.moddir = os.path.join(ud.pkgdir, ud.module)
|
ud.moddir = os.path.join(ud.pkgdir, ud.module)
|
||||||
|
|
||||||
@@ -81,7 +78,9 @@ class Hg(Fetch):
|
|||||||
|
|
||||||
basecmd = data.expand('${FETCHCMD_hg}', d)
|
basecmd = data.expand('${FETCHCMD_hg}', d)
|
||||||
|
|
||||||
proto = ud.parm.get('proto', 'http')
|
proto = "http"
|
||||||
|
if "proto" in ud.parm:
|
||||||
|
proto = ud.parm["proto"]
|
||||||
|
|
||||||
host = ud.host
|
host = ud.host
|
||||||
if proto == "file":
|
if proto == "file":
|
||||||
@@ -117,41 +116,34 @@ class Hg(Fetch):
|
|||||||
def go(self, loc, ud, d):
|
def go(self, loc, ud, d):
|
||||||
"""Fetch url"""
|
"""Fetch url"""
|
||||||
|
|
||||||
logger.debug(2, "Fetch: checking for module directory '" + ud.moddir + "'")
|
bb.msg.debug(2, bb.msg.domain.Fetcher, "Fetch: checking for module directory '" + ud.moddir + "'")
|
||||||
|
|
||||||
if os.access(os.path.join(ud.moddir, '.hg'), os.R_OK):
|
if os.access(os.path.join(ud.moddir, '.hg'), os.R_OK):
|
||||||
updatecmd = self._buildhgcommand(ud, d, "pull")
|
updatecmd = self._buildhgcommand(ud, d, "pull")
|
||||||
logger.info("Update " + loc)
|
bb.msg.note(1, bb.msg.domain.Fetcher, "Update " + loc)
|
||||||
# update sources there
|
# update sources there
|
||||||
os.chdir(ud.moddir)
|
os.chdir(ud.moddir)
|
||||||
logger.debug(1, "Running %s", updatecmd)
|
bb.msg.debug(1, bb.msg.domain.Fetcher, "Running %s" % updatecmd)
|
||||||
runfetchcmd(updatecmd, d)
|
runfetchcmd(updatecmd, d)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
fetchcmd = self._buildhgcommand(ud, d, "fetch")
|
fetchcmd = self._buildhgcommand(ud, d, "fetch")
|
||||||
logger.info("Fetch " + loc)
|
bb.msg.note(1, bb.msg.domain.Fetcher, "Fetch " + loc)
|
||||||
# check out sources there
|
# check out sources there
|
||||||
bb.utils.mkdirhier(ud.pkgdir)
|
bb.mkdirhier(ud.pkgdir)
|
||||||
os.chdir(ud.pkgdir)
|
os.chdir(ud.pkgdir)
|
||||||
logger.debug(1, "Running %s", fetchcmd)
|
bb.msg.debug(1, bb.msg.domain.Fetcher, "Running %s" % fetchcmd)
|
||||||
runfetchcmd(fetchcmd, d)
|
runfetchcmd(fetchcmd, d)
|
||||||
|
|
||||||
# Even when we clone (fetch), we still need to update as hg's clone
|
# Even when we clone (fetch), we still need to update as hg's clone
|
||||||
# won't checkout the specified revision if its on a branch
|
# won't checkout the specified revision if its on a branch
|
||||||
updatecmd = self._buildhgcommand(ud, d, "update")
|
updatecmd = self._buildhgcommand(ud, d, "update")
|
||||||
os.chdir(ud.moddir)
|
bb.msg.debug(1, bb.msg.domain.Fetcher, "Running %s" % updatecmd)
|
||||||
logger.debug(1, "Running %s", updatecmd)
|
|
||||||
runfetchcmd(updatecmd, d)
|
runfetchcmd(updatecmd, d)
|
||||||
|
|
||||||
scmdata = ud.parm.get("scmdata", "")
|
|
||||||
if scmdata == "keep":
|
|
||||||
tar_flags = ""
|
|
||||||
else:
|
|
||||||
tar_flags = "--exclude '.hg' --exclude '.hgrags'"
|
|
||||||
|
|
||||||
os.chdir(ud.pkgdir)
|
os.chdir(ud.pkgdir)
|
||||||
try:
|
try:
|
||||||
runfetchcmd("tar %s -czf %s %s" % (tar_flags, ud.localpath, ud.module), d)
|
runfetchcmd("tar -czf %s %s" % (ud.localpath, ud.module), d)
|
||||||
except:
|
except:
|
||||||
t, v, tb = sys.exc_info()
|
t, v, tb = sys.exc_info()
|
||||||
try:
|
try:
|
||||||
@@ -160,7 +152,7 @@ class Hg(Fetch):
|
|||||||
pass
|
pass
|
||||||
raise t, v, tb
|
raise t, v, tb
|
||||||
|
|
||||||
def supports_srcrev(self):
|
def suppports_srcrev(self):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def _latest_revision(self, url, ud, d):
|
def _latest_revision(self, url, ud, d):
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ class Local(Fetch):
|
|||||||
Check the status of the url
|
Check the status of the url
|
||||||
"""
|
"""
|
||||||
if urldata.localpath.find("*") != -1:
|
if urldata.localpath.find("*") != -1:
|
||||||
logger.info("URL %s looks like a glob and was therefore not checked.", url)
|
bb.msg.note(1, bb.msg.domain.Fetcher, "URL %s looks like a glob and was therefore not checked." % url)
|
||||||
return True
|
return True
|
||||||
if os.path.exists(urldata.localpath):
|
if os.path.exists(urldata.localpath):
|
||||||
return True
|
return True
|
||||||
|
|||||||
@@ -8,10 +8,8 @@ Based on the svn "Fetch" implementation.
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import logging
|
|
||||||
import bb
|
import bb
|
||||||
from bb import data
|
from bb import data
|
||||||
from bb import utils
|
|
||||||
from bb.fetch import Fetch
|
from bb.fetch import Fetch
|
||||||
from bb.fetch import FetchError
|
from bb.fetch import FetchError
|
||||||
from bb.fetch import MissingParameterError
|
from bb.fetch import MissingParameterError
|
||||||
@@ -34,7 +32,10 @@ class Osc(Fetch):
|
|||||||
ud.module = ud.parm["module"]
|
ud.module = ud.parm["module"]
|
||||||
|
|
||||||
# Create paths to osc checkouts
|
# Create paths to osc checkouts
|
||||||
relpath = self._strip_leading_slashes(ud.path)
|
relpath = ud.path
|
||||||
|
if relpath.startswith('/'):
|
||||||
|
# Remove leading slash as os.path.join can't cope
|
||||||
|
relpath = relpath[1:]
|
||||||
ud.pkgdir = os.path.join(data.expand('${OSCDIR}', d), ud.host)
|
ud.pkgdir = os.path.join(data.expand('${OSCDIR}', d), ud.host)
|
||||||
ud.moddir = os.path.join(ud.pkgdir, relpath, ud.module)
|
ud.moddir = os.path.join(ud.pkgdir, relpath, ud.module)
|
||||||
|
|
||||||
@@ -60,7 +61,9 @@ class Osc(Fetch):
|
|||||||
|
|
||||||
basecmd = data.expand('${FETCHCMD_osc}', d)
|
basecmd = data.expand('${FETCHCMD_osc}', d)
|
||||||
|
|
||||||
proto = ud.parm.get('proto', 'ocs')
|
proto = "ocs"
|
||||||
|
if "proto" in ud.parm:
|
||||||
|
proto = ud.parm["proto"]
|
||||||
|
|
||||||
options = []
|
options = []
|
||||||
|
|
||||||
@@ -69,7 +72,10 @@ class Osc(Fetch):
|
|||||||
if ud.revision:
|
if ud.revision:
|
||||||
options.append("-r %s" % ud.revision)
|
options.append("-r %s" % ud.revision)
|
||||||
|
|
||||||
coroot = self._strip_leading_slashes(ud.path)
|
coroot = ud.path
|
||||||
|
if coroot.startswith('/'):
|
||||||
|
# Remove leading slash as os.path.join can't cope
|
||||||
|
coroot= coroot[1:]
|
||||||
|
|
||||||
if command is "fetch":
|
if command is "fetch":
|
||||||
osccmd = "%s %s co %s/%s %s" % (basecmd, config, coroot, ud.module, " ".join(options))
|
osccmd = "%s %s co %s/%s %s" % (basecmd, config, coroot, ud.module, " ".join(options))
|
||||||
@@ -85,22 +91,22 @@ class Osc(Fetch):
|
|||||||
Fetch url
|
Fetch url
|
||||||
"""
|
"""
|
||||||
|
|
||||||
logger.debug(2, "Fetch: checking for module directory '" + ud.moddir + "'")
|
bb.msg.debug(2, bb.msg.domain.Fetcher, "Fetch: checking for module directory '" + ud.moddir + "'")
|
||||||
|
|
||||||
if os.access(os.path.join(data.expand('${OSCDIR}', d), ud.path, ud.module), os.R_OK):
|
if os.access(os.path.join(data.expand('${OSCDIR}', d), ud.path, ud.module), os.R_OK):
|
||||||
oscupdatecmd = self._buildosccommand(ud, d, "update")
|
oscupdatecmd = self._buildosccommand(ud, d, "update")
|
||||||
logger.info("Update "+ loc)
|
bb.msg.note(1, bb.msg.domain.Fetcher, "Update "+ loc)
|
||||||
# update sources there
|
# update sources there
|
||||||
os.chdir(ud.moddir)
|
os.chdir(ud.moddir)
|
||||||
logger.debug(1, "Running %s", oscupdatecmd)
|
bb.msg.debug(1, bb.msg.domain.Fetcher, "Running %s" % oscupdatecmd)
|
||||||
runfetchcmd(oscupdatecmd, d)
|
runfetchcmd(oscupdatecmd, d)
|
||||||
else:
|
else:
|
||||||
oscfetchcmd = self._buildosccommand(ud, d, "fetch")
|
oscfetchcmd = self._buildosccommand(ud, d, "fetch")
|
||||||
logger.info("Fetch " + loc)
|
bb.msg.note(1, bb.msg.domain.Fetcher, "Fetch " + loc)
|
||||||
# check out sources there
|
# check out sources there
|
||||||
bb.utils.mkdirhier(ud.pkgdir)
|
bb.mkdirhier(ud.pkgdir)
|
||||||
os.chdir(ud.pkgdir)
|
os.chdir(ud.pkgdir)
|
||||||
logger.debug(1, "Running %s", oscfetchcmd)
|
bb.msg.debug(1, bb.msg.domain.Fetcher, "Running %s" % oscfetchcmd)
|
||||||
runfetchcmd(oscfetchcmd, d)
|
runfetchcmd(oscfetchcmd, d)
|
||||||
|
|
||||||
os.chdir(os.path.join(ud.pkgdir + ud.path))
|
os.chdir(os.path.join(ud.pkgdir + ud.path))
|
||||||
@@ -123,8 +129,9 @@ class Osc(Fetch):
|
|||||||
Generate a .oscrc to be used for this run.
|
Generate a .oscrc to be used for this run.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
config_path = os.path.join(data.expand('${OSCDIR}', d), "oscrc")
|
config_path = "%s/oscrc" % data.expand('${OSCDIR}', d)
|
||||||
bb.utils.remove(config_path)
|
if (os.path.exists(config_path)):
|
||||||
|
os.remove(config_path)
|
||||||
|
|
||||||
f = open(config_path, 'w')
|
f = open(config_path, 'w')
|
||||||
f.write("[general]\n")
|
f.write("[general]\n")
|
||||||
|
|||||||
@@ -27,12 +27,10 @@ BitBake build tools.
|
|||||||
|
|
||||||
from future_builtins import zip
|
from future_builtins import zip
|
||||||
import os
|
import os
|
||||||
import logging
|
|
||||||
import bb
|
import bb
|
||||||
from bb import data
|
from bb import data
|
||||||
from bb.fetch import Fetch
|
from bb.fetch import Fetch
|
||||||
from bb.fetch import FetchError
|
from bb.fetch import FetchError
|
||||||
from bb.fetch import logger
|
|
||||||
|
|
||||||
class Perforce(Fetch):
|
class Perforce(Fetch):
|
||||||
def supports(self, url, ud, d):
|
def supports(self, url, ud, d):
|
||||||
@@ -88,10 +86,10 @@ class Perforce(Fetch):
|
|||||||
depot += "@%s" % (p4date)
|
depot += "@%s" % (p4date)
|
||||||
|
|
||||||
p4cmd = data.getVar('FETCHCOMMAND_p4', d, 1)
|
p4cmd = data.getVar('FETCHCOMMAND_p4', d, 1)
|
||||||
logger.debug(1, "Running %s%s changes -m 1 %s", p4cmd, p4opt, depot)
|
bb.msg.debug(1, bb.msg.domain.Fetcher, "Running %s%s changes -m 1 %s" % (p4cmd, p4opt, depot))
|
||||||
p4file = os.popen("%s%s changes -m 1 %s" % (p4cmd, p4opt, depot))
|
p4file = os.popen("%s%s changes -m 1 %s" % (p4cmd, p4opt, depot))
|
||||||
cset = p4file.readline().strip()
|
cset = p4file.readline().strip()
|
||||||
logger.debug(1, "READ %s", cset)
|
bb.msg.debug(1, bb.msg.domain.Fetcher, "READ %s" % (cset))
|
||||||
if not cset:
|
if not cset:
|
||||||
return -1
|
return -1
|
||||||
|
|
||||||
@@ -113,7 +111,8 @@ class Perforce(Fetch):
|
|||||||
if which != -1:
|
if which != -1:
|
||||||
base = path[:which]
|
base = path[:which]
|
||||||
|
|
||||||
base = self._strip_leading_slashes(base)
|
if base[0] == "/":
|
||||||
|
base = base[1:]
|
||||||
|
|
||||||
cset = Perforce.getcset(d, path, host, user, pswd, parm)
|
cset = Perforce.getcset(d, path, host, user, pswd, parm)
|
||||||
|
|
||||||
@@ -133,7 +132,10 @@ class Perforce(Fetch):
|
|||||||
else:
|
else:
|
||||||
path = depot
|
path = depot
|
||||||
|
|
||||||
module = parm.get('module', os.path.basename(path))
|
if "module" in parm:
|
||||||
|
module = parm["module"]
|
||||||
|
else:
|
||||||
|
module = os.path.basename(path)
|
||||||
|
|
||||||
localdata = data.createCopy(d)
|
localdata = data.createCopy(d)
|
||||||
data.setVar('OVERRIDES', "p4:%s" % data.getVar('OVERRIDES', localdata), localdata)
|
data.setVar('OVERRIDES', "p4:%s" % data.getVar('OVERRIDES', localdata), localdata)
|
||||||
@@ -153,13 +155,13 @@ class Perforce(Fetch):
|
|||||||
p4cmd = data.getVar('FETCHCOMMAND', localdata, 1)
|
p4cmd = data.getVar('FETCHCOMMAND', localdata, 1)
|
||||||
|
|
||||||
# create temp directory
|
# create temp directory
|
||||||
logger.debug(2, "Fetch: creating temporary directory")
|
bb.msg.debug(2, bb.msg.domain.Fetcher, "Fetch: creating temporary directory")
|
||||||
bb.utils.mkdirhier(data.expand('${WORKDIR}', localdata))
|
bb.mkdirhier(data.expand('${WORKDIR}', localdata))
|
||||||
data.setVar('TMPBASE', data.expand('${WORKDIR}/oep4.XXXXXX', localdata), localdata)
|
data.setVar('TMPBASE', data.expand('${WORKDIR}/oep4.XXXXXX', localdata), localdata)
|
||||||
tmppipe = os.popen(data.getVar('MKTEMPDIRCMD', localdata, 1) or "false")
|
tmppipe = os.popen(data.getVar('MKTEMPDIRCMD', localdata, 1) or "false")
|
||||||
tmpfile = tmppipe.readline().strip()
|
tmpfile = tmppipe.readline().strip()
|
||||||
if not tmpfile:
|
if not tmpfile:
|
||||||
logger.error("Fetch: unable to create temporary directory.. make sure 'mktemp' is in the PATH.")
|
bb.msg.error(bb.msg.domain.Fetcher, "Fetch: unable to create temporary directory.. make sure 'mktemp' is in the PATH.")
|
||||||
raise FetchError(module)
|
raise FetchError(module)
|
||||||
|
|
||||||
if "label" in parm:
|
if "label" in parm:
|
||||||
@@ -169,12 +171,12 @@ class Perforce(Fetch):
|
|||||||
depot = "%s@%s" % (depot, cset)
|
depot = "%s@%s" % (depot, cset)
|
||||||
|
|
||||||
os.chdir(tmpfile)
|
os.chdir(tmpfile)
|
||||||
logger.info("Fetch " + loc)
|
bb.msg.note(1, bb.msg.domain.Fetcher, "Fetch " + loc)
|
||||||
logger.info("%s%s files %s", p4cmd, p4opt, depot)
|
bb.msg.note(1, bb.msg.domain.Fetcher, "%s%s files %s" % (p4cmd, p4opt, depot))
|
||||||
p4file = os.popen("%s%s files %s" % (p4cmd, p4opt, depot))
|
p4file = os.popen("%s%s files %s" % (p4cmd, p4opt, depot))
|
||||||
|
|
||||||
if not p4file:
|
if not p4file:
|
||||||
logger.error("Fetch: unable to get the P4 files from %s", depot)
|
bb.msg.error(bb.msg.domain.Fetcher, "Fetch: unable to get the P4 files from %s" % (depot))
|
||||||
raise FetchError(module)
|
raise FetchError(module)
|
||||||
|
|
||||||
count = 0
|
count = 0
|
||||||
@@ -192,7 +194,7 @@ class Perforce(Fetch):
|
|||||||
count = count + 1
|
count = count + 1
|
||||||
|
|
||||||
if count == 0:
|
if count == 0:
|
||||||
logger.error("Fetch: No files gathered from the P4 fetch")
|
bb.msg.error(bb.msg.domain.Fetcher, "Fetch: No files gathered from the P4 fetch")
|
||||||
raise FetchError(module)
|
raise FetchError(module)
|
||||||
|
|
||||||
myret = os.system("tar -czf %s %s" % (ud.localpath, module))
|
myret = os.system("tar -czf %s %s" % (ud.localpath, module))
|
||||||
@@ -203,4 +205,4 @@ class Perforce(Fetch):
|
|||||||
pass
|
pass
|
||||||
raise FetchError(module)
|
raise FetchError(module)
|
||||||
# cleanup
|
# cleanup
|
||||||
bb.utils.prunedir(tmpfile)
|
os.system('rm -rf %s' % tmpfile)
|
||||||
|
|||||||
@@ -45,11 +45,24 @@ class Repo(Fetch):
|
|||||||
"master".
|
"master".
|
||||||
"""
|
"""
|
||||||
|
|
||||||
ud.proto = ud.parm.get('protocol', 'git')
|
if "protocol" in ud.parm:
|
||||||
ud.branch = ud.parm.get('branch', 'master')
|
ud.proto = ud.parm["protocol"]
|
||||||
ud.manifest = ud.parm.get('manifest', 'default.xml')
|
else:
|
||||||
if not ud.manifest.endswith('.xml'):
|
ud.proto = "git"
|
||||||
ud.manifest += '.xml'
|
|
||||||
|
if "branch" in ud.parm:
|
||||||
|
ud.branch = ud.parm["branch"]
|
||||||
|
else:
|
||||||
|
ud.branch = "master"
|
||||||
|
|
||||||
|
if "manifest" in ud.parm:
|
||||||
|
manifest = ud.parm["manifest"]
|
||||||
|
if manifest.endswith(".xml"):
|
||||||
|
ud.manifest = manifest
|
||||||
|
else:
|
||||||
|
ud.manifest = manifest + ".xml"
|
||||||
|
else:
|
||||||
|
ud.manifest = "default.xml"
|
||||||
|
|
||||||
ud.localfile = data.expand("repo_%s%s_%s_%s.tar.gz" % (ud.host, ud.path.replace("/", "."), ud.manifest, ud.branch), d)
|
ud.localfile = data.expand("repo_%s%s_%s_%s.tar.gz" % (ud.host, ud.path.replace("/", "."), ud.manifest, ud.branch), d)
|
||||||
|
|
||||||
@@ -59,7 +72,7 @@ class Repo(Fetch):
|
|||||||
"""Fetch url"""
|
"""Fetch url"""
|
||||||
|
|
||||||
if os.access(os.path.join(data.getVar("DL_DIR", d, True), ud.localfile), os.R_OK):
|
if os.access(os.path.join(data.getVar("DL_DIR", d, True), ud.localfile), os.R_OK):
|
||||||
logger.debug(1, "%s already exists (or was stashed). Skipping repo init / sync.", ud.localpath)
|
bb.msg.debug(1, bb.msg.domain.Fetcher, "%s already exists (or was stashed). Skipping repo init / sync." % ud.localpath)
|
||||||
return
|
return
|
||||||
|
|
||||||
gitsrcname = "%s%s" % (ud.host, ud.path.replace("/", "."))
|
gitsrcname = "%s%s" % (ud.host, ud.path.replace("/", "."))
|
||||||
@@ -71,7 +84,7 @@ class Repo(Fetch):
|
|||||||
else:
|
else:
|
||||||
username = ""
|
username = ""
|
||||||
|
|
||||||
bb.utils.mkdirhier(os.path.join(codir, "repo"))
|
bb.mkdirhier(os.path.join(codir, "repo"))
|
||||||
os.chdir(os.path.join(codir, "repo"))
|
os.chdir(os.path.join(codir, "repo"))
|
||||||
if not os.path.exists(os.path.join(codir, "repo", ".repo")):
|
if not os.path.exists(os.path.join(codir, "repo", ".repo")):
|
||||||
runfetchcmd("repo init -m %s -b %s -u %s://%s%s%s" % (ud.manifest, ud.branch, ud.proto, username, ud.host, ud.path), d)
|
runfetchcmd("repo init -m %s -b %s -u %s://%s%s%s" % (ud.manifest, ud.branch, ud.proto, username, ud.host, ud.path), d)
|
||||||
@@ -79,16 +92,10 @@ class Repo(Fetch):
|
|||||||
runfetchcmd("repo sync", d)
|
runfetchcmd("repo sync", d)
|
||||||
os.chdir(codir)
|
os.chdir(codir)
|
||||||
|
|
||||||
scmdata = ud.parm.get("scmdata", "")
|
|
||||||
if scmdata == "keep":
|
|
||||||
tar_flags = ""
|
|
||||||
else:
|
|
||||||
tar_flags = "--exclude '.repo' --exclude '.git'"
|
|
||||||
|
|
||||||
# Create a cache
|
# Create a cache
|
||||||
runfetchcmd("tar %s -czf %s %s" % (tar_flags, ud.localpath, os.path.join(".", "*") ), d)
|
runfetchcmd("tar --exclude=.repo --exclude=.git -czf %s %s" % (ud.localpath, os.path.join(".", "*") ), d)
|
||||||
|
|
||||||
def supports_srcrev(self):
|
def suppports_srcrev(self):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def _build_revision(self, url, ud, d):
|
def _build_revision(self, url, ud, d):
|
||||||
|
|||||||
@@ -26,13 +26,11 @@ This implementation is for svk. It is based on the svn implementation
|
|||||||
# Based on functions from the base bb module, Copyright 2003 Holger Schurig
|
# Based on functions from the base bb module, Copyright 2003 Holger Schurig
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import logging
|
|
||||||
import bb
|
import bb
|
||||||
from bb import data
|
from bb import data
|
||||||
from bb.fetch import Fetch
|
from bb.fetch import Fetch
|
||||||
from bb.fetch import FetchError
|
from bb.fetch import FetchError
|
||||||
from bb.fetch import MissingParameterError
|
from bb.fetch import MissingParameterError
|
||||||
from bb.fetch import logger
|
|
||||||
|
|
||||||
class Svk(Fetch):
|
class Svk(Fetch):
|
||||||
"""Class to fetch a module or modules from svk repositories"""
|
"""Class to fetch a module or modules from svk repositories"""
|
||||||
@@ -48,14 +46,18 @@ class Svk(Fetch):
|
|||||||
else:
|
else:
|
||||||
ud.module = ud.parm["module"]
|
ud.module = ud.parm["module"]
|
||||||
|
|
||||||
ud.revision = ud.parm.get('rev', "")
|
ud.revision = ""
|
||||||
|
if 'rev' in ud.parm:
|
||||||
|
ud.revision = ud.parm['rev']
|
||||||
|
|
||||||
ud.localfile = data.expand('%s_%s_%s_%s_%s.tar.gz' % (ud.module.replace('/', '.'), ud.host, ud.path.replace('/', '.'), ud.revision, ud.date), d)
|
ud.localfile = data.expand('%s_%s_%s_%s_%s.tar.gz' % (ud.module.replace('/', '.'), ud.host, ud.path.replace('/', '.'), ud.revision, ud.date), d)
|
||||||
|
|
||||||
return os.path.join(data.getVar("DL_DIR", d, True), ud.localfile)
|
return os.path.join(data.getVar("DL_DIR", d, True), ud.localfile)
|
||||||
|
|
||||||
def forcefetch(self, url, ud, d):
|
def forcefetch(self, url, ud, d):
|
||||||
return ud.date == "now"
|
if (ud.date == "now"):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
def go(self, loc, ud, d):
|
def go(self, loc, ud, d):
|
||||||
"""Fetch urls"""
|
"""Fetch urls"""
|
||||||
@@ -70,19 +72,19 @@ class Svk(Fetch):
|
|||||||
# create temp directory
|
# create temp directory
|
||||||
localdata = data.createCopy(d)
|
localdata = data.createCopy(d)
|
||||||
data.update_data(localdata)
|
data.update_data(localdata)
|
||||||
logger.debug(2, "Fetch: creating temporary directory")
|
bb.msg.debug(2, bb.msg.domain.Fetcher, "Fetch: creating temporary directory")
|
||||||
bb.utils.mkdirhier(data.expand('${WORKDIR}', localdata))
|
bb.mkdirhier(data.expand('${WORKDIR}', localdata))
|
||||||
data.setVar('TMPBASE', data.expand('${WORKDIR}/oesvk.XXXXXX', localdata), localdata)
|
data.setVar('TMPBASE', data.expand('${WORKDIR}/oesvk.XXXXXX', localdata), localdata)
|
||||||
tmppipe = os.popen(data.getVar('MKTEMPDIRCMD', localdata, 1) or "false")
|
tmppipe = os.popen(data.getVar('MKTEMPDIRCMD', localdata, 1) or "false")
|
||||||
tmpfile = tmppipe.readline().strip()
|
tmpfile = tmppipe.readline().strip()
|
||||||
if not tmpfile:
|
if not tmpfile:
|
||||||
logger.error("Fetch: unable to create temporary directory.. make sure 'mktemp' is in the PATH.")
|
bb.msg.error(bb.msg.domain.Fetcher, "Fetch: unable to create temporary directory.. make sure 'mktemp' is in the PATH.")
|
||||||
raise FetchError(ud.module)
|
raise FetchError(ud.module)
|
||||||
|
|
||||||
# check out sources there
|
# check out sources there
|
||||||
os.chdir(tmpfile)
|
os.chdir(tmpfile)
|
||||||
logger.info("Fetch " + loc)
|
bb.msg.note(1, bb.msg.domain.Fetcher, "Fetch " + loc)
|
||||||
logger.debug(1, "Running %s", svkcmd)
|
bb.msg.debug(1, bb.msg.domain.Fetcher, "Running %s" % svkcmd)
|
||||||
myret = os.system(svkcmd)
|
myret = os.system(svkcmd)
|
||||||
if myret != 0:
|
if myret != 0:
|
||||||
try:
|
try:
|
||||||
@@ -101,4 +103,4 @@ class Svk(Fetch):
|
|||||||
pass
|
pass
|
||||||
raise FetchError(ud.module)
|
raise FetchError(ud.module)
|
||||||
# cleanup
|
# cleanup
|
||||||
bb.utils.prunedir(tmpfile)
|
os.system('rm -rf %s' % tmpfile)
|
||||||
|
|||||||
@@ -25,14 +25,12 @@ BitBake 'Fetch' implementation for svn.
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import logging
|
|
||||||
import bb
|
import bb
|
||||||
from bb import data
|
from bb import data
|
||||||
from bb.fetch import Fetch
|
from bb.fetch import Fetch
|
||||||
from bb.fetch import FetchError
|
from bb.fetch import FetchError
|
||||||
from bb.fetch import MissingParameterError
|
from bb.fetch import MissingParameterError
|
||||||
from bb.fetch import runfetchcmd
|
from bb.fetch import runfetchcmd
|
||||||
from bb.fetch import logger
|
|
||||||
|
|
||||||
class Svn(Fetch):
|
class Svn(Fetch):
|
||||||
"""Class to fetch a module or modules from svn repositories"""
|
"""Class to fetch a module or modules from svn repositories"""
|
||||||
@@ -49,7 +47,10 @@ class Svn(Fetch):
|
|||||||
ud.module = ud.parm["module"]
|
ud.module = ud.parm["module"]
|
||||||
|
|
||||||
# Create paths to svn checkouts
|
# Create paths to svn checkouts
|
||||||
relpath = self._strip_leading_slashes(ud.path)
|
relpath = ud.path
|
||||||
|
if relpath.startswith('/'):
|
||||||
|
# Remove leading slash as os.path.join can't cope
|
||||||
|
relpath = relpath[1:]
|
||||||
ud.pkgdir = os.path.join(data.expand('${SVNDIR}', d), ud.host, relpath)
|
ud.pkgdir = os.path.join(data.expand('${SVNDIR}', d), ud.host, relpath)
|
||||||
ud.moddir = os.path.join(ud.pkgdir, ud.module)
|
ud.moddir = os.path.join(ud.pkgdir, ud.module)
|
||||||
|
|
||||||
@@ -91,7 +92,9 @@ class Svn(Fetch):
|
|||||||
|
|
||||||
basecmd = data.expand('${FETCHCMD_svn}', d)
|
basecmd = data.expand('${FETCHCMD_svn}', d)
|
||||||
|
|
||||||
proto = ud.parm.get('proto', 'svn')
|
proto = "svn"
|
||||||
|
if "proto" in ud.parm:
|
||||||
|
proto = ud.parm["proto"]
|
||||||
|
|
||||||
svn_rsh = None
|
svn_rsh = None
|
||||||
if proto == "svn+ssh" and "rsh" in ud.parm:
|
if proto == "svn+ssh" and "rsh" in ud.parm:
|
||||||
@@ -133,34 +136,28 @@ class Svn(Fetch):
|
|||||||
def go(self, loc, ud, d):
|
def go(self, loc, ud, d):
|
||||||
"""Fetch url"""
|
"""Fetch url"""
|
||||||
|
|
||||||
logger.debug(2, "Fetch: checking for module directory '" + ud.moddir + "'")
|
bb.msg.debug(2, bb.msg.domain.Fetcher, "Fetch: checking for module directory '" + ud.moddir + "'")
|
||||||
|
|
||||||
if os.access(os.path.join(ud.moddir, '.svn'), os.R_OK):
|
if os.access(os.path.join(ud.moddir, '.svn'), os.R_OK):
|
||||||
svnupdatecmd = self._buildsvncommand(ud, d, "update")
|
svnupdatecmd = self._buildsvncommand(ud, d, "update")
|
||||||
logger.info("Update " + loc)
|
bb.msg.note(1, bb.msg.domain.Fetcher, "Update " + loc)
|
||||||
# update sources there
|
# update sources there
|
||||||
os.chdir(ud.moddir)
|
os.chdir(ud.moddir)
|
||||||
logger.debug(1, "Running %s", svnupdatecmd)
|
bb.msg.debug(1, bb.msg.domain.Fetcher, "Running %s" % svnupdatecmd)
|
||||||
runfetchcmd(svnupdatecmd, d)
|
runfetchcmd(svnupdatecmd, d)
|
||||||
else:
|
else:
|
||||||
svnfetchcmd = self._buildsvncommand(ud, d, "fetch")
|
svnfetchcmd = self._buildsvncommand(ud, d, "fetch")
|
||||||
logger.info("Fetch " + loc)
|
bb.msg.note(1, bb.msg.domain.Fetcher, "Fetch " + loc)
|
||||||
# check out sources there
|
# check out sources there
|
||||||
bb.utils.mkdirhier(ud.pkgdir)
|
bb.mkdirhier(ud.pkgdir)
|
||||||
os.chdir(ud.pkgdir)
|
os.chdir(ud.pkgdir)
|
||||||
logger.debug(1, "Running %s", svnfetchcmd)
|
bb.msg.debug(1, bb.msg.domain.Fetcher, "Running %s" % svnfetchcmd)
|
||||||
runfetchcmd(svnfetchcmd, d)
|
runfetchcmd(svnfetchcmd, d)
|
||||||
|
|
||||||
scmdata = ud.parm.get("scmdata", "")
|
|
||||||
if scmdata == "keep":
|
|
||||||
tar_flags = ""
|
|
||||||
else:
|
|
||||||
tar_flags = "--exclude '.svn'"
|
|
||||||
|
|
||||||
os.chdir(ud.pkgdir)
|
os.chdir(ud.pkgdir)
|
||||||
# tar them up to a defined filename
|
# tar them up to a defined filename
|
||||||
try:
|
try:
|
||||||
runfetchcmd("tar %s -czf %s %s" % (tar_flags, ud.localpath, ud.module), d)
|
runfetchcmd("tar -czf %s %s" % (ud.localpath, ud.module), d)
|
||||||
except:
|
except:
|
||||||
t, v, tb = sys.exc_info()
|
t, v, tb = sys.exc_info()
|
||||||
try:
|
try:
|
||||||
@@ -169,7 +166,7 @@ class Svn(Fetch):
|
|||||||
pass
|
pass
|
||||||
raise t, v, tb
|
raise t, v, tb
|
||||||
|
|
||||||
def supports_srcrev(self):
|
def suppports_srcrev(self):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def _revision_key(self, url, ud, d):
|
def _revision_key(self, url, ud, d):
|
||||||
@@ -182,7 +179,7 @@ class Svn(Fetch):
|
|||||||
"""
|
"""
|
||||||
Return the latest upstream revision number
|
Return the latest upstream revision number
|
||||||
"""
|
"""
|
||||||
logger.debug(2, "SVN fetcher hitting network for %s", url)
|
bb.msg.debug(2, bb.msg.domain.Fetcher, "SVN fetcher hitting network for %s" % url)
|
||||||
|
|
||||||
output = runfetchcmd("LANG=C LC_ALL=C " + self._buildsvncommand(ud, d, "info"), d, True)
|
output = runfetchcmd("LANG=C LC_ALL=C " + self._buildsvncommand(ud, d, "info"), d, True)
|
||||||
|
|
||||||
|
|||||||
@@ -26,11 +26,12 @@ BitBake build tools.
|
|||||||
# Based on functions from the base bb module, Copyright 2003 Holger Schurig
|
# Based on functions from the base bb module, Copyright 2003 Holger Schurig
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import logging
|
|
||||||
import bb
|
import bb
|
||||||
import urllib
|
|
||||||
from bb import data
|
from bb import data
|
||||||
from bb.fetch import Fetch, FetchError, encodeurl, decodeurl, logger, runfetchcmd
|
from bb.fetch import Fetch
|
||||||
|
from bb.fetch import FetchError
|
||||||
|
from bb.fetch import encodeurl, decodeurl
|
||||||
|
from bb.fetch import runfetchcmd
|
||||||
|
|
||||||
class Wget(Fetch):
|
class Wget(Fetch):
|
||||||
"""Class to fetch urls via 'wget'"""
|
"""Class to fetch urls via 'wget'"""
|
||||||
@@ -44,7 +45,7 @@ class Wget(Fetch):
|
|||||||
|
|
||||||
url = encodeurl([ud.type, ud.host, ud.path, ud.user, ud.pswd, {}])
|
url = encodeurl([ud.type, ud.host, ud.path, ud.user, ud.pswd, {}])
|
||||||
ud.basename = os.path.basename(ud.path)
|
ud.basename = os.path.basename(ud.path)
|
||||||
ud.localfile = data.expand(urllib.unquote(ud.basename), d)
|
ud.localfile = data.expand(os.path.basename(url), d)
|
||||||
|
|
||||||
return os.path.join(data.getVar("DL_DIR", d, True), ud.localfile)
|
return os.path.join(data.getVar("DL_DIR", d, True), ud.localfile)
|
||||||
|
|
||||||
@@ -67,14 +68,15 @@ class Wget(Fetch):
|
|||||||
|
|
||||||
fetchcmd = fetchcmd.replace("${URI}", uri.split(";")[0])
|
fetchcmd = fetchcmd.replace("${URI}", uri.split(";")[0])
|
||||||
fetchcmd = fetchcmd.replace("${FILE}", ud.basename)
|
fetchcmd = fetchcmd.replace("${FILE}", ud.basename)
|
||||||
logger.info("fetch " + uri)
|
|
||||||
logger.debug(2, "executing " + fetchcmd)
|
bb.msg.note(1, bb.msg.domain.Fetcher, "fetch " + uri)
|
||||||
|
bb.msg.debug(2, bb.msg.domain.Fetcher, "executing " + fetchcmd)
|
||||||
runfetchcmd(fetchcmd, d)
|
runfetchcmd(fetchcmd, d)
|
||||||
|
|
||||||
# Sanity check since wget can pretend it succeed when it didn't
|
# Sanity check since wget can pretend it succeed when it didn't
|
||||||
# Also, this used to happen if sourceforge sent us to the mirror page
|
# Also, this used to happen if sourceforge sent us to the mirror page
|
||||||
if not os.path.exists(ud.localpath) and not checkonly:
|
if not os.path.exists(ud.localpath) and not checkonly:
|
||||||
logger.debug(2, "The fetch command for %s returned success but %s doesn't exist?...", uri, ud.localpath)
|
bb.msg.debug(2, bb.msg.domain.Fetcher, "The fetch command for %s returned success but %s doesn't exist?..." % (uri, ud.localpath))
|
||||||
return False
|
return False
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,141 +0,0 @@
|
|||||||
"""
|
|
||||||
BitBake 'Fetch' implementation for bzr.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
# Copyright (C) 2007 Ross Burton
|
|
||||||
# Copyright (C) 2007 Richard Purdie
|
|
||||||
#
|
|
||||||
# Classes for obtaining upstream sources for the
|
|
||||||
# BitBake build tools.
|
|
||||||
# Copyright (C) 2003, 2004 Chris Larson
|
|
||||||
#
|
|
||||||
# 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 sys
|
|
||||||
import logging
|
|
||||||
import bb
|
|
||||||
from bb import data
|
|
||||||
from bb.fetch2 import FetchMethod
|
|
||||||
from bb.fetch2 import FetchError
|
|
||||||
from bb.fetch2 import runfetchcmd
|
|
||||||
from bb.fetch2 import logger
|
|
||||||
|
|
||||||
class Bzr(FetchMethod):
|
|
||||||
def supports(self, url, ud, d):
|
|
||||||
return ud.type in ['bzr']
|
|
||||||
|
|
||||||
def urldata_init(self, ud, d):
|
|
||||||
"""
|
|
||||||
init bzr specific variable within url data
|
|
||||||
"""
|
|
||||||
# Create paths to bzr checkouts
|
|
||||||
relpath = self._strip_leading_slashes(ud.path)
|
|
||||||
ud.pkgdir = os.path.join(data.expand('${BZRDIR}', d), ud.host, relpath)
|
|
||||||
|
|
||||||
if not ud.revision:
|
|
||||||
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)
|
|
||||||
|
|
||||||
def _buildbzrcommand(self, ud, d, command):
|
|
||||||
"""
|
|
||||||
Build up an bzr commandline based on ud
|
|
||||||
command is "fetch", "update", "revno"
|
|
||||||
"""
|
|
||||||
|
|
||||||
basecmd = data.expand('${FETCHCMD_bzr}', d)
|
|
||||||
|
|
||||||
proto = ud.parm.get('proto', 'http')
|
|
||||||
|
|
||||||
bzrroot = ud.host + ud.path
|
|
||||||
|
|
||||||
options = []
|
|
||||||
|
|
||||||
if command is "revno":
|
|
||||||
bzrcmd = "%s revno %s %s://%s" % (basecmd, " ".join(options), proto, bzrroot)
|
|
||||||
else:
|
|
||||||
if ud.revision:
|
|
||||||
options.append("-r %s" % ud.revision)
|
|
||||||
|
|
||||||
if command is "fetch":
|
|
||||||
bzrcmd = "%s co %s %s://%s" % (basecmd, " ".join(options), proto, bzrroot)
|
|
||||||
elif command is "update":
|
|
||||||
bzrcmd = "%s pull %s --overwrite" % (basecmd, " ".join(options))
|
|
||||||
else:
|
|
||||||
raise FetchError("Invalid bzr command %s" % command, ud.url)
|
|
||||||
|
|
||||||
return bzrcmd
|
|
||||||
|
|
||||||
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", 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)
|
|
||||||
else:
|
|
||||||
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", loc)
|
|
||||||
bb.utils.mkdirhier(ud.pkgdir)
|
|
||||||
os.chdir(ud.pkgdir)
|
|
||||||
logger.debug(1, "Running %s", bzrcmd)
|
|
||||||
runfetchcmd(bzrcmd, d)
|
|
||||||
|
|
||||||
os.chdir(ud.pkgdir)
|
|
||||||
|
|
||||||
scmdata = ud.parm.get("scmdata", "")
|
|
||||||
if scmdata == "keep":
|
|
||||||
tar_flags = ""
|
|
||||||
else:
|
|
||||||
tar_flags = "--exclude '.bzr' --exclude '.bzrtags'"
|
|
||||||
|
|
||||||
# tar them up to a defined filename
|
|
||||||
runfetchcmd("tar %s -czf %s %s" % (tar_flags, ud.localpath, os.path.basename(ud.pkgdir)), d, cleanup = [ud.localpath])
|
|
||||||
|
|
||||||
def supports_srcrev(self):
|
|
||||||
return True
|
|
||||||
|
|
||||||
def _revision_key(self, url, ud, d, name):
|
|
||||||
"""
|
|
||||||
Return a unique key for the url
|
|
||||||
"""
|
|
||||||
return "bzr:" + ud.pkgdir
|
|
||||||
|
|
||||||
def _latest_revision(self, url, ud, d, name):
|
|
||||||
"""
|
|
||||||
Return the latest upstream revision number
|
|
||||||
"""
|
|
||||||
logger.debug(2, "BZR fetcher hitting network for %s", url)
|
|
||||||
|
|
||||||
bb.fetch2.check_network_access(d, self._buildbzrcommand(ud, d, "revno"), ud.url)
|
|
||||||
|
|
||||||
output = runfetchcmd(self._buildbzrcommand(ud, d, "revno"), d, True)
|
|
||||||
|
|
||||||
return output.strip()
|
|
||||||
|
|
||||||
def _sortable_revision(self, url, ud, d):
|
|
||||||
"""
|
|
||||||
Return a sortable revision number which in our case is the revision number
|
|
||||||
"""
|
|
||||||
|
|
||||||
return self._build_revision(url, ud, d)
|
|
||||||
|
|
||||||
def _build_revision(self, url, ud, d):
|
|
||||||
return ud.revision
|
|
||||||
@@ -1,181 +0,0 @@
|
|||||||
# ex:ts=4:sw=4:sts=4:et
|
|
||||||
# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
|
|
||||||
"""
|
|
||||||
BitBake 'Fetch' implementations
|
|
||||||
|
|
||||||
Classes for obtaining upstream sources for the
|
|
||||||
BitBake build tools.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
# Copyright (C) 2003, 2004 Chris Larson
|
|
||||||
#
|
|
||||||
# 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.
|
|
||||||
#
|
|
||||||
#Based on functions from the base bb module, Copyright 2003 Holger Schurig
|
|
||||||
#
|
|
||||||
|
|
||||||
import os
|
|
||||||
import logging
|
|
||||||
import bb
|
|
||||||
from bb import data
|
|
||||||
from bb.fetch2 import FetchMethod, FetchError, MissingParameterError, logger
|
|
||||||
from bb.fetch2 import runfetchcmd
|
|
||||||
|
|
||||||
class Cvs(FetchMethod):
|
|
||||||
"""
|
|
||||||
Class to fetch a module or modules from cvs repositories
|
|
||||||
"""
|
|
||||||
def supports(self, url, ud, d):
|
|
||||||
"""
|
|
||||||
Check to see if a given url can be fetched with cvs.
|
|
||||||
"""
|
|
||||||
return ud.type in ['cvs']
|
|
||||||
|
|
||||||
def urldata_init(self, ud, d):
|
|
||||||
if not "module" in ud.parm:
|
|
||||||
raise MissingParameterError("module", ud.url)
|
|
||||||
ud.module = ud.parm["module"]
|
|
||||||
|
|
||||||
ud.tag = ud.parm.get('tag', "")
|
|
||||||
|
|
||||||
# Override the default date in certain cases
|
|
||||||
if 'date' in ud.parm:
|
|
||||||
ud.date = ud.parm['date']
|
|
||||||
elif ud.tag:
|
|
||||||
ud.date = ""
|
|
||||||
|
|
||||||
norecurse = ''
|
|
||||||
if 'norecurse' in ud.parm:
|
|
||||||
norecurse = '_norecurse'
|
|
||||||
|
|
||||||
fullpath = ''
|
|
||||||
if 'fullpath' in ud.parm:
|
|
||||||
fullpath = '_fullpath'
|
|
||||||
|
|
||||||
ud.localfile = 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, url, ud, d):
|
|
||||||
if (ud.date == "now"):
|
|
||||||
return True
|
|
||||||
if not os.path.exists(ud.localpath):
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
def download(self, loc, ud, d):
|
|
||||||
|
|
||||||
method = ud.parm.get('method', 'pserver')
|
|
||||||
localdir = ud.parm.get('localdir', ud.module)
|
|
||||||
cvs_port = ud.parm.get('port', '')
|
|
||||||
|
|
||||||
cvs_rsh = None
|
|
||||||
if method == "ext":
|
|
||||||
if "rsh" in ud.parm:
|
|
||||||
cvs_rsh = ud.parm["rsh"]
|
|
||||||
|
|
||||||
if method == "dir":
|
|
||||||
cvsroot = ud.path
|
|
||||||
else:
|
|
||||||
cvsroot = ":" + method
|
|
||||||
cvsproxyhost = data.getVar('CVS_PROXY_HOST', d, True)
|
|
||||||
if cvsproxyhost:
|
|
||||||
cvsroot += ";proxy=" + cvsproxyhost
|
|
||||||
cvsproxyport = data.getVar('CVS_PROXY_PORT', d, True)
|
|
||||||
if cvsproxyport:
|
|
||||||
cvsroot += ";proxyport=" + cvsproxyport
|
|
||||||
cvsroot += ":" + ud.user
|
|
||||||
if ud.pswd:
|
|
||||||
cvsroot += ":" + ud.pswd
|
|
||||||
cvsroot += "@" + ud.host + ":" + cvs_port + ud.path
|
|
||||||
|
|
||||||
options = []
|
|
||||||
if 'norecurse' in ud.parm:
|
|
||||||
options.append("-l")
|
|
||||||
if ud.date:
|
|
||||||
# treat YYYYMMDDHHMM specially for CVS
|
|
||||||
if len(ud.date) == 12:
|
|
||||||
options.append("-D \"%s %s:%s UTC\"" % (ud.date[0:8], ud.date[8:10], ud.date[10:12]))
|
|
||||||
else:
|
|
||||||
options.append("-D \"%s UTC\"" % ud.date)
|
|
||||||
if ud.tag:
|
|
||||||
options.append("-r %s" % ud.tag)
|
|
||||||
|
|
||||||
localdata = data.createCopy(d)
|
|
||||||
data.setVar('OVERRIDES', "cvs:%s" % data.getVar('OVERRIDES', localdata), localdata)
|
|
||||||
data.update_data(localdata)
|
|
||||||
|
|
||||||
data.setVar('CVSROOT', cvsroot, localdata)
|
|
||||||
data.setVar('CVSCOOPTS', " ".join(options), localdata)
|
|
||||||
data.setVar('CVSMODULE', ud.module, localdata)
|
|
||||||
cvscmd = data.getVar('FETCHCOMMAND', localdata, True)
|
|
||||||
cvsupdatecmd = data.getVar('UPDATECOMMAND', localdata, True)
|
|
||||||
|
|
||||||
if cvs_rsh:
|
|
||||||
cvscmd = "CVS_RSH=\"%s\" %s" % (cvs_rsh, cvscmd)
|
|
||||||
cvsupdatecmd = "CVS_RSH=\"%s\" %s" % (cvs_rsh, cvsupdatecmd)
|
|
||||||
|
|
||||||
# create module directory
|
|
||||||
logger.debug(2, "Fetch: checking for module directory")
|
|
||||||
pkg = data.expand('${PN}', d)
|
|
||||||
pkgdir = os.path.join(data.expand('${CVSDIR}', localdata), pkg)
|
|
||||||
moddir = os.path.join(pkgdir, localdir)
|
|
||||||
if os.access(os.path.join(moddir, 'CVS'), os.R_OK):
|
|
||||||
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 " + loc)
|
|
||||||
# check out sources there
|
|
||||||
bb.utils.mkdirhier(pkgdir)
|
|
||||||
os.chdir(pkgdir)
|
|
||||||
logger.debug(1, "Running %s", cvscmd)
|
|
||||||
bb.fetch2.check_network_access(d, cvscmd, ud.url)
|
|
||||||
cmd = cvscmd
|
|
||||||
|
|
||||||
runfetchcmd(cmd, d, cleanup = [moddir])
|
|
||||||
|
|
||||||
if not os.access(moddir, os.R_OK):
|
|
||||||
raise FetchError("Directory %s was not readable despite sucessful fetch?!" % moddir, ud.url)
|
|
||||||
|
|
||||||
scmdata = ud.parm.get("scmdata", "")
|
|
||||||
if scmdata == "keep":
|
|
||||||
tar_flags = ""
|
|
||||||
else:
|
|
||||||
tar_flags = "--exclude 'CVS'"
|
|
||||||
|
|
||||||
# tar them up to a defined filename
|
|
||||||
if 'fullpath' in ud.parm:
|
|
||||||
os.chdir(pkgdir)
|
|
||||||
cmd = "tar %s -czf %s %s" % (tar_flags, ud.localpath, localdir)
|
|
||||||
else:
|
|
||||||
os.chdir(moddir)
|
|
||||||
os.chdir('..')
|
|
||||||
cmd = "tar %s -czf %s %s" % (tar_flags, ud.localpath, os.path.basename(moddir))
|
|
||||||
|
|
||||||
runfetchcmd(cmd, d, cleanup = [ud.localpath])
|
|
||||||
|
|
||||||
def clean(self, ud, d):
|
|
||||||
""" Clean CVS Files and tarballs """
|
|
||||||
|
|
||||||
pkg = data.expand('${PN}', d)
|
|
||||||
localdata = data.createCopy(d)
|
|
||||||
data.setVar('OVERRIDES', "cvs:%s" % data.getVar('OVERRIDES', localdata), localdata)
|
|
||||||
data.update_data(localdata)
|
|
||||||
pkgdir = os.path.join(data.expand('${CVSDIR}', localdata), pkg)
|
|
||||||
|
|
||||||
bb.utils.remove(pkgdir, True)
|
|
||||||
bb.utils.remove(ud.localpath)
|
|
||||||
|
|
||||||
@@ -1,242 +0,0 @@
|
|||||||
# ex:ts=4:sw=4:sts=4:et
|
|
||||||
# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
|
|
||||||
"""
|
|
||||||
BitBake 'Fetch' git implementation
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
#Copyright (C) 2005 Richard Purdie
|
|
||||||
#
|
|
||||||
# This program is free software; you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU General Public License version 2 as
|
|
||||||
# published by the Free Software Foundation.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License along
|
|
||||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
|
|
||||||
import os
|
|
||||||
import bb
|
|
||||||
from bb import data
|
|
||||||
from bb.fetch2 import FetchMethod
|
|
||||||
from bb.fetch2 import runfetchcmd
|
|
||||||
from bb.fetch2 import logger
|
|
||||||
|
|
||||||
class Git(FetchMethod):
|
|
||||||
"""Class to fetch a module or modules from git repositories"""
|
|
||||||
def init(self, d):
|
|
||||||
#
|
|
||||||
# Only enable _sortable revision if the key is set
|
|
||||||
#
|
|
||||||
if bb.data.getVar("BB_GIT_CLONE_FOR_SRCREV", d, True):
|
|
||||||
self._sortable_buildindex = self._sortable_buildindex_disabled
|
|
||||||
def supports(self, url, ud, d):
|
|
||||||
"""
|
|
||||||
Check to see if a given url can be fetched with git.
|
|
||||||
"""
|
|
||||||
return ud.type in ['git']
|
|
||||||
|
|
||||||
def urldata_init(self, ud, d):
|
|
||||||
"""
|
|
||||||
init git specific variable within url data
|
|
||||||
so that the git method like latest_revision() can work
|
|
||||||
"""
|
|
||||||
if 'protocol' in ud.parm:
|
|
||||||
ud.proto = ud.parm['protocol']
|
|
||||||
elif not ud.host:
|
|
||||||
ud.proto = 'file'
|
|
||||||
else:
|
|
||||||
ud.proto = "rsync"
|
|
||||||
|
|
||||||
ud.nocheckout = False
|
|
||||||
if 'nocheckout' in ud.parm:
|
|
||||||
ud.nocheckout = True
|
|
||||||
|
|
||||||
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)
|
|
||||||
ud.branches = {}
|
|
||||||
for name in ud.names:
|
|
||||||
branch = branches[ud.names.index(name)]
|
|
||||||
ud.branches[name] = branch
|
|
||||||
|
|
||||||
gitsrcname = '%s%s' % (ud.host, ud.path.replace('/', '.'))
|
|
||||||
ud.mirrortarball = 'git2_%s.tar.gz' % (gitsrcname)
|
|
||||||
ud.fullmirror = os.path.join(data.getVar("DL_DIR", d, True), ud.mirrortarball)
|
|
||||||
ud.clonedir = os.path.join(data.expand('${GITDIR}', d), gitsrcname)
|
|
||||||
|
|
||||||
ud.basecmd = data.getVar("FETCHCMD_git", d, True) or "git"
|
|
||||||
|
|
||||||
for name in ud.names:
|
|
||||||
# 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]]):
|
|
||||||
ud.revisions[name] = self.latest_revision(ud.url, ud, d, name)
|
|
||||||
|
|
||||||
ud.write_tarballs = (data.getVar("BB_GENERATE_MIRROR_TARBALLS", d, True) or "0") != "0"
|
|
||||||
|
|
||||||
ud.localfile = ud.clonedir
|
|
||||||
|
|
||||||
def localpath(self, url, ud, d):
|
|
||||||
return ud.clonedir
|
|
||||||
|
|
||||||
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.revisions[name], d):
|
|
||||||
return True
|
|
||||||
if ud.write_tarballs and not os.path.exists(ud.fullmirror):
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
def try_premirror(self, u, ud, d):
|
|
||||||
# If we don't do this, updating an existing checkout with only premirrors
|
|
||||||
# is not possible
|
|
||||||
if bb.data.getVar("BB_FETCH_PREMIRRORONLY", d, True) is not None:
|
|
||||||
return True
|
|
||||||
if os.path.exists(ud.clonedir):
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
def download(self, loc, ud, d):
|
|
||||||
"""Fetch url"""
|
|
||||||
|
|
||||||
if ud.user:
|
|
||||||
username = ud.user + '@'
|
|
||||||
else:
|
|
||||||
username = ""
|
|
||||||
|
|
||||||
ud.repochanged = not os.path.exists(ud.fullmirror)
|
|
||||||
|
|
||||||
# If the checkout doesn't exist and the mirror tarball does, extract it
|
|
||||||
if not os.path.exists(ud.clonedir) and os.path.exists(ud.fullmirror):
|
|
||||||
bb.utils.mkdirhier(ud.clonedir)
|
|
||||||
os.chdir(ud.clonedir)
|
|
||||||
runfetchcmd("tar -xzf %s" % (ud.fullmirror), d)
|
|
||||||
|
|
||||||
# If the repo still doesn't exist, fallback to cloning it
|
|
||||||
if not os.path.exists(ud.clonedir):
|
|
||||||
bb.fetch2.check_network_access(d, "git clone --bare %s%s" % (ud.host, ud.path))
|
|
||||||
runfetchcmd("%s clone --bare %s://%s%s%s %s" % (ud.basecmd, ud.proto, username, ud.host, ud.path, ud.clonedir), d)
|
|
||||||
|
|
||||||
os.chdir(ud.clonedir)
|
|
||||||
# Update the checkout if needed
|
|
||||||
needupdate = False
|
|
||||||
for name in ud.names:
|
|
||||||
if not self._contains_ref(ud.revisions[name], d):
|
|
||||||
needupdate = True
|
|
||||||
if needupdate:
|
|
||||||
bb.fetch2.check_network_access(d, "git fetch %s%s" % (ud.host, ud.path), ud.url)
|
|
||||||
try:
|
|
||||||
runfetchcmd("%s remote prune origin" % ud.basecmd, d)
|
|
||||||
runfetchcmd("%s remote rm origin" % ud.basecmd, d)
|
|
||||||
except bb.fetch2.FetchError:
|
|
||||||
logger.debug(1, "No Origin")
|
|
||||||
|
|
||||||
runfetchcmd("%s remote add origin %s://%s%s%s" % (ud.basecmd, ud.proto, username, ud.host, ud.path), d)
|
|
||||||
runfetchcmd("%s fetch --all -t" % ud.basecmd, d)
|
|
||||||
runfetchcmd("%s prune-packed" % ud.basecmd, d)
|
|
||||||
runfetchcmd("%s pack-redundant --all | xargs -r rm" % ud.basecmd, d)
|
|
||||||
ud.repochanged = True
|
|
||||||
|
|
||||||
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)):
|
|
||||||
os.chdir(ud.clonedir)
|
|
||||||
logger.info("Creating tarball of git repository")
|
|
||||||
runfetchcmd("tar -czf %s %s" % (ud.fullmirror, os.path.join(".") ), d)
|
|
||||||
|
|
||||||
def unpack(self, ud, destdir, d):
|
|
||||||
""" unpack the downloaded src to destdir"""
|
|
||||||
|
|
||||||
subdir = ud.parm.get("subpath", "")
|
|
||||||
if subdir != "":
|
|
||||||
readpathspec = ":%s" % (subdir)
|
|
||||||
else:
|
|
||||||
readpathspec = ""
|
|
||||||
|
|
||||||
destdir = os.path.join(destdir, "git/")
|
|
||||||
if os.path.exists(destdir):
|
|
||||||
bb.utils.prunedir(destdir)
|
|
||||||
|
|
||||||
runfetchcmd("git clone -s -n %s %s" % (ud.clonedir, destdir), d)
|
|
||||||
if not ud.nocheckout:
|
|
||||||
os.chdir(destdir)
|
|
||||||
runfetchcmd("%s read-tree %s%s" % (ud.basecmd, ud.revisions[ud.names[0]], readpathspec), d)
|
|
||||||
runfetchcmd("%s checkout-index -q -f -a" % ud.basecmd, d)
|
|
||||||
return True
|
|
||||||
|
|
||||||
def clean(self, ud, d):
|
|
||||||
""" clean the git directory """
|
|
||||||
|
|
||||||
bb.utils.remove(ud.localpath, True)
|
|
||||||
bb.utils.remove(ud.fullmirror)
|
|
||||||
|
|
||||||
def supports_srcrev(self):
|
|
||||||
return True
|
|
||||||
|
|
||||||
def _contains_ref(self, tag, d):
|
|
||||||
basecmd = data.getVar("FETCHCMD_git", d, True) or "git"
|
|
||||||
output = runfetchcmd("%s log --pretty=oneline -n 1 %s -- 2> /dev/null | wc -l" % (basecmd, tag), d, quiet=True)
|
|
||||||
return output.split()[0] != "0"
|
|
||||||
|
|
||||||
def _revision_key(self, url, ud, d, name):
|
|
||||||
"""
|
|
||||||
Return a unique key for the url
|
|
||||||
"""
|
|
||||||
return "git:" + ud.host + ud.path.replace('/', '.') + ud.branches[name]
|
|
||||||
|
|
||||||
def _latest_revision(self, url, ud, d, name):
|
|
||||||
"""
|
|
||||||
Compute the HEAD revision for the url
|
|
||||||
"""
|
|
||||||
if ud.user:
|
|
||||||
username = ud.user + '@'
|
|
||||||
else:
|
|
||||||
username = ""
|
|
||||||
|
|
||||||
bb.fetch2.check_network_access(d, "git ls-remote %s%s %s" % (ud.host, ud.path, ud.branches[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])
|
|
||||||
output = runfetchcmd(cmd, d, True)
|
|
||||||
if not output:
|
|
||||||
raise bb.fetch2.FetchError("The command %s gave empty output unexpectedly" % cmd, url)
|
|
||||||
return output.split()[0]
|
|
||||||
|
|
||||||
def _build_revision(self, url, ud, d, name):
|
|
||||||
return ud.revisions[name]
|
|
||||||
|
|
||||||
def _sortable_buildindex_disabled(self, url, ud, d, rev):
|
|
||||||
"""
|
|
||||||
Return a suitable buildindex for the revision specified. This is done by counting revisions
|
|
||||||
using "git rev-list" which may or may not work in different circumstances.
|
|
||||||
"""
|
|
||||||
|
|
||||||
cwd = os.getcwd()
|
|
||||||
|
|
||||||
# Check if we have the rev already
|
|
||||||
|
|
||||||
if not os.path.exists(ud.clonedir):
|
|
||||||
print("no repo")
|
|
||||||
self.download(None, ud, d)
|
|
||||||
if not os.path.exists(ud.clonedir):
|
|
||||||
logger.error("GIT repository for %s doesn't exist in %s, cannot get sortable buildnumber, using old value", url, ud.clonedir)
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
os.chdir(ud.clonedir)
|
|
||||||
if not self._contains_ref(rev, d):
|
|
||||||
self.download(None, ud, d)
|
|
||||||
|
|
||||||
output = runfetchcmd("%s rev-list %s -- 2> /dev/null | wc -l" % (ud.basecmd, rev), d, quiet=True)
|
|
||||||
os.chdir(cwd)
|
|
||||||
|
|
||||||
buildindex = "%s" % output.split()[0]
|
|
||||||
logger.debug(1, "GIT repository for %s in %s is returning %s revisions in rev-list before %s", url, ud.clonedir, buildindex, rev)
|
|
||||||
return buildindex
|
|
||||||
@@ -1,174 +0,0 @@
|
|||||||
# ex:ts=4:sw=4:sts=4:et
|
|
||||||
# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
|
|
||||||
"""
|
|
||||||
BitBake 'Fetch' implementation for mercurial DRCS (hg).
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
# Copyright (C) 2003, 2004 Chris Larson
|
|
||||||
# Copyright (C) 2004 Marcin Juszkiewicz
|
|
||||||
# Copyright (C) 2007 Robert Schuster
|
|
||||||
#
|
|
||||||
# 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.
|
|
||||||
#
|
|
||||||
# Based on functions from the base bb module, Copyright 2003 Holger Schurig
|
|
||||||
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
import logging
|
|
||||||
import bb
|
|
||||||
from bb import data
|
|
||||||
from bb.fetch2 import FetchMethod
|
|
||||||
from bb.fetch2 import FetchError
|
|
||||||
from bb.fetch2 import MissingParameterError
|
|
||||||
from bb.fetch2 import runfetchcmd
|
|
||||||
from bb.fetch2 import logger
|
|
||||||
|
|
||||||
class Hg(FetchMethod):
|
|
||||||
"""Class to fetch from mercurial repositories"""
|
|
||||||
def supports(self, url, ud, d):
|
|
||||||
"""
|
|
||||||
Check to see if a given url can be fetched with mercurial.
|
|
||||||
"""
|
|
||||||
return ud.type in ['hg']
|
|
||||||
|
|
||||||
def urldata_init(self, ud, d):
|
|
||||||
"""
|
|
||||||
init hg specific variable within url data
|
|
||||||
"""
|
|
||||||
if not "module" in ud.parm:
|
|
||||||
raise MissingParameterError('module', ud.url)
|
|
||||||
|
|
||||||
ud.module = ud.parm["module"]
|
|
||||||
|
|
||||||
# Create paths to mercurial checkouts
|
|
||||||
relpath = self._strip_leading_slashes(ud.path)
|
|
||||||
ud.pkgdir = os.path.join(data.expand('${HGDIR}', d), ud.host, relpath)
|
|
||||||
ud.moddir = os.path.join(ud.pkgdir, ud.module)
|
|
||||||
|
|
||||||
if 'rev' in ud.parm:
|
|
||||||
ud.revision = ud.parm['rev']
|
|
||||||
elif not ud.revision:
|
|
||||||
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, url, ud, d):
|
|
||||||
revTag = ud.parm.get('rev', 'tip')
|
|
||||||
if revTag == "tip":
|
|
||||||
return True
|
|
||||||
if not os.path.exists(ud.localpath):
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
def _buildhgcommand(self, ud, d, command):
|
|
||||||
"""
|
|
||||||
Build up an hg commandline based on ud
|
|
||||||
command is "fetch", "update", "info"
|
|
||||||
"""
|
|
||||||
|
|
||||||
basecmd = data.expand('${FETCHCMD_hg}', d)
|
|
||||||
|
|
||||||
proto = ud.parm.get('proto', 'http')
|
|
||||||
|
|
||||||
host = ud.host
|
|
||||||
if proto == "file":
|
|
||||||
host = "/"
|
|
||||||
ud.host = "localhost"
|
|
||||||
|
|
||||||
if not ud.user:
|
|
||||||
hgroot = host + ud.path
|
|
||||||
else:
|
|
||||||
hgroot = ud.user + "@" + host + ud.path
|
|
||||||
|
|
||||||
if command is "info":
|
|
||||||
return "%s identify -i %s://%s/%s" % (basecmd, proto, hgroot, ud.module)
|
|
||||||
|
|
||||||
options = [];
|
|
||||||
if ud.revision:
|
|
||||||
options.append("-r %s" % ud.revision)
|
|
||||||
|
|
||||||
if command is "fetch":
|
|
||||||
cmd = "%s clone %s %s://%s/%s %s" % (basecmd, " ".join(options), proto, hgroot, ud.module, ud.module)
|
|
||||||
elif command is "pull":
|
|
||||||
# do not pass options list; limiting pull to rev causes the local
|
|
||||||
# repo not to contain it and immediately following "update" command
|
|
||||||
# will crash
|
|
||||||
cmd = "%s pull" % (basecmd)
|
|
||||||
elif command is "update":
|
|
||||||
cmd = "%s update -C %s" % (basecmd, " ".join(options))
|
|
||||||
else:
|
|
||||||
raise FetchError("Invalid hg command %s" % command, ud.url)
|
|
||||||
|
|
||||||
return cmd
|
|
||||||
|
|
||||||
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 " + loc)
|
|
||||||
# update sources there
|
|
||||||
os.chdir(ud.moddir)
|
|
||||||
logger.debug(1, "Running %s", updatecmd)
|
|
||||||
bb.fetch2.check_network_access(d, updatecmd, ud.url)
|
|
||||||
runfetchcmd(updatecmd, d)
|
|
||||||
|
|
||||||
else:
|
|
||||||
fetchcmd = self._buildhgcommand(ud, d, "fetch")
|
|
||||||
logger.info("Fetch " + loc)
|
|
||||||
# check out sources there
|
|
||||||
bb.utils.mkdirhier(ud.pkgdir)
|
|
||||||
os.chdir(ud.pkgdir)
|
|
||||||
logger.debug(1, "Running %s", fetchcmd)
|
|
||||||
bb.fetch2.check_network_access(d, fetchcmd, ud.url)
|
|
||||||
runfetchcmd(fetchcmd, d)
|
|
||||||
|
|
||||||
# Even when we clone (fetch), we still need to update as hg's clone
|
|
||||||
# won't checkout the specified revision if its on a branch
|
|
||||||
updatecmd = self._buildhgcommand(ud, d, "update")
|
|
||||||
os.chdir(ud.moddir)
|
|
||||||
logger.debug(1, "Running %s", updatecmd)
|
|
||||||
runfetchcmd(updatecmd, d)
|
|
||||||
|
|
||||||
scmdata = ud.parm.get("scmdata", "")
|
|
||||||
if scmdata == "keep":
|
|
||||||
tar_flags = ""
|
|
||||||
else:
|
|
||||||
tar_flags = "--exclude '.hg' --exclude '.hgrags'"
|
|
||||||
|
|
||||||
os.chdir(ud.pkgdir)
|
|
||||||
runfetchcmd("tar %s -czf %s %s" % (tar_flags, ud.localpath, ud.module), d, cleanup = [ud.localpath])
|
|
||||||
|
|
||||||
def supports_srcrev(self):
|
|
||||||
return True
|
|
||||||
|
|
||||||
def _latest_revision(self, url, ud, d, name):
|
|
||||||
"""
|
|
||||||
Compute tip revision for the url
|
|
||||||
"""
|
|
||||||
bb.fetch2.check_network_access(d, self._buildhgcommand(ud, d, "info"))
|
|
||||||
output = runfetchcmd(self._buildhgcommand(ud, d, "info"), d)
|
|
||||||
return output.strip()
|
|
||||||
|
|
||||||
def _build_revision(self, url, ud, d):
|
|
||||||
return ud.revision
|
|
||||||
|
|
||||||
def _revision_key(self, url, ud, d, name):
|
|
||||||
"""
|
|
||||||
Return a unique key for the url
|
|
||||||
"""
|
|
||||||
return "hg:" + ud.moddir
|
|
||||||
@@ -1,93 +0,0 @@
|
|||||||
# ex:ts=4:sw=4:sts=4:et
|
|
||||||
# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
|
|
||||||
"""
|
|
||||||
BitBake 'Fetch' implementations
|
|
||||||
|
|
||||||
Classes for obtaining upstream sources for the
|
|
||||||
BitBake build tools.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
# Copyright (C) 2003, 2004 Chris Larson
|
|
||||||
#
|
|
||||||
# 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.
|
|
||||||
#
|
|
||||||
# Based on functions from the base bb module, Copyright 2003 Holger Schurig
|
|
||||||
|
|
||||||
import os
|
|
||||||
import bb
|
|
||||||
import bb.utils
|
|
||||||
from bb import data
|
|
||||||
from bb.fetch2 import FetchMethod
|
|
||||||
|
|
||||||
class Local(FetchMethod):
|
|
||||||
def supports(self, url, urldata, d):
|
|
||||||
"""
|
|
||||||
Check to see if a given url represents a local fetch.
|
|
||||||
"""
|
|
||||||
return urldata.type in ['file']
|
|
||||||
|
|
||||||
def urldata_init(self, ud, d):
|
|
||||||
# We don't set localfile as for this fetcher the file is already local!
|
|
||||||
ud.basename = os.path.basename(ud.url.split("://")[1].split(";")[0])
|
|
||||||
return
|
|
||||||
|
|
||||||
def localpath(self, url, urldata, d):
|
|
||||||
"""
|
|
||||||
Return the local filename of a given url assuming a successful fetch.
|
|
||||||
"""
|
|
||||||
path = url.split("://")[1]
|
|
||||||
path = path.split(";")[0]
|
|
||||||
newpath = path
|
|
||||||
dldirfile = os.path.join(data.getVar("DL_DIR", d, True), os.path.basename(path))
|
|
||||||
if os.path.exists(dldirfile):
|
|
||||||
return dldirfile
|
|
||||||
if path[0] != "/":
|
|
||||||
filespath = data.getVar('FILESPATH', d, True)
|
|
||||||
if filespath:
|
|
||||||
newpath = bb.utils.which(filespath, path)
|
|
||||||
if not newpath:
|
|
||||||
filesdir = data.getVar('FILESDIR', d, True)
|
|
||||||
if filesdir:
|
|
||||||
newpath = os.path.join(filesdir, path)
|
|
||||||
if not os.path.exists(newpath) and path.find("*") == -1:
|
|
||||||
return dldirfile
|
|
||||||
return newpath
|
|
||||||
|
|
||||||
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, url, urldata, d):
|
|
||||||
"""Fetch urls (no-op for Local method)"""
|
|
||||||
# no need to fetch local files, we'll deal with them in place.
|
|
||||||
return 1
|
|
||||||
|
|
||||||
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.", url)
|
|
||||||
return True
|
|
||||||
if os.path.exists(urldata.localpath):
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
def clean(self, urldata, d):
|
|
||||||
return
|
|
||||||
|
|
||||||
@@ -1,135 +0,0 @@
|
|||||||
# ex:ts=4:sw=4:sts=4:et
|
|
||||||
# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
|
|
||||||
"""
|
|
||||||
Bitbake "Fetch" implementation for osc (Opensuse build service client).
|
|
||||||
Based on the svn "Fetch" implementation.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
import logging
|
|
||||||
import bb
|
|
||||||
from bb import data
|
|
||||||
from bb.fetch2 import FetchMethod
|
|
||||||
from bb.fetch2 import FetchError
|
|
||||||
from bb.fetch2 import MissingParameterError
|
|
||||||
from bb.fetch2 import runfetchcmd
|
|
||||||
|
|
||||||
class Osc(FetchMethod):
|
|
||||||
"""Class to fetch a module or modules from Opensuse build server
|
|
||||||
repositories."""
|
|
||||||
|
|
||||||
def supports(self, url, ud, d):
|
|
||||||
"""
|
|
||||||
Check to see if a given url can be fetched with osc.
|
|
||||||
"""
|
|
||||||
return ud.type in ['osc']
|
|
||||||
|
|
||||||
def urldata_init(self, ud, d):
|
|
||||||
if not "module" in ud.parm:
|
|
||||||
raise MissingParameterError('module', ud.url)
|
|
||||||
|
|
||||||
ud.module = ud.parm["module"]
|
|
||||||
|
|
||||||
# Create paths to osc checkouts
|
|
||||||
relpath = self._strip_leading_slashes(ud.path)
|
|
||||||
ud.pkgdir = os.path.join(data.expand('${OSCDIR}', d), ud.host)
|
|
||||||
ud.moddir = os.path.join(ud.pkgdir, relpath, ud.module)
|
|
||||||
|
|
||||||
if 'rev' in ud.parm:
|
|
||||||
ud.revision = ud.parm['rev']
|
|
||||||
else:
|
|
||||||
pv = data.getVar("PV", d, 0)
|
|
||||||
rev = bb.fetch2.srcrev_internal_helper(ud, d)
|
|
||||||
if rev and rev != True:
|
|
||||||
ud.revision = rev
|
|
||||||
else:
|
|
||||||
ud.revision = ""
|
|
||||||
|
|
||||||
ud.localfile = data.expand('%s_%s_%s.tar.gz' % (ud.module.replace('/', '.'), ud.path.replace('/', '.'), ud.revision), d)
|
|
||||||
|
|
||||||
def _buildosccommand(self, ud, d, command):
|
|
||||||
"""
|
|
||||||
Build up an ocs commandline based on ud
|
|
||||||
command is "fetch", "update", "info"
|
|
||||||
"""
|
|
||||||
|
|
||||||
basecmd = data.expand('${FETCHCMD_osc}', d)
|
|
||||||
|
|
||||||
proto = ud.parm.get('proto', 'ocs')
|
|
||||||
|
|
||||||
options = []
|
|
||||||
|
|
||||||
config = "-c %s" % self.generate_config(ud, d)
|
|
||||||
|
|
||||||
if ud.revision:
|
|
||||||
options.append("-r %s" % ud.revision)
|
|
||||||
|
|
||||||
coroot = self._strip_leading_slashes(ud.path)
|
|
||||||
|
|
||||||
if command is "fetch":
|
|
||||||
osccmd = "%s %s co %s/%s %s" % (basecmd, config, coroot, ud.module, " ".join(options))
|
|
||||||
elif command is "update":
|
|
||||||
osccmd = "%s %s up %s" % (basecmd, config, " ".join(options))
|
|
||||||
else:
|
|
||||||
raise FetchError("Invalid osc command %s" % command, ud.url)
|
|
||||||
|
|
||||||
return osccmd
|
|
||||||
|
|
||||||
def download(self, loc, ud, d):
|
|
||||||
"""
|
|
||||||
Fetch url
|
|
||||||
"""
|
|
||||||
|
|
||||||
logger.debug(2, "Fetch: checking for module directory '" + ud.moddir + "'")
|
|
||||||
|
|
||||||
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 "+ loc)
|
|
||||||
# update sources there
|
|
||||||
os.chdir(ud.moddir)
|
|
||||||
logger.debug(1, "Running %s", oscupdatecmd)
|
|
||||||
bb.fetch2.check_network_access(d, oscupdatecmd, ud.url)
|
|
||||||
runfetchcmd(oscupdatecmd, d)
|
|
||||||
else:
|
|
||||||
oscfetchcmd = self._buildosccommand(ud, d, "fetch")
|
|
||||||
logger.info("Fetch " + loc)
|
|
||||||
# check out sources there
|
|
||||||
bb.utils.mkdirhier(ud.pkgdir)
|
|
||||||
os.chdir(ud.pkgdir)
|
|
||||||
logger.debug(1, "Running %s", oscfetchcmd)
|
|
||||||
bb.fetch2.check_network_access(d, oscfetchcmd, ud.url)
|
|
||||||
runfetchcmd(oscfetchcmd, d)
|
|
||||||
|
|
||||||
os.chdir(os.path.join(ud.pkgdir + ud.path))
|
|
||||||
# tar them up to a defined filename
|
|
||||||
runfetchcmd("tar -czf %s %s" % (ud.localpath, ud.module), d, cleanup = [ud.localpath])
|
|
||||||
|
|
||||||
def supports_srcrev(self):
|
|
||||||
return False
|
|
||||||
|
|
||||||
def generate_config(self, ud, d):
|
|
||||||
"""
|
|
||||||
Generate a .oscrc to be used for this run.
|
|
||||||
"""
|
|
||||||
|
|
||||||
config_path = os.path.join(data.expand('${OSCDIR}', d), "oscrc")
|
|
||||||
if (os.path.exists(config_path)):
|
|
||||||
os.remove(config_path)
|
|
||||||
|
|
||||||
f = open(config_path, 'w')
|
|
||||||
f.write("[general]\n")
|
|
||||||
f.write("apisrv = %s\n" % ud.host)
|
|
||||||
f.write("scheme = http\n")
|
|
||||||
f.write("su-wrapper = su -c\n")
|
|
||||||
f.write("build-root = %s\n" % data.expand('${WORKDIR}', d))
|
|
||||||
f.write("urllist = http://moblin-obs.jf.intel.com:8888/build/%(project)s/%(repository)s/%(buildarch)s/:full/%(name)s.rpm\n")
|
|
||||||
f.write("extra-pkgs = gzip\n")
|
|
||||||
f.write("\n")
|
|
||||||
f.write("[%s]\n" % ud.host)
|
|
||||||
f.write("user = %s\n" % ud.parm["user"])
|
|
||||||
f.write("pass = %s\n" % ud.parm["pswd"])
|
|
||||||
f.close()
|
|
||||||
|
|
||||||
return config_path
|
|
||||||
@@ -1,196 +0,0 @@
|
|||||||
# ex:ts=4:sw=4:sts=4:et
|
|
||||||
# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
|
|
||||||
"""
|
|
||||||
BitBake 'Fetch' implementations
|
|
||||||
|
|
||||||
Classes for obtaining upstream sources for the
|
|
||||||
BitBake build tools.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
# Copyright (C) 2003, 2004 Chris Larson
|
|
||||||
#
|
|
||||||
# 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.
|
|
||||||
#
|
|
||||||
# Based on functions from the base bb module, Copyright 2003 Holger Schurig
|
|
||||||
|
|
||||||
from future_builtins import zip
|
|
||||||
import os
|
|
||||||
import logging
|
|
||||||
import bb
|
|
||||||
from bb import data
|
|
||||||
from bb.fetch2 import FetchMethod
|
|
||||||
from bb.fetch2 import FetchError
|
|
||||||
from bb.fetch2 import logger
|
|
||||||
from bb.fetch2 import runfetchcmd
|
|
||||||
|
|
||||||
class Perforce(FetchMethod):
|
|
||||||
def supports(self, url, ud, d):
|
|
||||||
return ud.type in ['p4']
|
|
||||||
|
|
||||||
def doparse(url, d):
|
|
||||||
parm = {}
|
|
||||||
path = url.split("://")[1]
|
|
||||||
delim = path.find("@");
|
|
||||||
if delim != -1:
|
|
||||||
(user, pswd, host, port) = path.split('@')[0].split(":")
|
|
||||||
path = path.split('@')[1]
|
|
||||||
else:
|
|
||||||
(host, port) = data.getVar('P4PORT', d).split(':')
|
|
||||||
user = ""
|
|
||||||
pswd = ""
|
|
||||||
|
|
||||||
if path.find(";") != -1:
|
|
||||||
keys=[]
|
|
||||||
values=[]
|
|
||||||
plist = path.split(';')
|
|
||||||
for item in plist:
|
|
||||||
if item.count('='):
|
|
||||||
(key, value) = item.split('=')
|
|
||||||
keys.append(key)
|
|
||||||
values.append(value)
|
|
||||||
|
|
||||||
parm = dict(zip(keys, values))
|
|
||||||
path = "//" + path.split(';')[0]
|
|
||||||
host += ":%s" % (port)
|
|
||||||
parm["cset"] = Perforce.getcset(d, path, host, user, pswd, parm)
|
|
||||||
|
|
||||||
return host, path, user, pswd, parm
|
|
||||||
doparse = staticmethod(doparse)
|
|
||||||
|
|
||||||
def getcset(d, depot, host, user, pswd, parm):
|
|
||||||
p4opt = ""
|
|
||||||
if "cset" in parm:
|
|
||||||
return parm["cset"];
|
|
||||||
if user:
|
|
||||||
p4opt += " -u %s" % (user)
|
|
||||||
if pswd:
|
|
||||||
p4opt += " -P %s" % (pswd)
|
|
||||||
if host:
|
|
||||||
p4opt += " -p %s" % (host)
|
|
||||||
|
|
||||||
p4date = data.getVar("P4DATE", d, True)
|
|
||||||
if "revision" in parm:
|
|
||||||
depot += "#%s" % (parm["revision"])
|
|
||||||
elif "label" in parm:
|
|
||||||
depot += "@%s" % (parm["label"])
|
|
||||||
elif p4date:
|
|
||||||
depot += "@%s" % (p4date)
|
|
||||||
|
|
||||||
p4cmd = data.getVar('FETCHCOMMAND_p4', d, True)
|
|
||||||
logger.debug(1, "Running %s%s changes -m 1 %s", p4cmd, p4opt, depot)
|
|
||||||
p4file = os.popen("%s%s changes -m 1 %s" % (p4cmd, p4opt, depot))
|
|
||||||
cset = p4file.readline().strip()
|
|
||||||
logger.debug(1, "READ %s", cset)
|
|
||||||
if not cset:
|
|
||||||
return -1
|
|
||||||
|
|
||||||
return cset.split(' ')[1]
|
|
||||||
getcset = staticmethod(getcset)
|
|
||||||
|
|
||||||
def urldata_init(self, ud, d):
|
|
||||||
(host, path, user, pswd, parm) = Perforce.doparse(ud.url, d)
|
|
||||||
|
|
||||||
# If a label is specified, we use that as our filename
|
|
||||||
|
|
||||||
if "label" in parm:
|
|
||||||
ud.localfile = "%s.tar.gz" % (parm["label"])
|
|
||||||
return
|
|
||||||
|
|
||||||
base = path
|
|
||||||
which = path.find('/...')
|
|
||||||
if which != -1:
|
|
||||||
base = path[:which]
|
|
||||||
|
|
||||||
base = self._strip_leading_slashes(base)
|
|
||||||
|
|
||||||
cset = Perforce.getcset(d, path, host, user, pswd, parm)
|
|
||||||
|
|
||||||
ud.localfile = data.expand('%s+%s+%s.tar.gz' % (host, base.replace('/', '.'), cset), d)
|
|
||||||
|
|
||||||
def download(self, loc, ud, d):
|
|
||||||
"""
|
|
||||||
Fetch urls
|
|
||||||
"""
|
|
||||||
|
|
||||||
(host, depot, user, pswd, parm) = Perforce.doparse(loc, d)
|
|
||||||
|
|
||||||
if depot.find('/...') != -1:
|
|
||||||
path = depot[:depot.find('/...')]
|
|
||||||
else:
|
|
||||||
path = depot
|
|
||||||
|
|
||||||
module = parm.get('module', os.path.basename(path))
|
|
||||||
|
|
||||||
localdata = data.createCopy(d)
|
|
||||||
data.setVar('OVERRIDES', "p4:%s" % data.getVar('OVERRIDES', localdata), localdata)
|
|
||||||
data.update_data(localdata)
|
|
||||||
|
|
||||||
# Get the p4 command
|
|
||||||
p4opt = ""
|
|
||||||
if user:
|
|
||||||
p4opt += " -u %s" % (user)
|
|
||||||
|
|
||||||
if pswd:
|
|
||||||
p4opt += " -P %s" % (pswd)
|
|
||||||
|
|
||||||
if host:
|
|
||||||
p4opt += " -p %s" % (host)
|
|
||||||
|
|
||||||
p4cmd = data.getVar('FETCHCOMMAND', localdata, True)
|
|
||||||
|
|
||||||
# create temp directory
|
|
||||||
logger.debug(2, "Fetch: creating temporary directory")
|
|
||||||
bb.utils.mkdirhier(data.expand('${WORKDIR}', localdata))
|
|
||||||
data.setVar('TMPBASE', data.expand('${WORKDIR}/oep4.XXXXXX', localdata), localdata)
|
|
||||||
tmppipe = os.popen(data.getVar('MKTEMPDIRCMD', localdata, True) or "false")
|
|
||||||
tmpfile = tmppipe.readline().strip()
|
|
||||||
if not tmpfile:
|
|
||||||
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"])
|
|
||||||
else:
|
|
||||||
cset = Perforce.getcset(d, depot, host, user, pswd, parm)
|
|
||||||
depot = "%s@%s" % (depot, cset)
|
|
||||||
|
|
||||||
os.chdir(tmpfile)
|
|
||||||
logger.info("Fetch " + loc)
|
|
||||||
logger.info("%s%s files %s", p4cmd, p4opt, depot)
|
|
||||||
p4file = os.popen("%s%s files %s" % (p4cmd, p4opt, depot))
|
|
||||||
|
|
||||||
if not p4file:
|
|
||||||
raise FetchError("Fetch: unable to get the P4 files from %s" % depot, loc)
|
|
||||||
|
|
||||||
count = 0
|
|
||||||
|
|
||||||
for file in p4file:
|
|
||||||
list = file.split()
|
|
||||||
|
|
||||||
if list[2] == "delete":
|
|
||||||
continue
|
|
||||||
|
|
||||||
dest = list[0][len(path)+1:]
|
|
||||||
where = dest.find("#")
|
|
||||||
|
|
||||||
os.system("%s%s print -o %s/%s %s" % (p4cmd, p4opt, module, dest[:where], list[0]))
|
|
||||||
count = count + 1
|
|
||||||
|
|
||||||
if count == 0:
|
|
||||||
logger.error()
|
|
||||||
raise FetchError("Fetch: No files gathered from the P4 fetch", loc)
|
|
||||||
|
|
||||||
runfetchcmd("tar -czf %s %s" % (ud.localpath, module), d, cleanup = [ud.localpath])
|
|
||||||
# cleanup
|
|
||||||
bb.utils.prunedir(tmpfile)
|
|
||||||
@@ -1,98 +0,0 @@
|
|||||||
# ex:ts=4:sw=4:sts=4:et
|
|
||||||
# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
|
|
||||||
"""
|
|
||||||
BitBake "Fetch" repo (git) implementation
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
# Copyright (C) 2009 Tom Rini <trini@embeddedalley.com>
|
|
||||||
#
|
|
||||||
# Based on git.py which is:
|
|
||||||
#Copyright (C) 2005 Richard Purdie
|
|
||||||
#
|
|
||||||
# This program is free software; you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU General Public License version 2 as
|
|
||||||
# published by the Free Software Foundation.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License along
|
|
||||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
|
|
||||||
import os
|
|
||||||
import bb
|
|
||||||
from bb import data
|
|
||||||
from bb.fetch2 import FetchMethod
|
|
||||||
from bb.fetch2 import runfetchcmd
|
|
||||||
|
|
||||||
class Repo(FetchMethod):
|
|
||||||
"""Class to fetch a module or modules from repo (git) repositories"""
|
|
||||||
def supports(self, url, ud, d):
|
|
||||||
"""
|
|
||||||
Check to see if a given url can be fetched with repo.
|
|
||||||
"""
|
|
||||||
return ud.type in ["repo"]
|
|
||||||
|
|
||||||
def urldata_init(self, ud, d):
|
|
||||||
"""
|
|
||||||
We don"t care about the git rev of the manifests repository, but
|
|
||||||
we do care about the manifest to use. The default is "default".
|
|
||||||
We also care about the branch or tag to be used. The default is
|
|
||||||
"master".
|
|
||||||
"""
|
|
||||||
|
|
||||||
ud.proto = ud.parm.get('protocol', 'git')
|
|
||||||
ud.branch = ud.parm.get('branch', 'master')
|
|
||||||
ud.manifest = ud.parm.get('manifest', 'default.xml')
|
|
||||||
if not ud.manifest.endswith('.xml'):
|
|
||||||
ud.manifest += '.xml'
|
|
||||||
|
|
||||||
ud.localfile = data.expand("repo_%s%s_%s_%s.tar.gz" % (ud.host, ud.path.replace("/", "."), ud.manifest, ud.branch), 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):
|
|
||||||
logger.debug(1, "%s already exists (or was stashed). Skipping repo init / sync.", ud.localpath)
|
|
||||||
return
|
|
||||||
|
|
||||||
gitsrcname = "%s%s" % (ud.host, ud.path.replace("/", "."))
|
|
||||||
repodir = data.getVar("REPODIR", d, True) or os.path.join(data.getVar("DL_DIR", d, True), "repo")
|
|
||||||
codir = os.path.join(repodir, gitsrcname, ud.manifest)
|
|
||||||
|
|
||||||
if ud.user:
|
|
||||||
username = ud.user + "@"
|
|
||||||
else:
|
|
||||||
username = ""
|
|
||||||
|
|
||||||
bb.utils.mkdirhier(os.path.join(codir, "repo"))
|
|
||||||
os.chdir(os.path.join(codir, "repo"))
|
|
||||||
if not os.path.exists(os.path.join(codir, "repo", ".repo")):
|
|
||||||
bb.fetch2.check_network_access(d, "repo init -m %s -b %s -u %s://%s%s%s" % (ud.manifest, ud.branch, ud.proto, username, ud.host, ud.path), ud.url)
|
|
||||||
runfetchcmd("repo init -m %s -b %s -u %s://%s%s%s" % (ud.manifest, ud.branch, ud.proto, username, ud.host, ud.path), d)
|
|
||||||
|
|
||||||
bb.fetch2.check_network_access(d, "repo sync %s" % ud.url, ud.url)
|
|
||||||
runfetchcmd("repo sync", d)
|
|
||||||
os.chdir(codir)
|
|
||||||
|
|
||||||
scmdata = ud.parm.get("scmdata", "")
|
|
||||||
if scmdata == "keep":
|
|
||||||
tar_flags = ""
|
|
||||||
else:
|
|
||||||
tar_flags = "--exclude '.repo' --exclude '.git'"
|
|
||||||
|
|
||||||
# Create a cache
|
|
||||||
runfetchcmd("tar %s -czf %s %s" % (tar_flags, ud.localpath, os.path.join(".", "*") ), d)
|
|
||||||
|
|
||||||
def supports_srcrev(self):
|
|
||||||
return False
|
|
||||||
|
|
||||||
def _build_revision(self, url, ud, d):
|
|
||||||
return ud.manifest
|
|
||||||
|
|
||||||
def _want_sortable_revision(self, url, ud, d):
|
|
||||||
return False
|
|
||||||
@@ -1,120 +0,0 @@
|
|||||||
# ex:ts=4:sw=4:sts=4:et
|
|
||||||
# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
|
|
||||||
'''
|
|
||||||
BitBake 'Fetch' implementations
|
|
||||||
|
|
||||||
This implementation is for Secure Shell (SSH), and attempts to comply with the
|
|
||||||
IETF secsh internet draft:
|
|
||||||
http://tools.ietf.org/wg/secsh/draft-ietf-secsh-scp-sftp-ssh-uri/
|
|
||||||
|
|
||||||
Currently does not support the sftp parameters, as this uses scp
|
|
||||||
Also does not support the 'fingerprint' connection parameter.
|
|
||||||
|
|
||||||
'''
|
|
||||||
|
|
||||||
# Copyright (C) 2006 OpenedHand Ltd.
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# Based in part on svk.py:
|
|
||||||
# Copyright (C) 2006 Holger Hans Peter Freyther
|
|
||||||
# Based on svn.py:
|
|
||||||
# Copyright (C) 2003, 2004 Chris Larson
|
|
||||||
# Based on functions from the base bb module:
|
|
||||||
# Copyright 2003 Holger Schurig
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# 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 re, os
|
|
||||||
from bb import data
|
|
||||||
from bb.fetch2 import FetchMethod
|
|
||||||
from bb.fetch2 import FetchError
|
|
||||||
from bb.fetch2 import logger
|
|
||||||
from bb.fetch2 import runfetchcmd
|
|
||||||
|
|
||||||
|
|
||||||
__pattern__ = re.compile(r'''
|
|
||||||
\s* # Skip leading whitespace
|
|
||||||
ssh:// # scheme
|
|
||||||
( # Optional username/password block
|
|
||||||
(?P<user>\S+) # username
|
|
||||||
(:(?P<pass>\S+))? # colon followed by the password (optional)
|
|
||||||
)?
|
|
||||||
(?P<cparam>(;[^;]+)*)? # connection parameters block (optional)
|
|
||||||
@
|
|
||||||
(?P<host>\S+?) # non-greedy match of the host
|
|
||||||
(:(?P<port>[0-9]+))? # colon followed by the port (optional)
|
|
||||||
/
|
|
||||||
(?P<path>[^;]+) # path on the remote system, may be absolute or relative,
|
|
||||||
# and may include the use of '~' to reference the remote home
|
|
||||||
# directory
|
|
||||||
(?P<sparam>(;[^;]+)*)? # parameters block (optional)
|
|
||||||
$
|
|
||||||
''', re.VERBOSE)
|
|
||||||
|
|
||||||
class SSH(FetchMethod):
|
|
||||||
'''Class to fetch a module or modules via Secure Shell'''
|
|
||||||
|
|
||||||
def supports(self, url, urldata, d):
|
|
||||||
return __pattern__.match(url) != None
|
|
||||||
|
|
||||||
def localpath(self, url, urldata, d):
|
|
||||||
m = __pattern__.match(urldata.url)
|
|
||||||
path = m.group('path')
|
|
||||||
host = m.group('host')
|
|
||||||
lpath = os.path.join(data.getVar('DL_DIR', d, True), host, os.path.basename(path))
|
|
||||||
return lpath
|
|
||||||
|
|
||||||
def download(self, url, urldata, d):
|
|
||||||
dldir = data.getVar('DL_DIR', d, True)
|
|
||||||
|
|
||||||
m = __pattern__.match(url)
|
|
||||||
path = m.group('path')
|
|
||||||
host = m.group('host')
|
|
||||||
port = m.group('port')
|
|
||||||
user = m.group('user')
|
|
||||||
password = m.group('pass')
|
|
||||||
|
|
||||||
ldir = os.path.join(dldir, host)
|
|
||||||
lpath = os.path.join(ldir, os.path.basename(path))
|
|
||||||
|
|
||||||
if not os.path.exists(ldir):
|
|
||||||
os.makedirs(ldir)
|
|
||||||
|
|
||||||
if port:
|
|
||||||
port = '-P %s' % port
|
|
||||||
else:
|
|
||||||
port = ''
|
|
||||||
|
|
||||||
if user:
|
|
||||||
fr = user
|
|
||||||
if password:
|
|
||||||
fr += ':%s' % password
|
|
||||||
fr += '@%s' % host
|
|
||||||
else:
|
|
||||||
fr = host
|
|
||||||
fr += ':%s' % path
|
|
||||||
|
|
||||||
|
|
||||||
import commands
|
|
||||||
cmd = 'scp -B -r %s %s %s/' % (
|
|
||||||
port,
|
|
||||||
commands.mkarg(fr),
|
|
||||||
commands.mkarg(ldir)
|
|
||||||
)
|
|
||||||
|
|
||||||
bb.fetch2.check_network_access(d, cmd, urldata.url)
|
|
||||||
|
|
||||||
runfetchcmd(cmd, d)
|
|
||||||
|
|
||||||
@@ -1,97 +0,0 @@
|
|||||||
# ex:ts=4:sw=4:sts=4:et
|
|
||||||
# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
|
|
||||||
"""
|
|
||||||
BitBake 'Fetch' implementations
|
|
||||||
|
|
||||||
This implementation is for svk. It is based on the svn implementation
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
# Copyright (C) 2006 Holger Hans Peter Freyther
|
|
||||||
# Copyright (C) 2003, 2004 Chris Larson
|
|
||||||
#
|
|
||||||
# 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.
|
|
||||||
#
|
|
||||||
# Based on functions from the base bb module, Copyright 2003 Holger Schurig
|
|
||||||
|
|
||||||
import os
|
|
||||||
import logging
|
|
||||||
import bb
|
|
||||||
from bb import data
|
|
||||||
from bb.fetch2 import FetchMethod
|
|
||||||
from bb.fetch2 import FetchError
|
|
||||||
from bb.fetch2 import MissingParameterError
|
|
||||||
from bb.fetch2 import logger
|
|
||||||
from bb.fetch2 import runfetchcmd
|
|
||||||
|
|
||||||
class Svk(FetchMethod):
|
|
||||||
"""Class to fetch a module or modules from svk repositories"""
|
|
||||||
def supports(self, url, ud, d):
|
|
||||||
"""
|
|
||||||
Check to see if a given url can be fetched with svk.
|
|
||||||
"""
|
|
||||||
return ud.type in ['svk']
|
|
||||||
|
|
||||||
def urldata_init(self, ud, d):
|
|
||||||
|
|
||||||
if not "module" in ud.parm:
|
|
||||||
raise MissingParameterError('module', ud.url)
|
|
||||||
else:
|
|
||||||
ud.module = ud.parm["module"]
|
|
||||||
|
|
||||||
ud.revision = ud.parm.get('rev', "")
|
|
||||||
|
|
||||||
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, url, ud, d):
|
|
||||||
if ud.date == "now":
|
|
||||||
return True
|
|
||||||
if not os.path.exists(ud.localpath):
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
def download(self, loc, ud, d):
|
|
||||||
"""Fetch urls"""
|
|
||||||
|
|
||||||
svkroot = ud.host + ud.path
|
|
||||||
|
|
||||||
svkcmd = "svk co -r {%s} %s/%s" % (ud.date, svkroot, ud.module)
|
|
||||||
|
|
||||||
if ud.revision:
|
|
||||||
svkcmd = "svk co -r %s %s/%s" % (ud.revision, svkroot, ud.module)
|
|
||||||
|
|
||||||
# create temp directory
|
|
||||||
localdata = data.createCopy(d)
|
|
||||||
data.update_data(localdata)
|
|
||||||
logger.debug(2, "Fetch: creating temporary directory")
|
|
||||||
bb.utils.mkdirhier(data.expand('${WORKDIR}', localdata))
|
|
||||||
data.setVar('TMPBASE', data.expand('${WORKDIR}/oesvk.XXXXXX', localdata), localdata)
|
|
||||||
tmppipe = os.popen(data.getVar('MKTEMPDIRCMD', localdata, True) or "false")
|
|
||||||
tmpfile = tmppipe.readline().strip()
|
|
||||||
if not tmpfile:
|
|
||||||
logger.error()
|
|
||||||
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 " + loc)
|
|
||||||
logger.debug(1, "Running %s", svkcmd)
|
|
||||||
runfetchcmd(svkcmd, d, cleanup = [tmpfile])
|
|
||||||
|
|
||||||
os.chdir(os.path.join(tmpfile, os.path.dirname(ud.module)))
|
|
||||||
# tar them up to a defined filename
|
|
||||||
runfetchcmd("tar -czf %s %s" % (ud.localpath, os.path.basename(ud.module)), d, cleanup = [ud.localpath])
|
|
||||||
|
|
||||||
# cleanup
|
|
||||||
bb.utils.prunedir(tmpfile)
|
|
||||||
@@ -1,180 +0,0 @@
|
|||||||
# ex:ts=4:sw=4:sts=4:et
|
|
||||||
# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
|
|
||||||
"""
|
|
||||||
BitBake 'Fetch' implementation for svn.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
# Copyright (C) 2003, 2004 Chris Larson
|
|
||||||
# Copyright (C) 2004 Marcin Juszkiewicz
|
|
||||||
#
|
|
||||||
# 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.
|
|
||||||
#
|
|
||||||
# Based on functions from the base bb module, Copyright 2003 Holger Schurig
|
|
||||||
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
import logging
|
|
||||||
import bb
|
|
||||||
from bb import data
|
|
||||||
from bb.fetch2 import FetchMethod
|
|
||||||
from bb.fetch2 import FetchError
|
|
||||||
from bb.fetch2 import MissingParameterError
|
|
||||||
from bb.fetch2 import runfetchcmd
|
|
||||||
from bb.fetch2 import logger
|
|
||||||
|
|
||||||
class Svn(FetchMethod):
|
|
||||||
"""Class to fetch a module or modules from svn repositories"""
|
|
||||||
def supports(self, url, ud, d):
|
|
||||||
"""
|
|
||||||
Check to see if a given url can be fetched with svn.
|
|
||||||
"""
|
|
||||||
return ud.type in ['svn']
|
|
||||||
|
|
||||||
def urldata_init(self, ud, d):
|
|
||||||
"""
|
|
||||||
init svn specific variable within url data
|
|
||||||
"""
|
|
||||||
if not "module" in ud.parm:
|
|
||||||
raise MissingParameterError('module', ud.url)
|
|
||||||
|
|
||||||
ud.module = ud.parm["module"]
|
|
||||||
|
|
||||||
# Create paths to svn checkouts
|
|
||||||
relpath = self._strip_leading_slashes(ud.path)
|
|
||||||
ud.pkgdir = os.path.join(data.expand('${SVNDIR}', d), ud.host, relpath)
|
|
||||||
ud.moddir = os.path.join(ud.pkgdir, ud.module)
|
|
||||||
|
|
||||||
if 'rev' in ud.parm:
|
|
||||||
ud.revision = ud.parm['rev']
|
|
||||||
|
|
||||||
ud.localfile = data.expand('%s_%s_%s_%s_.tar.gz' % (ud.module.replace('/', '.'), ud.host, ud.path.replace('/', '.'), ud.revision), d)
|
|
||||||
|
|
||||||
def _buildsvncommand(self, ud, d, command):
|
|
||||||
"""
|
|
||||||
Build up an svn commandline based on ud
|
|
||||||
command is "fetch", "update", "info"
|
|
||||||
"""
|
|
||||||
|
|
||||||
basecmd = data.expand('${FETCHCMD_svn}', d)
|
|
||||||
|
|
||||||
proto = ud.parm.get('proto', 'svn')
|
|
||||||
|
|
||||||
svn_rsh = None
|
|
||||||
if proto == "svn+ssh" and "rsh" in ud.parm:
|
|
||||||
svn_rsh = ud.parm["rsh"]
|
|
||||||
|
|
||||||
svnroot = ud.host + ud.path
|
|
||||||
|
|
||||||
options = []
|
|
||||||
|
|
||||||
if ud.user:
|
|
||||||
options.append("--username %s" % ud.user)
|
|
||||||
|
|
||||||
if ud.pswd:
|
|
||||||
options.append("--password %s" % ud.pswd)
|
|
||||||
|
|
||||||
if command is "info":
|
|
||||||
svncmd = "%s info %s %s://%s/%s/" % (basecmd, " ".join(options), proto, svnroot, ud.module)
|
|
||||||
else:
|
|
||||||
suffix = ""
|
|
||||||
if ud.revision:
|
|
||||||
options.append("-r %s" % ud.revision)
|
|
||||||
suffix = "@%s" % (ud.revision)
|
|
||||||
|
|
||||||
if command is "fetch":
|
|
||||||
svncmd = "%s co %s %s://%s/%s%s %s" % (basecmd, " ".join(options), proto, svnroot, ud.module, suffix, ud.module)
|
|
||||||
elif command is "update":
|
|
||||||
svncmd = "%s update %s" % (basecmd, " ".join(options))
|
|
||||||
else:
|
|
||||||
raise FetchError("Invalid svn command %s" % command, ud.url)
|
|
||||||
|
|
||||||
if svn_rsh:
|
|
||||||
svncmd = "svn_RSH=\"%s\" %s" % (svn_rsh, svncmd)
|
|
||||||
|
|
||||||
return svncmd
|
|
||||||
|
|
||||||
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 " + loc)
|
|
||||||
# update sources there
|
|
||||||
os.chdir(ud.moddir)
|
|
||||||
logger.debug(1, "Running %s", svnupdatecmd)
|
|
||||||
bb.fetch2.check_network_access(d, svnupdatecmd, ud.url)
|
|
||||||
runfetchcmd(svnupdatecmd, d)
|
|
||||||
else:
|
|
||||||
svnfetchcmd = self._buildsvncommand(ud, d, "fetch")
|
|
||||||
logger.info("Fetch " + loc)
|
|
||||||
# check out sources there
|
|
||||||
bb.utils.mkdirhier(ud.pkgdir)
|
|
||||||
os.chdir(ud.pkgdir)
|
|
||||||
logger.debug(1, "Running %s", svnfetchcmd)
|
|
||||||
bb.fetch2.check_network_access(d, svnfetchcmd, ud.url)
|
|
||||||
runfetchcmd(svnfetchcmd, d)
|
|
||||||
|
|
||||||
scmdata = ud.parm.get("scmdata", "")
|
|
||||||
if scmdata == "keep":
|
|
||||||
tar_flags = ""
|
|
||||||
else:
|
|
||||||
tar_flags = "--exclude '.svn'"
|
|
||||||
|
|
||||||
os.chdir(ud.pkgdir)
|
|
||||||
# tar them up to a defined filename
|
|
||||||
runfetchcmd("tar %s -czf %s %s" % (tar_flags, ud.localpath, ud.module), d, cleanup = [ud.localpath])
|
|
||||||
|
|
||||||
def clean(self, ud, d):
|
|
||||||
""" Clean SVN specific files and dirs """
|
|
||||||
|
|
||||||
bb.utils.remove(ud.localpath)
|
|
||||||
bb.utils.remove(ud.moddir, True)
|
|
||||||
|
|
||||||
|
|
||||||
def supports_srcrev(self):
|
|
||||||
return True
|
|
||||||
|
|
||||||
def _revision_key(self, url, ud, d, name):
|
|
||||||
"""
|
|
||||||
Return a unique key for the url
|
|
||||||
"""
|
|
||||||
return "svn:" + ud.moddir
|
|
||||||
|
|
||||||
def _latest_revision(self, url, ud, d, name):
|
|
||||||
"""
|
|
||||||
Return the latest upstream revision number
|
|
||||||
"""
|
|
||||||
bb.fetch2.check_network_access(d, self._buildsvncommand(ud, d, "info"))
|
|
||||||
|
|
||||||
output = runfetchcmd("LANG=C LC_ALL=C " + self._buildsvncommand(ud, d, "info"), d, True)
|
|
||||||
|
|
||||||
revision = None
|
|
||||||
for line in output.splitlines():
|
|
||||||
if "Last Changed Rev" in line:
|
|
||||||
revision = line.split(":")[1].strip()
|
|
||||||
|
|
||||||
return revision
|
|
||||||
|
|
||||||
def _sortable_revision(self, url, ud, d):
|
|
||||||
"""
|
|
||||||
Return a sortable revision number which in our case is the revision number
|
|
||||||
"""
|
|
||||||
|
|
||||||
return self._build_revision(url, ud, d)
|
|
||||||
|
|
||||||
def _build_revision(self, url, ud, d):
|
|
||||||
return ud.revision
|
|
||||||
@@ -1,91 +0,0 @@
|
|||||||
# ex:ts=4:sw=4:sts=4:et
|
|
||||||
# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
|
|
||||||
"""
|
|
||||||
BitBake 'Fetch' implementations
|
|
||||||
|
|
||||||
Classes for obtaining upstream sources for the
|
|
||||||
BitBake build tools.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
# Copyright (C) 2003, 2004 Chris Larson
|
|
||||||
#
|
|
||||||
# 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.
|
|
||||||
#
|
|
||||||
# Based on functions from the base bb module, Copyright 2003 Holger Schurig
|
|
||||||
|
|
||||||
import os
|
|
||||||
import logging
|
|
||||||
import bb
|
|
||||||
import urllib
|
|
||||||
from bb import data
|
|
||||||
from bb.fetch2 import FetchMethod
|
|
||||||
from bb.fetch2 import FetchError
|
|
||||||
from bb.fetch2 import encodeurl
|
|
||||||
from bb.fetch2 import decodeurl
|
|
||||||
from bb.fetch2 import logger
|
|
||||||
from bb.fetch2 import runfetchcmd
|
|
||||||
|
|
||||||
class Wget(FetchMethod):
|
|
||||||
"""Class to fetch urls via 'wget'"""
|
|
||||||
def supports(self, url, ud, d):
|
|
||||||
"""
|
|
||||||
Check to see if a given url can be fetched with wget.
|
|
||||||
"""
|
|
||||||
return ud.type in ['http', 'https', 'ftp']
|
|
||||||
|
|
||||||
def urldata_init(self, ud, d):
|
|
||||||
|
|
||||||
ud.basename = os.path.basename(ud.path)
|
|
||||||
ud.localfile = data.expand(urllib.unquote(ud.basename), d)
|
|
||||||
|
|
||||||
def download(self, uri, ud, d, checkonly = False):
|
|
||||||
"""Fetch urls"""
|
|
||||||
|
|
||||||
def fetch_uri(uri, ud, d):
|
|
||||||
if checkonly:
|
|
||||||
fetchcmd = data.getVar("CHECKCOMMAND", d, True)
|
|
||||||
elif os.path.exists(ud.localpath):
|
|
||||||
# file exists, but we didnt complete it.. trying again..
|
|
||||||
fetchcmd = data.getVar("RESUMECOMMAND", d, True)
|
|
||||||
else:
|
|
||||||
fetchcmd = data.getVar("FETCHCOMMAND", d, True)
|
|
||||||
|
|
||||||
uri = uri.split(";")[0]
|
|
||||||
uri_decoded = list(decodeurl(uri))
|
|
||||||
uri_type = uri_decoded[0]
|
|
||||||
uri_host = uri_decoded[1]
|
|
||||||
|
|
||||||
fetchcmd = fetchcmd.replace("${URI}", uri.split(";")[0])
|
|
||||||
fetchcmd = fetchcmd.replace("${FILE}", ud.basename)
|
|
||||||
logger.info("fetch " + uri)
|
|
||||||
logger.debug(2, "executing " + fetchcmd)
|
|
||||||
bb.fetch2.check_network_access(d, fetchcmd)
|
|
||||||
runfetchcmd(fetchcmd, d)
|
|
||||||
|
|
||||||
# Sanity check since wget can pretend it succeed when it didn't
|
|
||||||
# Also, this used to happen if sourceforge sent us to the mirror page
|
|
||||||
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)
|
|
||||||
|
|
||||||
localdata = data.createCopy(d)
|
|
||||||
data.setVar('OVERRIDES', "wget:" + data.getVar('OVERRIDES', localdata), localdata)
|
|
||||||
data.update_data(localdata)
|
|
||||||
|
|
||||||
fetch_uri(uri, ud, localdata)
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
def checkstatus(self, uri, ud, d):
|
|
||||||
return self.download(uri, ud, d, True)
|
|
||||||
@@ -23,66 +23,12 @@ Message handling infrastructure for bitbake
|
|||||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
import logging
|
|
||||||
import collections
|
import collections
|
||||||
from itertools import groupby
|
|
||||||
import warnings
|
|
||||||
import bb
|
import bb
|
||||||
import bb.event
|
import bb.event
|
||||||
|
|
||||||
class BBLogFormatter(logging.Formatter):
|
debug_level = collections.defaultdict(lambda: 0)
|
||||||
"""Formatter which ensures that our 'plain' messages (logging.INFO + 1) are used as is"""
|
verbose = False
|
||||||
|
|
||||||
DEBUG3 = logging.DEBUG - 2
|
|
||||||
DEBUG2 = logging.DEBUG - 1
|
|
||||||
DEBUG = logging.DEBUG
|
|
||||||
VERBOSE = logging.INFO - 1
|
|
||||||
NOTE = logging.INFO
|
|
||||||
PLAIN = logging.INFO + 1
|
|
||||||
ERROR = logging.ERROR
|
|
||||||
WARNING = logging.WARNING
|
|
||||||
CRITICAL = logging.CRITICAL
|
|
||||||
|
|
||||||
levelnames = {
|
|
||||||
DEBUG3 : 'DEBUG',
|
|
||||||
DEBUG2 : 'DEBUG',
|
|
||||||
DEBUG : 'DEBUG',
|
|
||||||
VERBOSE: 'NOTE',
|
|
||||||
NOTE : 'NOTE',
|
|
||||||
PLAIN : '',
|
|
||||||
WARNING : 'WARNING',
|
|
||||||
ERROR : 'ERROR',
|
|
||||||
CRITICAL: 'ERROR',
|
|
||||||
}
|
|
||||||
|
|
||||||
def getLevelName(self, levelno):
|
|
||||||
try:
|
|
||||||
return self.levelnames[levelno]
|
|
||||||
except KeyError:
|
|
||||||
self.levelnames[levelno] = value = 'Level %d' % levelno
|
|
||||||
return value
|
|
||||||
|
|
||||||
def format(self, record):
|
|
||||||
record.levelname = self.getLevelName(record.levelno)
|
|
||||||
if record.levelno == self.PLAIN:
|
|
||||||
return record.getMessage()
|
|
||||||
else:
|
|
||||||
return logging.Formatter.format(self, record)
|
|
||||||
|
|
||||||
class Loggers(dict):
|
|
||||||
def __getitem__(self, key):
|
|
||||||
if key in self:
|
|
||||||
return dict.__getitem__(self, key)
|
|
||||||
else:
|
|
||||||
log = logging.getLogger("BitBake.%s" % domain._fields[key])
|
|
||||||
dict.__setitem__(self, key, log)
|
|
||||||
return log
|
|
||||||
|
|
||||||
class DebugLevel(dict):
|
|
||||||
def __getitem__(self, key):
|
|
||||||
if key == "default":
|
|
||||||
key = domain.Default
|
|
||||||
return get_debug_level(key)
|
|
||||||
|
|
||||||
def _NamedTuple(name, fields):
|
def _NamedTuple(name, fields):
|
||||||
Tuple = collections.namedtuple(name, " ".join(fields))
|
Tuple = collections.namedtuple(name, " ".join(fields))
|
||||||
@@ -102,99 +48,97 @@ domain = _NamedTuple("Domain", (
|
|||||||
"RunQueue",
|
"RunQueue",
|
||||||
"TaskData",
|
"TaskData",
|
||||||
"Util"))
|
"Util"))
|
||||||
logger = logging.getLogger("BitBake")
|
|
||||||
loggers = Loggers()
|
|
||||||
debug_level = DebugLevel()
|
|
||||||
|
|
||||||
|
|
||||||
|
class MsgBase(bb.event.Event):
|
||||||
|
"""Base class for messages"""
|
||||||
|
|
||||||
|
def __init__(self, msg):
|
||||||
|
self._message = msg
|
||||||
|
bb.event.Event.__init__(self)
|
||||||
|
|
||||||
|
class MsgDebug(MsgBase):
|
||||||
|
"""Debug Message"""
|
||||||
|
|
||||||
|
class MsgNote(MsgBase):
|
||||||
|
"""Note Message"""
|
||||||
|
|
||||||
|
class MsgWarn(MsgBase):
|
||||||
|
"""Warning Message"""
|
||||||
|
|
||||||
|
class MsgError(MsgBase):
|
||||||
|
"""Error Message"""
|
||||||
|
|
||||||
|
class MsgFatal(MsgBase):
|
||||||
|
"""Fatal Message"""
|
||||||
|
|
||||||
|
class MsgPlain(MsgBase):
|
||||||
|
"""General output"""
|
||||||
|
|
||||||
|
#
|
||||||
# Message control functions
|
# Message control functions
|
||||||
#
|
#
|
||||||
|
|
||||||
def set_debug_level(level):
|
def set_debug_level(level):
|
||||||
for log in loggers.itervalues():
|
for d in domain:
|
||||||
log.setLevel(logging.NOTSET)
|
debug_level[d] = level
|
||||||
|
debug_level[domain.Default] = level
|
||||||
if level:
|
|
||||||
logger.setLevel(logging.DEBUG - level + 1)
|
|
||||||
else:
|
|
||||||
logger.setLevel(logging.INFO)
|
|
||||||
|
|
||||||
def get_debug_level(msgdomain = domain.Default):
|
def get_debug_level(msgdomain = domain.Default):
|
||||||
if not msgdomain:
|
return debug_level[msgdomain]
|
||||||
level = logger.getEffectiveLevel()
|
|
||||||
else:
|
|
||||||
level = loggers[msgdomain].getEffectiveLevel()
|
|
||||||
return max(0, logging.DEBUG - level + 1)
|
|
||||||
|
|
||||||
def set_verbose(level):
|
def set_verbose(level):
|
||||||
if level:
|
verbose = level
|
||||||
logger.setLevel(BBLogFormatter.VERBOSE)
|
|
||||||
else:
|
|
||||||
logger.setLevel(BBLogFormatter.INFO)
|
|
||||||
|
|
||||||
def set_debug_domains(domainargs):
|
def set_debug_domains(strdomains):
|
||||||
for (domainarg, iterator) in groupby(domainargs):
|
for domainstr in strdomains:
|
||||||
for index, msgdomain in enumerate(domain._fields):
|
for d in domain:
|
||||||
if msgdomain == domainarg:
|
if domain._fields[d] == domainstr:
|
||||||
level = len(tuple(iterator))
|
debug_level[d] += 1
|
||||||
if level:
|
|
||||||
loggers[index].setLevel(logging.DEBUG - level + 1)
|
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
warn(None, "Logging domain %s is not valid, ignoring" % domainarg)
|
warn(None, "Logging domain %s is not valid, ignoring" % domainstr)
|
||||||
|
|
||||||
#
|
#
|
||||||
# Message handling functions
|
# Message handling functions
|
||||||
#
|
#
|
||||||
|
|
||||||
def debug(level, msgdomain, msg):
|
def debug(level, msgdomain, msg, fn = None):
|
||||||
warnings.warn("bb.msg.debug will soon be deprecated in favor of the python 'logging' module",
|
|
||||||
PendingDeprecationWarning, stacklevel=2)
|
|
||||||
level = logging.DEBUG - (level - 1)
|
|
||||||
if not msgdomain:
|
if not msgdomain:
|
||||||
logger.debug(level, msg)
|
msgdomain = domain.Default
|
||||||
else:
|
|
||||||
loggers[msgdomain].debug(level, msg)
|
|
||||||
|
|
||||||
def plain(msg):
|
if debug_level[msgdomain] >= level:
|
||||||
warnings.warn("bb.msg.plain will soon be deprecated in favor of the python 'logging' module",
|
bb.event.fire(MsgDebug(msg), None)
|
||||||
PendingDeprecationWarning, stacklevel=2)
|
if bb.event.useStdout:
|
||||||
logger.plain(msg)
|
print('DEBUG: %s' % (msg))
|
||||||
|
|
||||||
def note(level, msgdomain, msg):
|
def note(level, msgdomain, msg, fn = None):
|
||||||
warnings.warn("bb.msg.note will soon be deprecated in favor of the python 'logging' module",
|
|
||||||
PendingDeprecationWarning, stacklevel=2)
|
|
||||||
if level > 1:
|
|
||||||
if msgdomain:
|
|
||||||
logger.verbose(msg)
|
|
||||||
else:
|
|
||||||
loggers[msgdomain].verbose(msg)
|
|
||||||
else:
|
|
||||||
if msgdomain:
|
|
||||||
logger.info(msg)
|
|
||||||
else:
|
|
||||||
loggers[msgdomain].info(msg)
|
|
||||||
|
|
||||||
def warn(msgdomain, msg):
|
|
||||||
warnings.warn("bb.msg.warn will soon be deprecated in favor of the python 'logging' module",
|
|
||||||
PendingDeprecationWarning, stacklevel=2)
|
|
||||||
if not msgdomain:
|
if not msgdomain:
|
||||||
logger.warn(msg)
|
msgdomain = domain.Default
|
||||||
else:
|
|
||||||
loggers[msgdomain].warn(msg)
|
|
||||||
|
|
||||||
def error(msgdomain, msg):
|
if level == 1 or verbose or debug_level[msgdomain] >= 1:
|
||||||
warnings.warn("bb.msg.error will soon be deprecated in favor of the python 'logging' module",
|
bb.event.fire(MsgNote(msg), None)
|
||||||
PendingDeprecationWarning, stacklevel=2)
|
if bb.event.useStdout:
|
||||||
if not msgdomain:
|
print('NOTE: %s' % (msg))
|
||||||
logger.error(msg)
|
|
||||||
else:
|
|
||||||
loggers[msgdomain].error(msg)
|
|
||||||
|
|
||||||
def fatal(msgdomain, msg):
|
def warn(msgdomain, msg, fn = None):
|
||||||
warnings.warn("bb.msg.fatal will soon be deprecated in favor of raising appropriate exceptions",
|
bb.event.fire(MsgWarn(msg), None)
|
||||||
PendingDeprecationWarning, stacklevel=2)
|
if bb.event.useStdout:
|
||||||
if not msgdomain:
|
print('WARNING: %s' % (msg))
|
||||||
logger.critical(msg)
|
|
||||||
else:
|
def error(msgdomain, msg, fn = None):
|
||||||
loggers[msgdomain].critical(msg)
|
bb.event.fire(MsgError(msg), None)
|
||||||
|
if bb.event.useStdout:
|
||||||
|
print('ERROR: %s' % (msg))
|
||||||
|
|
||||||
|
def fatal(msgdomain, msg, fn = None):
|
||||||
|
bb.event.fire(MsgFatal(msg), None)
|
||||||
|
|
||||||
|
if bb.event.useStdout:
|
||||||
|
print('FATAL: %s' % (msg))
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
def plain(msg, fn = None):
|
||||||
|
bb.event.fire(MsgPlain(msg), None)
|
||||||
|
if bb.event.useStdout:
|
||||||
|
print(msg)
|
||||||
|
|||||||
@@ -26,15 +26,10 @@ File parsers for the BitBake build tools.
|
|||||||
|
|
||||||
handlers = []
|
handlers = []
|
||||||
|
|
||||||
import os
|
import bb, os
|
||||||
import stat
|
|
||||||
import logging
|
|
||||||
import bb
|
|
||||||
import bb.utils
|
import bb.utils
|
||||||
import bb.siggen
|
import bb.siggen
|
||||||
|
|
||||||
logger = logging.getLogger("BitBake.Parsing")
|
|
||||||
|
|
||||||
class ParseError(Exception):
|
class ParseError(Exception):
|
||||||
"""Exception raised when parsing fails"""
|
"""Exception raised when parsing fails"""
|
||||||
|
|
||||||
@@ -44,19 +39,19 @@ class SkipPackage(Exception):
|
|||||||
__mtime_cache = {}
|
__mtime_cache = {}
|
||||||
def cached_mtime(f):
|
def cached_mtime(f):
|
||||||
if f not in __mtime_cache:
|
if f not in __mtime_cache:
|
||||||
__mtime_cache[f] = os.stat(f)[stat.ST_MTIME]
|
__mtime_cache[f] = os.stat(f)[8]
|
||||||
return __mtime_cache[f]
|
return __mtime_cache[f]
|
||||||
|
|
||||||
def cached_mtime_noerror(f):
|
def cached_mtime_noerror(f):
|
||||||
if f not in __mtime_cache:
|
if f not in __mtime_cache:
|
||||||
try:
|
try:
|
||||||
__mtime_cache[f] = os.stat(f)[stat.ST_MTIME]
|
__mtime_cache[f] = os.stat(f)[8]
|
||||||
except OSError:
|
except OSError:
|
||||||
return 0
|
return 0
|
||||||
return __mtime_cache[f]
|
return __mtime_cache[f]
|
||||||
|
|
||||||
def update_mtime(f):
|
def update_mtime(f):
|
||||||
__mtime_cache[f] = os.stat(f)[stat.ST_MTIME]
|
__mtime_cache[f] = os.stat(f)[8]
|
||||||
return __mtime_cache[f]
|
return __mtime_cache[f]
|
||||||
|
|
||||||
def mark_dependency(d, f):
|
def mark_dependency(d, f):
|
||||||
@@ -85,18 +80,18 @@ def init(fn, data):
|
|||||||
if h['supports'](fn):
|
if h['supports'](fn):
|
||||||
return h['init'](data)
|
return h['init'](data)
|
||||||
|
|
||||||
def init_parser(d):
|
def init_parser(d, dumpsigs):
|
||||||
bb.parse.siggen = bb.siggen.init(d)
|
bb.parse.siggen = bb.siggen.init(d, dumpsigs)
|
||||||
|
|
||||||
def resolve_file(fn, d):
|
def resolve_file(fn, d):
|
||||||
if not os.path.isabs(fn):
|
if not os.path.isabs(fn):
|
||||||
bbpath = bb.data.getVar("BBPATH", d, True)
|
bbpath = bb.data.getVar("BBPATH", d, True)
|
||||||
newfn = bb.utils.which(bbpath, fn)
|
newfn = bb.which(bbpath, fn)
|
||||||
if not newfn:
|
if not newfn:
|
||||||
raise IOError("file %s not found in %s" % (fn, bbpath))
|
raise IOError("file %s not found in %s" % (fn, bbpath))
|
||||||
fn = newfn
|
fn = newfn
|
||||||
|
|
||||||
logger.debug(2, "LOAD %s", fn)
|
bb.msg.debug(2, bb.msg.domain.Parsing, "LOAD %s" % fn)
|
||||||
return fn
|
return fn
|
||||||
|
|
||||||
# Used by OpenEmbedded metadata
|
# Used by OpenEmbedded metadata
|
||||||
|
|||||||
@@ -23,14 +23,11 @@
|
|||||||
|
|
||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
from future_builtins import filter
|
from future_builtins import filter
|
||||||
import re
|
import bb, re, string
|
||||||
import string
|
|
||||||
import logging
|
|
||||||
import bb
|
|
||||||
import itertools
|
|
||||||
from bb import methodpool
|
from bb import methodpool
|
||||||
from bb.parse import logger
|
import itertools
|
||||||
|
|
||||||
|
__word__ = re.compile(r"\S+")
|
||||||
__parsed_methods__ = bb.methodpool.get_parsed_dict()
|
__parsed_methods__ = bb.methodpool.get_parsed_dict()
|
||||||
_bbversions_re = re.compile(r"\[(?P<from>[0-9]+)-(?P<to>[0-9]+)\]")
|
_bbversions_re = re.compile(r"\[(?P<from>[0-9]+)-(?P<to>[0-9]+)\]")
|
||||||
|
|
||||||
@@ -40,14 +37,13 @@ class StatementGroup(list):
|
|||||||
statement.eval(data)
|
statement.eval(data)
|
||||||
|
|
||||||
class AstNode(object):
|
class AstNode(object):
|
||||||
def __init__(self, filename, lineno):
|
pass
|
||||||
self.filename = filename
|
|
||||||
self.lineno = lineno
|
|
||||||
|
|
||||||
class IncludeNode(AstNode):
|
class IncludeNode(AstNode):
|
||||||
def __init__(self, filename, lineno, what_file, force):
|
def __init__(self, what_file, fn, lineno, force):
|
||||||
AstNode.__init__(self, filename, lineno)
|
|
||||||
self.what_file = what_file
|
self.what_file = what_file
|
||||||
|
self.from_fn = fn
|
||||||
|
self.from_lineno = lineno
|
||||||
self.force = force
|
self.force = force
|
||||||
|
|
||||||
def eval(self, data):
|
def eval(self, data):
|
||||||
@@ -55,17 +51,16 @@ class IncludeNode(AstNode):
|
|||||||
Include the file and evaluate the statements
|
Include the file and evaluate the statements
|
||||||
"""
|
"""
|
||||||
s = bb.data.expand(self.what_file, data)
|
s = bb.data.expand(self.what_file, data)
|
||||||
logger.debug(2, "CONF %s:%s: including %s", self.filename, self.lineno, s)
|
bb.msg.debug(3, bb.msg.domain.Parsing, "CONF %s:%d: including %s" % (self.from_fn, self.from_lineno, s))
|
||||||
|
|
||||||
# TODO: Cache those includes... maybe not here though
|
# TODO: Cache those includes... maybe not here though
|
||||||
if self.force:
|
if self.force:
|
||||||
bb.parse.ConfHandler.include(self.filename, s, data, "include required")
|
bb.parse.ConfHandler.include(self.from_fn, s, data, "include required")
|
||||||
else:
|
else:
|
||||||
bb.parse.ConfHandler.include(self.filename, s, data, False)
|
bb.parse.ConfHandler.include(self.from_fn, s, data, False)
|
||||||
|
|
||||||
class ExportNode(AstNode):
|
class ExportNode(AstNode):
|
||||||
def __init__(self, filename, lineno, var):
|
def __init__(self, var):
|
||||||
AstNode.__init__(self, filename, lineno)
|
|
||||||
self.var = var
|
self.var = var
|
||||||
|
|
||||||
def eval(self, data):
|
def eval(self, data):
|
||||||
@@ -78,8 +73,7 @@ class DataNode(AstNode):
|
|||||||
this need to be re-evaluated... we might be able to do
|
this need to be re-evaluated... we might be able to do
|
||||||
that faster with multiple classes.
|
that faster with multiple classes.
|
||||||
"""
|
"""
|
||||||
def __init__(self, filename, lineno, groupd):
|
def __init__(self, groupd):
|
||||||
AstNode.__init__(self, filename, lineno)
|
|
||||||
self.groupd = groupd
|
self.groupd = groupd
|
||||||
|
|
||||||
def getFunc(self, key, data):
|
def getFunc(self, key, data):
|
||||||
@@ -115,22 +109,26 @@ class DataNode(AstNode):
|
|||||||
if 'flag' in groupd and groupd['flag'] != None:
|
if 'flag' in groupd and groupd['flag'] != None:
|
||||||
bb.data.setVarFlag(key, groupd['flag'], val, data)
|
bb.data.setVarFlag(key, groupd['flag'], val, data)
|
||||||
elif groupd["lazyques"]:
|
elif groupd["lazyques"]:
|
||||||
|
assigned = bb.data.getVar("__lazy_assigned", data) or []
|
||||||
|
assigned.append(key)
|
||||||
|
bb.data.setVar("__lazy_assigned", assigned, data)
|
||||||
bb.data.setVarFlag(key, "defaultval", val, data)
|
bb.data.setVarFlag(key, "defaultval", val, data)
|
||||||
else:
|
else:
|
||||||
bb.data.setVar(key, val, data)
|
bb.data.setVar(key, val, data)
|
||||||
|
|
||||||
class MethodNode(AstNode):
|
class MethodNode:
|
||||||
def __init__(self, filename, lineno, func_name, body):
|
def __init__(self, func_name, body, lineno, fn):
|
||||||
AstNode.__init__(self, filename, lineno)
|
|
||||||
self.func_name = func_name
|
self.func_name = func_name
|
||||||
self.body = body
|
self.body = body
|
||||||
|
self.fn = fn
|
||||||
|
self.lineno = lineno
|
||||||
|
|
||||||
def eval(self, data):
|
def eval(self, data):
|
||||||
if self.func_name == "__anonymous":
|
if self.func_name == "__anonymous":
|
||||||
funcname = ("__anon_%s_%s" % (self.lineno, self.filename.translate(string.maketrans('/.+-', '____'))))
|
funcname = ("__anon_%s_%s" % (self.lineno, self.fn.translate(string.maketrans('/.+-', '____'))))
|
||||||
if not funcname in bb.methodpool._parsed_fns:
|
if not funcname in bb.methodpool._parsed_fns:
|
||||||
text = "def %s(d):\n" % (funcname) + '\n'.join(self.body)
|
text = "def %s(d):\n" % (funcname) + '\n'.join(self.body)
|
||||||
bb.methodpool.insert_method(funcname, text, self.filename)
|
bb.methodpool.insert_method(funcname, text, self.fn)
|
||||||
anonfuncs = bb.data.getVar('__BBANONFUNCS', data) or []
|
anonfuncs = bb.data.getVar('__BBANONFUNCS', data) or []
|
||||||
anonfuncs.append(funcname)
|
anonfuncs.append(funcname)
|
||||||
bb.data.setVar('__BBANONFUNCS', anonfuncs, data)
|
bb.data.setVar('__BBANONFUNCS', anonfuncs, data)
|
||||||
@@ -139,26 +137,25 @@ class MethodNode(AstNode):
|
|||||||
bb.data.setVar(self.func_name, '\n'.join(self.body), data)
|
bb.data.setVar(self.func_name, '\n'.join(self.body), data)
|
||||||
|
|
||||||
class PythonMethodNode(AstNode):
|
class PythonMethodNode(AstNode):
|
||||||
def __init__(self, filename, lineno, function, define, body):
|
def __init__(self, funcname, root, body, fn):
|
||||||
AstNode.__init__(self, filename, lineno)
|
self.func_name = funcname
|
||||||
self.function = function
|
self.root = root
|
||||||
self.define = define
|
|
||||||
self.body = body
|
self.body = body
|
||||||
|
self.fn = fn
|
||||||
|
|
||||||
def eval(self, data):
|
def eval(self, data):
|
||||||
# Note we will add root to parsedmethods after having parse
|
# Note we will add root to parsedmethods after having parse
|
||||||
# 'this' file. This means we will not parse methods from
|
# 'this' file. This means we will not parse methods from
|
||||||
# bb classes twice
|
# bb classes twice
|
||||||
text = '\n'.join(self.body)
|
text = '\n'.join(self.body)
|
||||||
if not bb.methodpool.parsed_module(self.define):
|
if not bb.methodpool.parsed_module(self.root):
|
||||||
bb.methodpool.insert_method(self.define, text, self.filename)
|
bb.methodpool.insert_method(self.root, text, self.fn)
|
||||||
bb.data.setVarFlag(self.function, "func", 1, data)
|
bb.data.setVarFlag(self.func_name, "func", 1, data)
|
||||||
bb.data.setVarFlag(self.function, "python", 1, data)
|
bb.data.setVarFlag(self.func_name, "python", 1, data)
|
||||||
bb.data.setVar(self.function, text, data)
|
bb.data.setVar(self.func_name, text, data)
|
||||||
|
|
||||||
class MethodFlagsNode(AstNode):
|
class MethodFlagsNode(AstNode):
|
||||||
def __init__(self, filename, lineno, key, m):
|
def __init__(self, key, m):
|
||||||
AstNode.__init__(self, filename, lineno)
|
|
||||||
self.key = key
|
self.key = key
|
||||||
self.m = m
|
self.m = m
|
||||||
|
|
||||||
@@ -178,9 +175,8 @@ class MethodFlagsNode(AstNode):
|
|||||||
bb.data.delVarFlag(self.key, "fakeroot", data)
|
bb.data.delVarFlag(self.key, "fakeroot", data)
|
||||||
|
|
||||||
class ExportFuncsNode(AstNode):
|
class ExportFuncsNode(AstNode):
|
||||||
def __init__(self, filename, lineno, fns, classes):
|
def __init__(self, fns, classes):
|
||||||
AstNode.__init__(self, filename, lineno)
|
self.n = __word__.findall(fns)
|
||||||
self.n = fns.split()
|
|
||||||
self.classes = classes
|
self.classes = classes
|
||||||
|
|
||||||
def eval(self, data):
|
def eval(self, data):
|
||||||
@@ -218,8 +214,7 @@ class ExportFuncsNode(AstNode):
|
|||||||
bb.data.setVarFlag(var, 'export_func', '1', data)
|
bb.data.setVarFlag(var, 'export_func', '1', data)
|
||||||
|
|
||||||
class AddTaskNode(AstNode):
|
class AddTaskNode(AstNode):
|
||||||
def __init__(self, filename, lineno, func, before, after):
|
def __init__(self, func, before, after):
|
||||||
AstNode.__init__(self, filename, lineno)
|
|
||||||
self.func = func
|
self.func = func
|
||||||
self.before = before
|
self.before = before
|
||||||
self.after = after
|
self.after = after
|
||||||
@@ -250,9 +245,8 @@ class AddTaskNode(AstNode):
|
|||||||
bb.data.setVarFlag(entry, "deps", [var] + existing, data)
|
bb.data.setVarFlag(entry, "deps", [var] + existing, data)
|
||||||
|
|
||||||
class BBHandlerNode(AstNode):
|
class BBHandlerNode(AstNode):
|
||||||
def __init__(self, filename, lineno, fns):
|
def __init__(self, fns):
|
||||||
AstNode.__init__(self, filename, lineno)
|
self.hs = __word__.findall(fns)
|
||||||
self.hs = fns.split()
|
|
||||||
|
|
||||||
def eval(self, data):
|
def eval(self, data):
|
||||||
bbhands = bb.data.getVar('__BBHANDLERS', data) or []
|
bbhands = bb.data.getVar('__BBHANDLERS', data) or []
|
||||||
@@ -262,51 +256,56 @@ class BBHandlerNode(AstNode):
|
|||||||
bb.data.setVar('__BBHANDLERS', bbhands, data)
|
bb.data.setVar('__BBHANDLERS', bbhands, data)
|
||||||
|
|
||||||
class InheritNode(AstNode):
|
class InheritNode(AstNode):
|
||||||
def __init__(self, filename, lineno, classes):
|
def __init__(self, files):
|
||||||
AstNode.__init__(self, filename, lineno)
|
self.n = __word__.findall(files)
|
||||||
self.classes = classes
|
|
||||||
|
|
||||||
def eval(self, data):
|
def eval(self, data):
|
||||||
bb.parse.BBHandler.inherit(self.classes, data)
|
bb.parse.BBHandler.inherit(self.n, data)
|
||||||
|
|
||||||
def handleInclude(statements, filename, lineno, m, force):
|
def handleInclude(statements, m, fn, lineno, force):
|
||||||
statements.append(IncludeNode(filename, lineno, m.group(1), force))
|
statements.append(IncludeNode(m.group(1), fn, lineno, force))
|
||||||
|
|
||||||
def handleExport(statements, filename, lineno, m):
|
def handleExport(statements, m):
|
||||||
statements.append(ExportNode(filename, lineno, m.group(1)))
|
statements.append(ExportNode(m.group(1)))
|
||||||
|
|
||||||
def handleData(statements, filename, lineno, groupd):
|
def handleData(statements, groupd):
|
||||||
statements.append(DataNode(filename, lineno, groupd))
|
statements.append(DataNode(groupd))
|
||||||
|
|
||||||
def handleMethod(statements, filename, lineno, func_name, body):
|
def handleMethod(statements, func_name, lineno, fn, body):
|
||||||
statements.append(MethodNode(filename, lineno, func_name, body))
|
statements.append(MethodNode(func_name, body, lineno, fn))
|
||||||
|
|
||||||
def handlePythonMethod(statements, filename, lineno, funcname, root, body):
|
def handlePythonMethod(statements, funcname, root, body, fn):
|
||||||
statements.append(PythonMethodNode(filename, lineno, funcname, root, body))
|
statements.append(PythonMethodNode(funcname, root, body, fn))
|
||||||
|
|
||||||
def handleMethodFlags(statements, filename, lineno, key, m):
|
def handleMethodFlags(statements, key, m):
|
||||||
statements.append(MethodFlagsNode(filename, lineno, key, m))
|
statements.append(MethodFlagsNode(key, m))
|
||||||
|
|
||||||
def handleExportFuncs(statements, filename, lineno, m, classes):
|
def handleExportFuncs(statements, m, classes):
|
||||||
statements.append(ExportFuncsNode(filename, lineno, m.group(1), classes))
|
statements.append(ExportFuncsNode(m.group(1), classes))
|
||||||
|
|
||||||
def handleAddTask(statements, filename, lineno, m):
|
def handleAddTask(statements, m):
|
||||||
func = m.group("func")
|
func = m.group("func")
|
||||||
before = m.group("before")
|
before = m.group("before")
|
||||||
after = m.group("after")
|
after = m.group("after")
|
||||||
if func is None:
|
if func is None:
|
||||||
return
|
return
|
||||||
|
|
||||||
statements.append(AddTaskNode(filename, lineno, func, before, after))
|
statements.append(AddTaskNode(func, before, after))
|
||||||
|
|
||||||
def handleBBHandlers(statements, filename, lineno, m):
|
def handleBBHandlers(statements, m):
|
||||||
statements.append(BBHandlerNode(filename, lineno, m.group(1)))
|
statements.append(BBHandlerNode(m.group(1)))
|
||||||
|
|
||||||
def handleInherit(statements, filename, lineno, m):
|
def handleInherit(statements, m):
|
||||||
classes = m.group(1)
|
files = m.group(1)
|
||||||
statements.append(InheritNode(filename, lineno, classes.split()))
|
n = __word__.findall(files)
|
||||||
|
statements.append(InheritNode(m.group(1)))
|
||||||
|
|
||||||
def finalize(fn, d, variant = None):
|
def finalize(fn, d, variant = None):
|
||||||
|
for lazykey in bb.data.getVar("__lazy_assigned", d) or ():
|
||||||
|
if bb.data.getVar(lazykey, d) is None:
|
||||||
|
val = bb.data.getVarFlag(lazykey, "defaultval", d)
|
||||||
|
bb.data.setVar(lazykey, val, d)
|
||||||
|
|
||||||
bb.data.expandKeys(d)
|
bb.data.expandKeys(d)
|
||||||
bb.data.update_data(d)
|
bb.data.update_data(d)
|
||||||
code = []
|
code = []
|
||||||
@@ -366,7 +365,7 @@ def _expand_versions(versions):
|
|||||||
def multi_finalize(fn, d):
|
def multi_finalize(fn, d):
|
||||||
appends = (d.getVar("__BBAPPEND", True) or "").split()
|
appends = (d.getVar("__BBAPPEND", True) or "").split()
|
||||||
for append in appends:
|
for append in appends:
|
||||||
logger.debug(2, "Appending .bbappend file %s to %s", append, fn)
|
bb.msg.debug(2, bb.msg.domain.Parsing, "Appending .bbappend file " + append + " to " + fn)
|
||||||
bb.parse.BBHandler.handle(append, d, True)
|
bb.parse.BBHandler.handle(append, d, True)
|
||||||
|
|
||||||
safe_d = d
|
safe_d = d
|
||||||
|
|||||||
@@ -27,12 +27,11 @@
|
|||||||
|
|
||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
import re, bb, os
|
import re, bb, os
|
||||||
import logging
|
import bb.fetch, bb.build, bb.utils
|
||||||
import bb.build, bb.utils
|
|
||||||
from bb import data
|
from bb import data
|
||||||
|
|
||||||
from . import ConfHandler
|
from . import ConfHandler
|
||||||
from .. import resolve_file, ast, logger
|
from .. import resolve_file, ast
|
||||||
from .ConfHandler import include, init
|
from .ConfHandler import include, init
|
||||||
|
|
||||||
# For compatibility
|
# For compatibility
|
||||||
@@ -65,8 +64,7 @@ IN_PYTHON_EOF = -9999999999999
|
|||||||
|
|
||||||
|
|
||||||
def supports(fn, d):
|
def supports(fn, d):
|
||||||
"""Return True if fn has a supported extension"""
|
return fn[-3:] == ".bb" or fn[-8:] == ".bbclass" or fn[-4:] == ".inc"
|
||||||
return os.path.splitext(fn)[-1] in [".bb", ".bbclass", ".inc"]
|
|
||||||
|
|
||||||
def inherit(files, d):
|
def inherit(files, d):
|
||||||
__inherit_cache = data.getVar('__inherit_cache', d) or []
|
__inherit_cache = data.getVar('__inherit_cache', d) or []
|
||||||
@@ -74,11 +72,11 @@ def inherit(files, d):
|
|||||||
lineno = 0
|
lineno = 0
|
||||||
for file in files:
|
for file in files:
|
||||||
file = data.expand(file, d)
|
file = data.expand(file, d)
|
||||||
if not os.path.isabs(file) and not file.endswith(".bbclass"):
|
if file[0] != "/" and file[-8:] != ".bbclass":
|
||||||
file = os.path.join('classes', '%s.bbclass' % file)
|
file = os.path.join('classes', '%s.bbclass' % file)
|
||||||
|
|
||||||
if not file in __inherit_cache:
|
if not file in __inherit_cache:
|
||||||
logger.log(logging.DEBUG -1, "BB %s:%d: inheriting %s", fn, lineno, file)
|
bb.msg.debug(2, bb.msg.domain.Parsing, "BB %s:%d: inheriting %s" % (fn, lineno, file))
|
||||||
__inherit_cache.append( file )
|
__inherit_cache.append( file )
|
||||||
data.setVar('__inherit_cache', __inherit_cache, d)
|
data.setVar('__inherit_cache', __inherit_cache, d)
|
||||||
include(fn, file, d, "inherit")
|
include(fn, file, d, "inherit")
|
||||||
@@ -117,12 +115,12 @@ def handle(fn, d, include):
|
|||||||
|
|
||||||
|
|
||||||
if include == 0:
|
if include == 0:
|
||||||
logger.debug(2, "BB %s: handle(data)", fn)
|
bb.msg.debug(2, bb.msg.domain.Parsing, "BB " + fn + ": handle(data)")
|
||||||
else:
|
else:
|
||||||
logger.debug(2, "BB %s: handle(data, include)", fn)
|
bb.msg.debug(2, bb.msg.domain.Parsing, "BB " + fn + ": handle(data, include)")
|
||||||
|
|
||||||
base_name = os.path.basename(fn)
|
(root, ext) = os.path.splitext(os.path.basename(fn))
|
||||||
(root, ext) = os.path.splitext(base_name)
|
base_name = "%s%s" % (root, ext)
|
||||||
init(d)
|
init(d)
|
||||||
|
|
||||||
if ext == ".bbclass":
|
if ext == ".bbclass":
|
||||||
@@ -172,7 +170,7 @@ def feeder(lineno, s, fn, root, statements):
|
|||||||
if __infunc__:
|
if __infunc__:
|
||||||
if s == '}':
|
if s == '}':
|
||||||
__body__.append('')
|
__body__.append('')
|
||||||
ast.handleMethod(statements, fn, lineno, __infunc__, __body__)
|
ast.handleMethod(statements, __infunc__, lineno, fn, __body__)
|
||||||
__infunc__ = ""
|
__infunc__ = ""
|
||||||
__body__ = []
|
__body__ = []
|
||||||
else:
|
else:
|
||||||
@@ -185,22 +183,16 @@ def feeder(lineno, s, fn, root, statements):
|
|||||||
__body__.append(s)
|
__body__.append(s)
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
ast.handlePythonMethod(statements, fn, lineno, __inpython__,
|
ast.handlePythonMethod(statements, __inpython__, root, __body__, fn)
|
||||||
root, __body__)
|
|
||||||
__body__ = []
|
__body__ = []
|
||||||
__inpython__ = False
|
__inpython__ = False
|
||||||
|
|
||||||
if lineno == IN_PYTHON_EOF:
|
if lineno == IN_PYTHON_EOF:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# fall through
|
||||||
|
|
||||||
# Skip empty lines
|
if s == '' or s[0] == '#': return # skip comments and empty lines
|
||||||
if s == '':
|
|
||||||
return
|
|
||||||
|
|
||||||
if s[0] == '#':
|
|
||||||
if len(__residue__) != 0 and __residue__[0][0] != "#":
|
|
||||||
bb.error("There is a comment on line %s of file %s (%s) which is in the middle of a multiline expression.\nBitbake used to ignore these but no longer does so, please fix your metadata as errors are likely as a result of this change." % (lineno, fn, s))
|
|
||||||
|
|
||||||
if s[-1] == '\\':
|
if s[-1] == '\\':
|
||||||
__residue__.append(s[:-1])
|
__residue__.append(s[:-1])
|
||||||
@@ -209,14 +201,10 @@ def feeder(lineno, s, fn, root, statements):
|
|||||||
s = "".join(__residue__) + s
|
s = "".join(__residue__) + s
|
||||||
__residue__ = []
|
__residue__ = []
|
||||||
|
|
||||||
# Skip comments
|
|
||||||
if s[0] == '#':
|
|
||||||
return
|
|
||||||
|
|
||||||
m = __func_start_regexp__.match(s)
|
m = __func_start_regexp__.match(s)
|
||||||
if m:
|
if m:
|
||||||
__infunc__ = m.group("func") or "__anonymous"
|
__infunc__ = m.group("func") or "__anonymous"
|
||||||
ast.handleMethodFlags(statements, fn, lineno, __infunc__, m)
|
ast.handleMethodFlags(statements, __infunc__, m)
|
||||||
return
|
return
|
||||||
|
|
||||||
m = __def_regexp__.match(s)
|
m = __def_regexp__.match(s)
|
||||||
@@ -228,22 +216,22 @@ def feeder(lineno, s, fn, root, statements):
|
|||||||
|
|
||||||
m = __export_func_regexp__.match(s)
|
m = __export_func_regexp__.match(s)
|
||||||
if m:
|
if m:
|
||||||
ast.handleExportFuncs(statements, fn, lineno, m, classes)
|
ast.handleExportFuncs(statements, m, classes)
|
||||||
return
|
return
|
||||||
|
|
||||||
m = __addtask_regexp__.match(s)
|
m = __addtask_regexp__.match(s)
|
||||||
if m:
|
if m:
|
||||||
ast.handleAddTask(statements, fn, lineno, m)
|
ast.handleAddTask(statements, m)
|
||||||
return
|
return
|
||||||
|
|
||||||
m = __addhandler_regexp__.match(s)
|
m = __addhandler_regexp__.match(s)
|
||||||
if m:
|
if m:
|
||||||
ast.handleBBHandlers(statements, fn, lineno, m)
|
ast.handleBBHandlers(statements, m)
|
||||||
return
|
return
|
||||||
|
|
||||||
m = __inherit_regexp__.match(s)
|
m = __inherit_regexp__.match(s)
|
||||||
if m:
|
if m:
|
||||||
ast.handleInherit(statements, fn, lineno, m)
|
ast.handleInherit(statements, m)
|
||||||
return
|
return
|
||||||
|
|
||||||
return ConfHandler.feeder(lineno, s, fn, statements)
|
return ConfHandler.feeder(lineno, s, fn, statements)
|
||||||
|
|||||||
@@ -25,9 +25,8 @@
|
|||||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
import re, bb.data, os
|
import re, bb.data, os
|
||||||
import logging
|
|
||||||
import bb.utils
|
import bb.utils
|
||||||
from bb.parse import ParseError, resolve_file, ast, logger
|
from bb.parse import ParseError, resolve_file, ast
|
||||||
|
|
||||||
#__config_regexp__ = re.compile( r"(?P<exp>export\s*)?(?P<var>[a-zA-Z0-9\-_+.${}]+)\s*(?P<colon>:)?(?P<ques>\?)?=\s*(?P<apo>['\"]?)(?P<value>.*)(?P=apo)$")
|
#__config_regexp__ = re.compile( r"(?P<exp>export\s*)?(?P<var>[a-zA-Z0-9\-_+.${}]+)\s*(?P<colon>:)?(?P<ques>\?)?=\s*(?P<apo>['\"]?)(?P<value>.*)(?P=apo)$")
|
||||||
__config_regexp__ = re.compile( r"(?P<exp>export\s*)?(?P<var>[a-zA-Z0-9\-_+.${}/]+)(\[(?P<flag>[a-zA-Z0-9\-_+.]+)\])?\s*((?P<colon>:=)|(?P<lazyques>\?\?=)|(?P<ques>\?=)|(?P<append>\+=)|(?P<prepend>=\+)|(?P<predot>=\.)|(?P<postdot>\.=)|=)\s*(?P<apo>['\"]?)(?P<value>.*)(?P=apo)$")
|
__config_regexp__ = re.compile( r"(?P<exp>export\s*)?(?P<var>[a-zA-Z0-9\-_+.${}/]+)(\[(?P<flag>[a-zA-Z0-9\-_+.]+)\])?\s*((?P<colon>:=)|(?P<lazyques>\?\?=)|(?P<ques>\?=)|(?P<append>\+=)|(?P<prepend>=\+)|(?P<predot>=\.)|(?P<postdot>\.=)|=)\s*(?P<apo>['\"]?)(?P<value>.*)(?P=apo)$")
|
||||||
@@ -46,10 +45,10 @@ def supports(fn, d):
|
|||||||
|
|
||||||
def include(oldfn, fn, data, error_out):
|
def include(oldfn, fn, data, error_out):
|
||||||
"""
|
"""
|
||||||
error_out If True a ParseError will be raised if the to be included
|
|
||||||
config-files could not be included.
|
error_out If True a ParseError will be reaised if the to be included
|
||||||
"""
|
"""
|
||||||
if oldfn == fn: # prevent infinite recursion
|
if oldfn == fn: # prevent infinate recursion
|
||||||
return None
|
return None
|
||||||
|
|
||||||
import bb
|
import bb
|
||||||
@@ -69,7 +68,7 @@ def include(oldfn, fn, data, error_out):
|
|||||||
except IOError:
|
except IOError:
|
||||||
if error_out:
|
if error_out:
|
||||||
raise ParseError("Could not %(error_out)s file %(fn)s" % vars() )
|
raise ParseError("Could not %(error_out)s file %(fn)s" % vars() )
|
||||||
logger.debug(2, "CONF file '%s' not found", fn)
|
bb.msg.debug(2, bb.msg.domain.Parsing, "CONF file '%s' not found" % fn)
|
||||||
|
|
||||||
def handle(fn, data, include):
|
def handle(fn, data, include):
|
||||||
init(data)
|
init(data)
|
||||||
@@ -113,22 +112,22 @@ def feeder(lineno, s, fn, statements):
|
|||||||
m = __config_regexp__.match(s)
|
m = __config_regexp__.match(s)
|
||||||
if m:
|
if m:
|
||||||
groupd = m.groupdict()
|
groupd = m.groupdict()
|
||||||
ast.handleData(statements, fn, lineno, groupd)
|
ast.handleData(statements, groupd)
|
||||||
return
|
return
|
||||||
|
|
||||||
m = __include_regexp__.match(s)
|
m = __include_regexp__.match(s)
|
||||||
if m:
|
if m:
|
||||||
ast.handleInclude(statements, fn, lineno, m, False)
|
ast.handleInclude(statements, m, fn, lineno, False)
|
||||||
return
|
return
|
||||||
|
|
||||||
m = __require_regexp__.match(s)
|
m = __require_regexp__.match(s)
|
||||||
if m:
|
if m:
|
||||||
ast.handleInclude(statements, fn, lineno, m, True)
|
ast.handleInclude(statements, m, fn, lineno, True)
|
||||||
return
|
return
|
||||||
|
|
||||||
m = __export_regexp__.match(s)
|
m = __export_regexp__.match(s)
|
||||||
if m:
|
if m:
|
||||||
ast.handleExport(statements, fn, lineno, m)
|
ast.handleExport(statements, m)
|
||||||
return
|
return
|
||||||
|
|
||||||
raise ParseError("%s:%d: unparsed line: '%s'" % (fn, lineno, s));
|
raise ParseError("%s:%d: unparsed line: '%s'" % (fn, lineno, s));
|
||||||
|
|||||||
@@ -1,12 +1,6 @@
|
|||||||
"""BitBake Persistent Data Store
|
# BitBake Persistent Data Store
|
||||||
|
#
|
||||||
Used to store data in a central location such that other threads/tasks can
|
|
||||||
access them at some future date. Acts as a convenience wrapper around sqlite,
|
|
||||||
currently, providing a key/value store accessed by 'domain'.
|
|
||||||
"""
|
|
||||||
|
|
||||||
# Copyright (C) 2007 Richard Purdie
|
# Copyright (C) 2007 Richard Purdie
|
||||||
# Copyright (C) 2010 Chris Larson <chris_larson@mentor.com>
|
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or modify
|
# 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
|
# it under the terms of the GNU General Public License version 2 as
|
||||||
@@ -21,174 +15,119 @@ currently, providing a key/value store accessed by 'domain'.
|
|||||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
import collections
|
import bb, os
|
||||||
import logging
|
import bb.utils
|
||||||
import os.path
|
|
||||||
import sys
|
|
||||||
import warnings
|
|
||||||
import bb.msg, bb.data, bb.utils
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import sqlite3
|
import sqlite3
|
||||||
except ImportError:
|
except ImportError:
|
||||||
from pysqlite2 import dbapi2 as sqlite3
|
try:
|
||||||
|
from pysqlite2 import dbapi2 as sqlite3
|
||||||
|
except ImportError:
|
||||||
|
bb.msg.fatal(bb.msg.domain.PersistData, "Importing sqlite3 and pysqlite2 failed, please install one of them. Python 2.5 or a 'python-pysqlite2' like package is likely to be what you need.")
|
||||||
|
|
||||||
sqlversion = sqlite3.sqlite_version_info
|
sqlversion = sqlite3.sqlite_version_info
|
||||||
if sqlversion[0] < 3 or (sqlversion[0] == 3 and sqlversion[1] < 3):
|
if sqlversion[0] < 3 or (sqlversion[0] == 3 and sqlversion[1] < 3):
|
||||||
raise Exception("sqlite3 version 3.3.0 or later is required.")
|
bb.msg.fatal(bb.msg.domain.PersistData, "sqlite3 version 3.3.0 or later is required.")
|
||||||
|
|
||||||
|
class PersistData:
|
||||||
|
"""
|
||||||
|
BitBake Persistent Data Store
|
||||||
|
|
||||||
logger = logging.getLogger("BitBake.PersistData")
|
Used to store data in a central location such that other threads/tasks can
|
||||||
|
access them at some future date.
|
||||||
|
|
||||||
|
The "domain" is used as a key to isolate each data pool and in this
|
||||||
|
implementation corresponds to an SQL table. The SQL table consists of a
|
||||||
|
simple key and value pair.
|
||||||
|
|
||||||
class SQLTable(collections.MutableMapping):
|
Why sqlite? It handles all the locking issues for us.
|
||||||
"""Object representing a table/domain in the database"""
|
"""
|
||||||
def __init__(self, cursor, table):
|
def __init__(self, d, persistent_database_connection):
|
||||||
self.cursor = cursor
|
if "connection" in persistent_database_connection:
|
||||||
self.table = table
|
self.cursor = persistent_database_connection["connection"].cursor()
|
||||||
|
return
|
||||||
|
self.cachedir = bb.data.getVar("PERSISTENT_DIR", d, True) or bb.data.getVar("CACHE", d, True)
|
||||||
|
if self.cachedir in [None, '']:
|
||||||
|
bb.msg.fatal(bb.msg.domain.PersistData, "Please set the 'PERSISTENT_DIR' or 'CACHE' variable.")
|
||||||
|
try:
|
||||||
|
os.stat(self.cachedir)
|
||||||
|
except OSError:
|
||||||
|
bb.utils.mkdirhier(self.cachedir)
|
||||||
|
|
||||||
self._execute("CREATE TABLE IF NOT EXISTS %s(key TEXT, value TEXT);"
|
self.cachefile = os.path.join(self.cachedir, "bb_persist_data.sqlite3")
|
||||||
% table)
|
bb.msg.debug(1, bb.msg.domain.PersistData, "Using '%s' as the persistent data cache" % self.cachefile)
|
||||||
|
|
||||||
def _execute(self, *query):
|
connection = sqlite3.connect(self.cachefile, timeout=5, isolation_level=None)
|
||||||
"""Execute a query, waiting to acquire a lock if necessary"""
|
persistent_database_connection["connection"] = connection
|
||||||
count = 0
|
self.cursor = persistent_database_connection["connection"].cursor()
|
||||||
while True:
|
|
||||||
try:
|
|
||||||
return self.cursor.execute(*query)
|
|
||||||
except sqlite3.OperationalError as exc:
|
|
||||||
if 'database is locked' in str(exc) and count < 500:
|
|
||||||
count = count + 1
|
|
||||||
continue
|
|
||||||
raise
|
|
||||||
|
|
||||||
def __getitem__(self, key):
|
|
||||||
data = self._execute("SELECT * from %s where key=?;" %
|
|
||||||
self.table, [key])
|
|
||||||
for row in data:
|
|
||||||
return row[1]
|
|
||||||
|
|
||||||
def __delitem__(self, key):
|
|
||||||
self._execute("DELETE from %s where key=?;" % self.table, [key])
|
|
||||||
|
|
||||||
def __setitem__(self, key, value):
|
|
||||||
data = self._execute("SELECT * from %s where key=?;" %
|
|
||||||
self.table, [key])
|
|
||||||
exists = len(list(data))
|
|
||||||
if exists:
|
|
||||||
self._execute("UPDATE %s SET value=? WHERE key=?;" % self.table,
|
|
||||||
[value, key])
|
|
||||||
else:
|
|
||||||
self._execute("INSERT into %s(key, value) values (?, ?);" %
|
|
||||||
self.table, [key, value])
|
|
||||||
|
|
||||||
def __contains__(self, key):
|
|
||||||
return key in set(self)
|
|
||||||
|
|
||||||
def __len__(self):
|
|
||||||
data = self._execute("SELECT COUNT(key) FROM %s;" % self.table)
|
|
||||||
for row in data:
|
|
||||||
return row[0]
|
|
||||||
|
|
||||||
def __iter__(self):
|
|
||||||
data = self._execute("SELECT key FROM %s;" % self.table)
|
|
||||||
for row in data:
|
|
||||||
yield row[0]
|
|
||||||
|
|
||||||
def iteritems(self):
|
|
||||||
data = self._execute("SELECT * FROM %s;" % self.table)
|
|
||||||
for row in data:
|
|
||||||
yield row[0], row[1]
|
|
||||||
|
|
||||||
def itervalues(self):
|
|
||||||
data = self._execute("SELECT value FROM %s;" % self.table)
|
|
||||||
for row in data:
|
|
||||||
yield row[0]
|
|
||||||
|
|
||||||
|
|
||||||
class SQLData(object):
|
|
||||||
"""Object representing the persistent data"""
|
|
||||||
def __init__(self, filename):
|
|
||||||
bb.utils.mkdirhier(os.path.dirname(filename))
|
|
||||||
|
|
||||||
self.filename = filename
|
|
||||||
self.connection = sqlite3.connect(filename, timeout=5,
|
|
||||||
isolation_level=None)
|
|
||||||
self.cursor = self.connection.cursor()
|
|
||||||
self._tables = {}
|
|
||||||
|
|
||||||
def __getitem__(self, table):
|
|
||||||
if not isinstance(table, basestring):
|
|
||||||
raise TypeError("table argument must be a string, not '%s'" %
|
|
||||||
type(table))
|
|
||||||
|
|
||||||
if table in self._tables:
|
|
||||||
return self._tables[table]
|
|
||||||
else:
|
|
||||||
tableobj = self._tables[table] = SQLTable(self.cursor, table)
|
|
||||||
return tableobj
|
|
||||||
|
|
||||||
def __delitem__(self, table):
|
|
||||||
if table in self._tables:
|
|
||||||
del self._tables[table]
|
|
||||||
self.cursor.execute("DROP TABLE IF EXISTS %s;" % table)
|
|
||||||
|
|
||||||
|
|
||||||
class PersistData(object):
|
|
||||||
"""Deprecated representation of the bitbake persistent data store"""
|
|
||||||
def __init__(self, d):
|
|
||||||
warnings.warn("Use of PersistData will be deprecated in the future",
|
|
||||||
category=PendingDeprecationWarning,
|
|
||||||
stacklevel=2)
|
|
||||||
|
|
||||||
self.data = persist(d)
|
|
||||||
logger.debug(1, "Using '%s' as the persistent data cache",
|
|
||||||
self.data.filename)
|
|
||||||
|
|
||||||
def addDomain(self, domain):
|
def addDomain(self, domain):
|
||||||
"""
|
"""
|
||||||
Add a domain (pending deprecation)
|
Should be called before any domain is used
|
||||||
|
Creates it if it doesn't exist.
|
||||||
"""
|
"""
|
||||||
return self.data[domain]
|
self._execute("CREATE TABLE IF NOT EXISTS %s(key TEXT, value TEXT);" % domain)
|
||||||
|
|
||||||
def delDomain(self, domain):
|
def delDomain(self, domain):
|
||||||
"""
|
"""
|
||||||
Removes a domain and all the data it contains
|
Removes a domain and all the data it contains
|
||||||
"""
|
"""
|
||||||
del self.data[domain]
|
self._execute("DROP TABLE IF EXISTS %s;" % domain)
|
||||||
|
|
||||||
def getKeyValues(self, domain):
|
def getKeyValues(self, domain):
|
||||||
"""
|
"""
|
||||||
Return a list of key + value pairs for a domain
|
Return a list of key + value pairs for a domain
|
||||||
"""
|
"""
|
||||||
return self.data[domain].items()
|
ret = {}
|
||||||
|
data = self._execute("SELECT key, value from %s;" % domain)
|
||||||
|
for row in data:
|
||||||
|
ret[str(row[0])] = str(row[1])
|
||||||
|
|
||||||
|
return ret
|
||||||
|
|
||||||
def getValue(self, domain, key):
|
def getValue(self, domain, key):
|
||||||
"""
|
"""
|
||||||
Return the value of a key for a domain
|
Return the value of a key for a domain
|
||||||
"""
|
"""
|
||||||
return self.data[domain][key]
|
data = self._execute("SELECT * from %s where key=?;" % domain, [key])
|
||||||
|
for row in data:
|
||||||
|
return row[1]
|
||||||
|
|
||||||
def setValue(self, domain, key, value):
|
def setValue(self, domain, key, value):
|
||||||
"""
|
"""
|
||||||
Sets the value of a key for a domain
|
Sets the value of a key for a domain
|
||||||
"""
|
"""
|
||||||
self.data[domain][key] = value
|
data = self._execute("SELECT * from %s where key=?;" % domain, [key])
|
||||||
|
rows = 0
|
||||||
|
for row in data:
|
||||||
|
rows = rows + 1
|
||||||
|
if rows:
|
||||||
|
self._execute("UPDATE %s SET value=? WHERE key=?;" % domain, [value, key])
|
||||||
|
else:
|
||||||
|
self._execute("INSERT into %s(key, value) values (?, ?);" % domain, [key, value])
|
||||||
|
|
||||||
def delValue(self, domain, key):
|
def delValue(self, domain, key):
|
||||||
"""
|
"""
|
||||||
Deletes a key/value pair
|
Deletes a key/value pair
|
||||||
"""
|
"""
|
||||||
del self.data[domain][key]
|
self._execute("DELETE from %s where key=?;" % domain, [key])
|
||||||
|
|
||||||
|
#
|
||||||
def persist(d):
|
# We wrap the sqlite execute calls as on contended machines or single threaded
|
||||||
"""Convenience factory for construction of SQLData based upon metadata"""
|
# systems we can have multiple processes trying to access the DB at once and it seems
|
||||||
cachedir = (bb.data.getVar("PERSISTENT_DIR", d, True) or
|
# sqlite sometimes doesn't wait for the timeout. We therefore loop but put in an
|
||||||
bb.data.getVar("CACHE", d, True))
|
# emergency brake too
|
||||||
if not cachedir:
|
#
|
||||||
logger.critical("Please set the 'PERSISTENT_DIR' or 'CACHE' variable")
|
def _execute(self, *query):
|
||||||
sys.exit(1)
|
count = 0
|
||||||
|
while True:
|
||||||
cachefile = os.path.join(cachedir, "bb_persist_data.sqlite3")
|
try:
|
||||||
return SQLData(cachefile)
|
ret = self.cursor.execute(*query)
|
||||||
|
#print "Had to retry %s times" % count
|
||||||
|
return ret
|
||||||
|
except sqlite3.OperationalError as e:
|
||||||
|
if 'database is locked' in str(e) and count < 500:
|
||||||
|
count = count + 1
|
||||||
|
continue
|
||||||
|
raise
|
||||||
|
|||||||
@@ -1,109 +0,0 @@
|
|||||||
import logging
|
|
||||||
import signal
|
|
||||||
import subprocess
|
|
||||||
|
|
||||||
logger = logging.getLogger('BitBake.Process')
|
|
||||||
|
|
||||||
def subprocess_setup():
|
|
||||||
# Python installs a SIGPIPE handler by default. This is usually not what
|
|
||||||
# non-Python subprocesses expect.
|
|
||||||
signal.signal(signal.SIGPIPE, signal.SIG_DFL)
|
|
||||||
|
|
||||||
class CmdError(RuntimeError):
|
|
||||||
def __init__(self, command, msg=None):
|
|
||||||
self.command = command
|
|
||||||
self.msg = msg
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
if not isinstance(self.command, basestring):
|
|
||||||
cmd = subprocess.list2cmdline(self.command)
|
|
||||||
else:
|
|
||||||
cmd = self.command
|
|
||||||
|
|
||||||
msg = "Execution of '%s' failed" % cmd
|
|
||||||
if self.msg:
|
|
||||||
msg += ': %s' % self.msg
|
|
||||||
return msg
|
|
||||||
|
|
||||||
class NotFoundError(CmdError):
|
|
||||||
def __str__(self):
|
|
||||||
return CmdError.__str__(self) + ": command not found"
|
|
||||||
|
|
||||||
class ExecutionError(CmdError):
|
|
||||||
def __init__(self, command, exitcode, stdout = None, stderr = None):
|
|
||||||
CmdError.__init__(self, command)
|
|
||||||
self.exitcode = exitcode
|
|
||||||
self.stdout = stdout
|
|
||||||
self.stderr = stderr
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
message = ""
|
|
||||||
if self.stderr:
|
|
||||||
message += self.stderr
|
|
||||||
if self.stdout:
|
|
||||||
message += self.stdout
|
|
||||||
if message:
|
|
||||||
message = ":\n" + message
|
|
||||||
return (CmdError.__str__(self) +
|
|
||||||
" with exit code %s" % self.exitcode + message)
|
|
||||||
|
|
||||||
class Popen(subprocess.Popen):
|
|
||||||
defaults = {
|
|
||||||
"close_fds": True,
|
|
||||||
"preexec_fn": subprocess_setup,
|
|
||||||
"stdout": subprocess.PIPE,
|
|
||||||
"stderr": subprocess.STDOUT,
|
|
||||||
"stdin": subprocess.PIPE,
|
|
||||||
"shell": False,
|
|
||||||
}
|
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
options = dict(self.defaults)
|
|
||||||
options.update(kwargs)
|
|
||||||
subprocess.Popen.__init__(self, *args, **options)
|
|
||||||
|
|
||||||
def _logged_communicate(pipe, log, input):
|
|
||||||
if pipe.stdin:
|
|
||||||
if input is not None:
|
|
||||||
pipe.stdin.write(input)
|
|
||||||
pipe.stdin.close()
|
|
||||||
|
|
||||||
bufsize = 512
|
|
||||||
outdata, errdata = [], []
|
|
||||||
while pipe.poll() is None:
|
|
||||||
if pipe.stdout is not None:
|
|
||||||
data = pipe.stdout.read(bufsize)
|
|
||||||
if data is not None:
|
|
||||||
outdata.append(data)
|
|
||||||
log.write(data)
|
|
||||||
|
|
||||||
if pipe.stderr is not None:
|
|
||||||
data = pipe.stderr.read(bufsize)
|
|
||||||
if data is not None:
|
|
||||||
errdata.append(data)
|
|
||||||
log.write(data)
|
|
||||||
return ''.join(outdata), ''.join(errdata)
|
|
||||||
|
|
||||||
def run(cmd, input=None, log=None, **options):
|
|
||||||
"""Convenience function to run a command and return its output, raising an
|
|
||||||
exception when the command fails"""
|
|
||||||
|
|
||||||
if isinstance(cmd, basestring) and not "shell" in options:
|
|
||||||
options["shell"] = True
|
|
||||||
|
|
||||||
try:
|
|
||||||
pipe = Popen(cmd, **options)
|
|
||||||
except OSError, exc:
|
|
||||||
if exc.errno == 2:
|
|
||||||
raise NotFoundError(cmd)
|
|
||||||
else:
|
|
||||||
raise CmdError(cmd, exc)
|
|
||||||
|
|
||||||
if log:
|
|
||||||
stdout, stderr = _logged_communicate(pipe, log, input)
|
|
||||||
else:
|
|
||||||
stdout, stderr = pipe.communicate(input)
|
|
||||||
|
|
||||||
if pipe.returncode != 0:
|
|
||||||
raise ExecutionError(cmd, pipe.returncode, stdout, stderr)
|
|
||||||
return stdout, stderr
|
|
||||||
@@ -22,12 +22,9 @@
|
|||||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
import re
|
import re
|
||||||
import logging
|
|
||||||
from bb import data, utils
|
from bb import data, utils
|
||||||
import bb
|
import bb
|
||||||
|
|
||||||
logger = logging.getLogger("BitBake.Provider")
|
|
||||||
|
|
||||||
class NoProvider(Exception):
|
class NoProvider(Exception):
|
||||||
"""Exception raised when no provider of a build dependency can be found"""
|
"""Exception raised when no provider of a build dependency can be found"""
|
||||||
|
|
||||||
@@ -123,9 +120,9 @@ def findPreferredProvider(pn, cfgData, dataCache, pkg_pn = None, item = None):
|
|||||||
if item:
|
if item:
|
||||||
itemstr = " (for item %s)" % item
|
itemstr = " (for item %s)" % item
|
||||||
if preferred_file is None:
|
if preferred_file is None:
|
||||||
logger.info("preferred version %s of %s not available%s", pv_str, pn, itemstr)
|
bb.msg.note(1, bb.msg.domain.Provider, "preferred version %s of %s not available%s" % (pv_str, pn, itemstr))
|
||||||
else:
|
else:
|
||||||
logger.debug(1, "selecting %s as PREFERRED_VERSION %s of package %s%s", preferred_file, pv_str, pn, itemstr)
|
bb.msg.debug(1, bb.msg.domain.Provider, "selecting %s as PREFERRED_VERSION %s of package %s%s" % (preferred_file, pv_str, pn, itemstr))
|
||||||
|
|
||||||
return (preferred_ver, preferred_file)
|
return (preferred_ver, preferred_file)
|
||||||
|
|
||||||
@@ -192,7 +189,7 @@ def _filterProviders(providers, item, cfgData, dataCache):
|
|||||||
pkg_pn[pn] = []
|
pkg_pn[pn] = []
|
||||||
pkg_pn[pn].append(p)
|
pkg_pn[pn].append(p)
|
||||||
|
|
||||||
logger.debug(1, "providers for %s are: %s", item, pkg_pn.keys())
|
bb.msg.debug(1, bb.msg.domain.Provider, "providers for %s are: %s" % (item, pkg_pn.keys()))
|
||||||
|
|
||||||
# First add PREFERRED_VERSIONS
|
# First add PREFERRED_VERSIONS
|
||||||
for pn in pkg_pn:
|
for pn in pkg_pn:
|
||||||
@@ -209,7 +206,7 @@ def _filterProviders(providers, item, cfgData, dataCache):
|
|||||||
eligible.append(preferred_versions[pn][1])
|
eligible.append(preferred_versions[pn][1])
|
||||||
|
|
||||||
if len(eligible) == 0:
|
if len(eligible) == 0:
|
||||||
logger.error("no eligible providers for %s", item)
|
bb.msg.error(bb.msg.domain.Provider, "no eligible providers for %s" % item)
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
# If pn == item, give it a slight default preference
|
# If pn == item, give it a slight default preference
|
||||||
@@ -245,13 +242,13 @@ def filterProviders(providers, item, cfgData, dataCache):
|
|||||||
for p in eligible:
|
for p in eligible:
|
||||||
pn = dataCache.pkg_fn[p]
|
pn = dataCache.pkg_fn[p]
|
||||||
if dataCache.preferred[item] == pn:
|
if dataCache.preferred[item] == pn:
|
||||||
logger.verbose("selecting %s to satisfy %s due to PREFERRED_PROVIDERS", pn, item)
|
bb.msg.note(2, bb.msg.domain.Provider, "selecting %s to satisfy %s due to PREFERRED_PROVIDERS" % (pn, item))
|
||||||
eligible.remove(p)
|
eligible.remove(p)
|
||||||
eligible = [p] + eligible
|
eligible = [p] + eligible
|
||||||
foundUnique = True
|
foundUnique = True
|
||||||
break
|
break
|
||||||
|
|
||||||
logger.debug(1, "sorted providers for %s are: %s", item, eligible)
|
bb.msg.debug(1, bb.msg.domain.Provider, "sorted providers for %s are: %s" % (item, eligible))
|
||||||
|
|
||||||
return eligible, foundUnique
|
return eligible, foundUnique
|
||||||
|
|
||||||
@@ -267,31 +264,27 @@ def filterProvidersRunTime(providers, item, cfgData, dataCache):
|
|||||||
# Should use dataCache.preferred here?
|
# Should use dataCache.preferred here?
|
||||||
preferred = []
|
preferred = []
|
||||||
preferred_vars = []
|
preferred_vars = []
|
||||||
pns = {}
|
|
||||||
for p in eligible:
|
|
||||||
pns[dataCache.pkg_fn[p]] = p
|
|
||||||
for p in eligible:
|
for p in eligible:
|
||||||
pn = dataCache.pkg_fn[p]
|
pn = dataCache.pkg_fn[p]
|
||||||
provides = dataCache.pn_provides[pn]
|
provides = dataCache.pn_provides[pn]
|
||||||
for provide in provides:
|
for provide in provides:
|
||||||
|
bb.msg.note(2, bb.msg.domain.Provider, "checking PREFERRED_PROVIDER_%s" % (provide))
|
||||||
prefervar = bb.data.getVar('PREFERRED_PROVIDER_%s' % provide, cfgData, 1)
|
prefervar = bb.data.getVar('PREFERRED_PROVIDER_%s' % provide, cfgData, 1)
|
||||||
logger.verbose("checking PREFERRED_PROVIDER_%s (value %s) against %s", provide, prefervar, pns.keys())
|
if prefervar == pn:
|
||||||
if prefervar in pns and pns[prefervar] not in preferred:
|
|
||||||
var = "PREFERRED_PROVIDER_%s = %s" % (provide, prefervar)
|
var = "PREFERRED_PROVIDER_%s = %s" % (provide, prefervar)
|
||||||
logger.verbose("selecting %s to satisfy runtime %s due to %s", prefervar, item, var)
|
bb.msg.note(2, bb.msg.domain.Provider, "selecting %s to satisfy runtime %s due to %s" % (pn, item, var))
|
||||||
preferred_vars.append(var)
|
preferred_vars.append(var)
|
||||||
pref = pns[prefervar]
|
eligible.remove(p)
|
||||||
eligible.remove(pref)
|
eligible = [p] + eligible
|
||||||
eligible = [pref] + eligible
|
preferred.append(p)
|
||||||
preferred.append(pref)
|
|
||||||
break
|
break
|
||||||
|
|
||||||
numberPreferred = len(preferred)
|
numberPreferred = len(preferred)
|
||||||
|
|
||||||
if numberPreferred > 1:
|
if numberPreferred > 1:
|
||||||
logger.error("Trying to resolve runtime dependency %s resulted in conflicting PREFERRED_PROVIDER entries being found.\nThe providers found were: %s\nThe PREFERRED_PROVIDER entries resulting in this conflict were: %s", item, preferred, preferred_vars)
|
bb.msg.error(bb.msg.domain.Provider, "Conflicting PREFERRED_PROVIDER entries were found which resulted in an attempt to select multiple providers (%s) for runtime dependecy %s\nThe entries resulting in this conflict were: %s" % (preferred, item, preferred_vars))
|
||||||
|
|
||||||
logger.debug(1, "sorted providers for %s are: %s", item, eligible)
|
bb.msg.debug(1, bb.msg.domain.Provider, "sorted providers for %s are: %s" % (item, eligible))
|
||||||
|
|
||||||
return eligible, numberPreferred
|
return eligible, numberPreferred
|
||||||
|
|
||||||
@@ -321,7 +314,7 @@ def getRuntimeProviders(dataCache, rdepend):
|
|||||||
try:
|
try:
|
||||||
regexp = re.compile(pattern)
|
regexp = re.compile(pattern)
|
||||||
except:
|
except:
|
||||||
logger.error("Error parsing regular expression '%s'", pattern)
|
bb.msg.error(bb.msg.domain.Provider, "Error parsing re expression: %s" % pattern)
|
||||||
raise
|
raise
|
||||||
regexp_cache[pattern] = regexp
|
regexp_cache[pattern] = regexp
|
||||||
if regexp.match(rdepend):
|
if regexp.match(rdepend):
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -18,21 +18,28 @@
|
|||||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
This module implements a passthrough server for BitBake.
|
This module implements an xmlrpc server for BitBake.
|
||||||
|
|
||||||
Use register_idle_function() to add a function which the server
|
Use this by deriving a class from BitBakeXMLRPCServer and then adding
|
||||||
calls from within idle_commands when no requests are pending. Make sure
|
methods which you want to "export" via XMLRPC. If the methods have the
|
||||||
|
prefix xmlrpc_, then registering those function will happen automatically,
|
||||||
|
if not, you need to call register_function.
|
||||||
|
|
||||||
|
Use register_idle_function() to add a function which the xmlrpc server
|
||||||
|
calls from within server_forever when no requests are pending. Make sure
|
||||||
that those functions are non-blocking or else you will introduce latency
|
that those functions are non-blocking or else you will introduce latency
|
||||||
in the server's main loop.
|
in the server's main loop.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import time
|
import time
|
||||||
import bb
|
import bb
|
||||||
|
from bb.ui import uievent
|
||||||
|
import xmlrpclib
|
||||||
import pickle
|
import pickle
|
||||||
import signal
|
|
||||||
|
|
||||||
DEBUG = False
|
DEBUG = False
|
||||||
|
|
||||||
|
from SimpleXMLRPCServer import SimpleXMLRPCServer, SimpleXMLRPCRequestHandler
|
||||||
import inspect, select
|
import inspect, select
|
||||||
|
|
||||||
class BitBakeServerCommands():
|
class BitBakeServerCommands():
|
||||||
@@ -79,22 +86,18 @@ class BBUIEventQueue:
|
|||||||
self.BBServer = BBServer
|
self.BBServer = BBServer
|
||||||
self.EventHandle = bb.event.register_UIHhandler(self)
|
self.EventHandle = bb.event.register_UIHhandler(self)
|
||||||
|
|
||||||
def __popEvent(self):
|
|
||||||
if len(self.eventQueue) == 0:
|
|
||||||
return None
|
|
||||||
return self.eventQueue.pop(0)
|
|
||||||
|
|
||||||
def getEvent(self):
|
def getEvent(self):
|
||||||
if len(self.eventQueue) == 0:
|
if len(self.eventQueue) == 0:
|
||||||
self.BBServer.idle_commands(0)
|
return None
|
||||||
return self.__popEvent()
|
|
||||||
|
return self.eventQueue.pop(0)
|
||||||
|
|
||||||
def waitEvent(self, delay):
|
def waitEvent(self, delay):
|
||||||
event = self.__popEvent()
|
event = self.getEvent()
|
||||||
if event:
|
if event:
|
||||||
return event
|
return event
|
||||||
self.BBServer.idle_commands(delay)
|
self.BBServer.idle_commands(delay)
|
||||||
return self.__popEvent()
|
return self.getEvent()
|
||||||
|
|
||||||
def queue_event(self, event):
|
def queue_event(self, event):
|
||||||
self.eventQueue.append(event)
|
self.eventQueue.append(event)
|
||||||
@@ -102,10 +105,6 @@ class BBUIEventQueue:
|
|||||||
def system_quit( self ):
|
def system_quit( self ):
|
||||||
bb.event.unregister_UIHhandler(self.EventHandle)
|
bb.event.unregister_UIHhandler(self.EventHandle)
|
||||||
|
|
||||||
# Dummy signal handler to ensure we break out of sleep upon SIGCHLD
|
|
||||||
def chldhandler(signum, stackframe):
|
|
||||||
pass
|
|
||||||
|
|
||||||
class BitBakeServer():
|
class BitBakeServer():
|
||||||
# remove this when you're done with debugging
|
# remove this when you're done with debugging
|
||||||
# allow_reuse_address = True
|
# allow_reuse_address = True
|
||||||
@@ -145,9 +144,7 @@ class BitBakeServer():
|
|||||||
pass
|
pass
|
||||||
if nextsleep is not None:
|
if nextsleep is not None:
|
||||||
#print "Sleeping for %s (%s)" % (nextsleep, delay)
|
#print "Sleeping for %s (%s)" % (nextsleep, delay)
|
||||||
signal.signal(signal.SIGCHLD, chldhandler)
|
|
||||||
time.sleep(nextsleep)
|
time.sleep(nextsleep)
|
||||||
signal.signal(signal.SIGCHLD, signal.SIG_DFL)
|
|
||||||
|
|
||||||
def server_exit(self):
|
def server_exit(self):
|
||||||
# Tell idle functions we're exiting
|
# Tell idle functions we're exiting
|
||||||
@@ -163,22 +160,15 @@ class BitbakeServerInfo():
|
|||||||
self.commands = server.commands
|
self.commands = server.commands
|
||||||
|
|
||||||
class BitBakeServerFork():
|
class BitBakeServerFork():
|
||||||
def __init__(self, cooker, server, serverinfo, logfile):
|
def __init__(self, serverinfo, command, logfile):
|
||||||
|
serverinfo.forkCommand = command
|
||||||
serverinfo.logfile = logfile
|
serverinfo.logfile = logfile
|
||||||
serverinfo.cooker = cooker
|
|
||||||
serverinfo.server = server
|
|
||||||
|
|
||||||
class BitbakeUILauch():
|
|
||||||
def launch(self, serverinfo, uifunc, *args):
|
|
||||||
return bb.cooker.server_main(serverinfo.cooker, uifunc, *args)
|
|
||||||
|
|
||||||
class BitBakeServerConnection():
|
class BitBakeServerConnection():
|
||||||
def __init__(self, serverinfo):
|
def __init__(self, serverinfo):
|
||||||
self.server = serverinfo.server
|
self.server = serverinfo.server
|
||||||
self.connection = serverinfo.commands
|
self.connection = serverinfo.commands
|
||||||
self.events = bb.server.none.BBUIEventQueue(self.server)
|
self.events = bb.server.none.BBUIEventQueue(self.server)
|
||||||
for event in bb.event.ui_queue:
|
|
||||||
self.events.queue_event(event)
|
|
||||||
|
|
||||||
def terminate(self):
|
def terminate(self):
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -45,82 +45,6 @@ if sys.hexversion < 0x020600F0:
|
|||||||
print("Sorry, python 2.6 or later is required for bitbake's XMLRPC mode")
|
print("Sorry, python 2.6 or later is required for bitbake's XMLRPC mode")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
##
|
|
||||||
# The xmlrpclib.Transport class has undergone various changes in Python 2.7
|
|
||||||
# which break BitBake's XMLRPC implementation.
|
|
||||||
# To work around this we subclass Transport and have a copy/paste of method
|
|
||||||
# implementations from Python 2.6.6's xmlrpclib.
|
|
||||||
#
|
|
||||||
# Upstream Python bug is #8194 (http://bugs.python.org/issue8194)
|
|
||||||
# This bug is relevant for Python 2.7.0 and 2.7.1 but was fixed for
|
|
||||||
# Python > 2.7.2
|
|
||||||
##
|
|
||||||
|
|
||||||
class BBTransport(xmlrpclib.Transport):
|
|
||||||
def request(self, host, handler, request_body, verbose=0):
|
|
||||||
h = self.make_connection(host)
|
|
||||||
if verbose:
|
|
||||||
h.set_debuglevel(1)
|
|
||||||
|
|
||||||
self.send_request(h, handler, request_body)
|
|
||||||
self.send_host(h, host)
|
|
||||||
self.send_user_agent(h)
|
|
||||||
self.send_content(h, request_body)
|
|
||||||
|
|
||||||
errcode, errmsg, headers = h.getreply()
|
|
||||||
|
|
||||||
if errcode != 200:
|
|
||||||
raise ProtocolError(
|
|
||||||
host + handler,
|
|
||||||
errcode, errmsg,
|
|
||||||
headers
|
|
||||||
)
|
|
||||||
|
|
||||||
self.verbose = verbose
|
|
||||||
|
|
||||||
try:
|
|
||||||
sock = h._conn.sock
|
|
||||||
except AttributeError:
|
|
||||||
sock = None
|
|
||||||
|
|
||||||
return self._parse_response(h.getfile(), sock)
|
|
||||||
|
|
||||||
def make_connection(self, host):
|
|
||||||
import httplib
|
|
||||||
host, extra_headers, x509 = self.get_host_info(host)
|
|
||||||
return httplib.HTTP(host)
|
|
||||||
|
|
||||||
def _parse_response(self, file, sock):
|
|
||||||
p, u = self.getparser()
|
|
||||||
|
|
||||||
while 1:
|
|
||||||
if sock:
|
|
||||||
response = sock.recv(1024)
|
|
||||||
else:
|
|
||||||
response = file.read(1024)
|
|
||||||
if not response:
|
|
||||||
break
|
|
||||||
if self.verbose:
|
|
||||||
print "body:", repr(response)
|
|
||||||
p.feed(response)
|
|
||||||
|
|
||||||
file.close()
|
|
||||||
p.close()
|
|
||||||
|
|
||||||
return u.close()
|
|
||||||
|
|
||||||
def _create_server(host, port):
|
|
||||||
# Python 2.7.0 and 2.7.1 have a buggy Transport implementation
|
|
||||||
# For those versions of Python, and only those versions, use our
|
|
||||||
# own copy/paste BBTransport class.
|
|
||||||
if (2, 7, 0) <= sys.version_info < (2, 7, 2):
|
|
||||||
t = BBTransport()
|
|
||||||
s = xmlrpclib.Server("http://%s:%d/" % (host, port), transport=t, allow_none=True)
|
|
||||||
else:
|
|
||||||
s = xmlrpclib.Server("http://%s:%d/" % (host, port), allow_none=True)
|
|
||||||
|
|
||||||
return s
|
|
||||||
|
|
||||||
class BitBakeServerCommands():
|
class BitBakeServerCommands():
|
||||||
def __init__(self, server, cooker):
|
def __init__(self, server, cooker):
|
||||||
self.cooker = cooker
|
self.cooker = cooker
|
||||||
@@ -130,8 +54,7 @@ class BitBakeServerCommands():
|
|||||||
"""
|
"""
|
||||||
Register a remote UI Event Handler
|
Register a remote UI Event Handler
|
||||||
"""
|
"""
|
||||||
s = _create_server(host, port)
|
s = xmlrpclib.Server("http://%s:%d" % (host, port), allow_none=True)
|
||||||
|
|
||||||
return bb.event.register_UIHhandler(s)
|
return bb.event.register_UIHhandler(s)
|
||||||
|
|
||||||
def unregisterEventHandler(self, handlerNum):
|
def unregisterEventHandler(self, handlerNum):
|
||||||
@@ -176,7 +99,6 @@ class BitBakeServer(SimpleXMLRPCServer):
|
|||||||
#self.register_introspection_functions()
|
#self.register_introspection_functions()
|
||||||
commands = BitBakeServerCommands(self, cooker)
|
commands = BitBakeServerCommands(self, cooker)
|
||||||
self.autoregister_all_functions(commands, "")
|
self.autoregister_all_functions(commands, "")
|
||||||
self.cooker = cooker
|
|
||||||
|
|
||||||
def autoregister_all_functions(self, context, prefix):
|
def autoregister_all_functions(self, context, prefix):
|
||||||
"""
|
"""
|
||||||
@@ -194,9 +116,6 @@ class BitBakeServer(SimpleXMLRPCServer):
|
|||||||
self._idlefuns[function] = data
|
self._idlefuns[function] = data
|
||||||
|
|
||||||
def serve_forever(self):
|
def serve_forever(self):
|
||||||
bb.cooker.server_main(self.cooker, self._serve_forever)
|
|
||||||
|
|
||||||
def _serve_forever(self):
|
|
||||||
"""
|
"""
|
||||||
Serve Requests. Overloaded to honor a quit command
|
Serve Requests. Overloaded to honor a quit command
|
||||||
"""
|
"""
|
||||||
@@ -245,19 +164,13 @@ class BitbakeServerInfo():
|
|||||||
self.port = server.port
|
self.port = server.port
|
||||||
|
|
||||||
class BitBakeServerFork():
|
class BitBakeServerFork():
|
||||||
def __init__(self, cooker, server, serverinfo, logfile):
|
def __init__(self, serverinfo, command, logfile):
|
||||||
daemonize.createDaemon(server.serve_forever, logfile)
|
daemonize.createDaemon(command, logfile)
|
||||||
|
|
||||||
class BitbakeUILauch():
|
|
||||||
def launch(self, serverinfo, uifunc, *args):
|
|
||||||
return uifunc(*args)
|
|
||||||
|
|
||||||
class BitBakeServerConnection():
|
class BitBakeServerConnection():
|
||||||
def __init__(self, serverinfo):
|
def __init__(self, serverinfo):
|
||||||
self.connection = _create_server(serverinfo.host, serverinfo.port)
|
self.connection = xmlrpclib.Server("http://%s:%s" % (serverinfo.host, serverinfo.port), allow_none=True)
|
||||||
self.events = uievent.BBUIEventQueue(self.connection)
|
self.events = uievent.BBUIEventQueue(self.connection)
|
||||||
for event in bb.event.ui_queue:
|
|
||||||
self.events.queue_event(event)
|
|
||||||
|
|
||||||
def terminate(self):
|
def terminate(self):
|
||||||
# Don't wait for server indefinitely
|
# Don't wait for server indefinitely
|
||||||
|
|||||||
@@ -180,9 +180,11 @@ class BitBakeShellCommands:
|
|||||||
last_exception = Providers.NoProvider
|
last_exception = Providers.NoProvider
|
||||||
|
|
||||||
except runqueue.TaskFailure as fnids:
|
except runqueue.TaskFailure as fnids:
|
||||||
|
for fnid in fnids:
|
||||||
|
print("ERROR: '%s' failed" % td.fn_index[fnid])
|
||||||
last_exception = runqueue.TaskFailure
|
last_exception = runqueue.TaskFailure
|
||||||
|
|
||||||
except build.FuncFailed as e:
|
except build.EventException as e:
|
||||||
print("ERROR: Couldn't build '%s'" % names)
|
print("ERROR: Couldn't build '%s'" % names)
|
||||||
last_exception = e
|
last_exception = e
|
||||||
|
|
||||||
@@ -245,7 +247,7 @@ class BitBakeShellCommands:
|
|||||||
cooker.buildFile(bf, cmd)
|
cooker.buildFile(bf, cmd)
|
||||||
except parse.ParseError:
|
except parse.ParseError:
|
||||||
print("ERROR: Unable to open or parse '%s'" % bf)
|
print("ERROR: Unable to open or parse '%s'" % bf)
|
||||||
except build.FuncFailed as e:
|
except build.EventException as e:
|
||||||
print("ERROR: Couldn't build '%s'" % name)
|
print("ERROR: Couldn't build '%s'" % name)
|
||||||
last_exception = e
|
last_exception = e
|
||||||
|
|
||||||
@@ -272,7 +274,9 @@ class BitBakeShellCommands:
|
|||||||
bbfile = params[0]
|
bbfile = params[0]
|
||||||
print("SHELL: Parsing '%s'" % bbfile)
|
print("SHELL: Parsing '%s'" % bbfile)
|
||||||
parse.update_mtime( bbfile )
|
parse.update_mtime( bbfile )
|
||||||
cooker.parser.reparse(bbfile)
|
cooker.bb_cache.cacheValidUpdate(bbfile)
|
||||||
|
fromCache = cooker.bb_cache.loadData(bbfile, cooker.configuration.data, cooker.status)
|
||||||
|
cooker.bb_cache.sync()
|
||||||
if False: #fromCache:
|
if False: #fromCache:
|
||||||
print("SHELL: File has not been updated, not reparsing")
|
print("SHELL: File has not been updated, not reparsing")
|
||||||
else:
|
else:
|
||||||
@@ -441,7 +445,7 @@ SRC_URI = ""
|
|||||||
name, var = params
|
name, var = params
|
||||||
bbfile = self._findProvider( name )
|
bbfile = self._findProvider( name )
|
||||||
if bbfile is not None:
|
if bbfile is not None:
|
||||||
the_data = cache.Cache.loadDataFull(bbfile, cooker.configuration.data)
|
the_data = cooker.bb_cache.loadDataFull(bbfile, cooker.configuration.data)
|
||||||
value = the_data.getVar( var, 1 )
|
value = the_data.getVar( var, 1 )
|
||||||
print(value)
|
print(value)
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -1,64 +1,50 @@
|
|||||||
import hashlib
|
import hashlib
|
||||||
import logging
|
|
||||||
import re
|
import re
|
||||||
import bb.data
|
|
||||||
|
|
||||||
logger = logging.getLogger('BitBake.SigGen')
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import cPickle as pickle
|
import cPickle as pickle
|
||||||
except ImportError:
|
except ImportError:
|
||||||
import pickle
|
import pickle
|
||||||
logger.info('Importing cPickle failed. Falling back to a very slow implementation.')
|
bb.msg.note(1, bb.msg.domain.Cache, "Importing cPickle failed. Falling back to a very slow implementation.")
|
||||||
|
|
||||||
def init(d):
|
def init(d, dumpsigs):
|
||||||
siggens = [obj for obj in globals().itervalues()
|
siggens = [obj for obj in globals().itervalues()
|
||||||
if type(obj) is type and issubclass(obj, SignatureGenerator)]
|
if type(obj) is type and issubclass(obj, SignatureGenerator)]
|
||||||
|
|
||||||
desired = bb.data.getVar("BB_SIGNATURE_HANDLER", d, True) or "noop"
|
desired = bb.data.getVar("BB_SIGNATURE_HANDLER", d, True) or "noop"
|
||||||
for sg in siggens:
|
for sg in siggens:
|
||||||
if desired == sg.name:
|
if desired == sg.name:
|
||||||
return sg(d)
|
return sg(d, dumpsigs)
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
logger.error("Invalid signature generator '%s', using default 'noop'\n"
|
bb.error("Invalid signature generator '%s', using default 'noop' generator" % desired)
|
||||||
"Available generators: %s",
|
bb.error("Available generators: %s" % ", ".join(obj.name for obj in siggens))
|
||||||
', '.join(obj.name for obj in siggens))
|
return SignatureGenerator(d, dumpsigs)
|
||||||
return SignatureGenerator(d)
|
|
||||||
|
|
||||||
class SignatureGenerator(object):
|
class SignatureGenerator(object):
|
||||||
"""
|
"""
|
||||||
"""
|
"""
|
||||||
name = "noop"
|
name = "noop"
|
||||||
|
|
||||||
def __init__(self, data):
|
def __init__(self, data, dumpsigs):
|
||||||
return
|
return
|
||||||
|
|
||||||
def finalise(self, fn, d, varient):
|
def finalise(self, fn, d):
|
||||||
return
|
return
|
||||||
|
|
||||||
def get_taskhash(self, fn, task, deps, dataCache):
|
|
||||||
return 0
|
|
||||||
|
|
||||||
def set_taskdata(self, hashes, deps):
|
|
||||||
return
|
|
||||||
|
|
||||||
def stampfile(self, stampbase, file_name, taskname, extrainfo):
|
|
||||||
return ("%s.%s.%s" % (stampbase, taskname, extrainfo)).rstrip('.')
|
|
||||||
|
|
||||||
class SignatureGeneratorBasic(SignatureGenerator):
|
class SignatureGeneratorBasic(SignatureGenerator):
|
||||||
"""
|
"""
|
||||||
"""
|
"""
|
||||||
name = "basic"
|
name = "basic"
|
||||||
|
|
||||||
def __init__(self, data):
|
def __init__(self, data, dumpsigs):
|
||||||
self.basehash = {}
|
self.basehash = {}
|
||||||
self.taskhash = {}
|
self.taskhash = {}
|
||||||
self.taskdeps = {}
|
self.taskdeps = {}
|
||||||
self.runtaskdeps = {}
|
self.runtaskdeps = {}
|
||||||
self.gendeps = {}
|
self.gendeps = {}
|
||||||
self.lookupcache = {}
|
self.lookupcache = {}
|
||||||
self.basewhitelist = set((data.getVar("BB_HASHBASE_WHITELIST", True) or "").split())
|
self.basewhitelist = (data.getVar("BB_HASHBASE_WHITELIST", True) or "").split()
|
||||||
self.taskwhitelist = data.getVar("BB_HASHTASK_WHITELIST", True) or None
|
self.taskwhitelist = data.getVar("BB_HASHTASK_WHITELIST", True) or None
|
||||||
|
|
||||||
if self.taskwhitelist:
|
if self.taskwhitelist:
|
||||||
@@ -66,33 +52,21 @@ class SignatureGeneratorBasic(SignatureGenerator):
|
|||||||
else:
|
else:
|
||||||
self.twl = None
|
self.twl = None
|
||||||
|
|
||||||
|
self.dumpsigs = dumpsigs
|
||||||
|
|
||||||
def _build_data(self, fn, d):
|
def _build_data(self, fn, d):
|
||||||
|
|
||||||
tasklist, gendeps = bb.data.generate_dependencies(d)
|
taskdeps, gendeps = bb.data.generate_dependencies(d)
|
||||||
|
|
||||||
taskdeps = {}
|
|
||||||
basehash = {}
|
basehash = {}
|
||||||
lookupcache = {}
|
lookupcache = {}
|
||||||
|
|
||||||
for task in tasklist:
|
for task in taskdeps:
|
||||||
data = d.getVar(task, False)
|
data = d.getVar(task, False)
|
||||||
lookupcache[task] = data
|
lookupcache[task] = data
|
||||||
|
for dep in sorted(taskdeps[task]):
|
||||||
newdeps = gendeps[task]
|
if dep in self.basewhitelist:
|
||||||
seen = set()
|
continue
|
||||||
while newdeps:
|
|
||||||
nextdeps = newdeps
|
|
||||||
seen |= nextdeps
|
|
||||||
newdeps = set()
|
|
||||||
for dep in nextdeps:
|
|
||||||
if dep in self.basewhitelist:
|
|
||||||
continue
|
|
||||||
newdeps |= gendeps[dep]
|
|
||||||
newdeps -= seen
|
|
||||||
|
|
||||||
alldeps = seen - self.basewhitelist
|
|
||||||
|
|
||||||
for dep in sorted(alldeps):
|
|
||||||
if dep in lookupcache:
|
if dep in lookupcache:
|
||||||
var = lookupcache[dep]
|
var = lookupcache[dep]
|
||||||
else:
|
else:
|
||||||
@@ -100,14 +74,13 @@ class SignatureGeneratorBasic(SignatureGenerator):
|
|||||||
lookupcache[dep] = var
|
lookupcache[dep] = var
|
||||||
if var:
|
if var:
|
||||||
data = data + var
|
data = data + var
|
||||||
if data is None:
|
|
||||||
bb.error("Task %s from %s seems to be empty?!" % (task, fn))
|
|
||||||
self.basehash[fn + "." + task] = hashlib.md5(data).hexdigest()
|
self.basehash[fn + "." + task] = hashlib.md5(data).hexdigest()
|
||||||
taskdeps[task] = sorted(alldeps)
|
#bb.note("Hash for %s is %s" % (task, tashhash[task]))
|
||||||
|
|
||||||
self.taskdeps[fn] = taskdeps
|
if self.dumpsigs:
|
||||||
self.gendeps[fn] = gendeps
|
self.taskdeps[fn] = taskdeps
|
||||||
self.lookupcache[fn] = lookupcache
|
self.gendeps[fn] = gendeps
|
||||||
|
self.lookupcache[fn] = lookupcache
|
||||||
|
|
||||||
return taskdeps
|
return taskdeps
|
||||||
|
|
||||||
@@ -128,18 +101,14 @@ class SignatureGeneratorBasic(SignatureGenerator):
|
|||||||
def get_taskhash(self, fn, task, deps, dataCache):
|
def get_taskhash(self, fn, task, deps, dataCache):
|
||||||
k = fn + "." + task
|
k = fn + "." + task
|
||||||
data = dataCache.basetaskhash[k]
|
data = dataCache.basetaskhash[k]
|
||||||
self.runtaskdeps[k] = []
|
self.runtaskdeps[k] = deps
|
||||||
for dep in sorted(deps):
|
for dep in sorted(deps):
|
||||||
# We only manipulate the dependencies for packages not in the whitelist
|
if self.twl and self.twl.search(dataCache.pkg_fn[fn]):
|
||||||
if self.twl and not self.twl.search(dataCache.pkg_fn[fn]):
|
#bb.note("Skipping %s" % dep)
|
||||||
# then process the actual dependencies
|
continue
|
||||||
dep_fn = re.search("(?P<fn>.*)\..*", dep).group('fn')
|
|
||||||
if self.twl.search(dataCache.pkg_fn[dep_fn]):
|
|
||||||
continue
|
|
||||||
if dep not in self.taskhash:
|
if dep not in self.taskhash:
|
||||||
bb.fatal("%s is not in taskhash, caller isn't calling in dependency order?", dep)
|
bb.fatal("%s is not in taskhash, caller isn't calling in dependency order?", dep)
|
||||||
data = data + self.taskhash[dep]
|
data = data + self.taskhash[dep]
|
||||||
self.runtaskdeps[k].append(dep)
|
|
||||||
h = hashlib.md5(data).hexdigest()
|
h = hashlib.md5(data).hexdigest()
|
||||||
self.taskhash[k] = h
|
self.taskhash[k] = h
|
||||||
#d.setVar("BB_TASKHASH_task-%s" % task, taskhash[task])
|
#d.setVar("BB_TASKHASH_task-%s" % task, taskhash[task])
|
||||||
@@ -158,8 +127,6 @@ class SignatureGeneratorBasic(SignatureGenerator):
|
|||||||
else:
|
else:
|
||||||
sigfile = stampbase + "." + task + ".sigbasedata" + "." + self.basehash[k]
|
sigfile = stampbase + "." + task + ".sigbasedata" + "." + self.basehash[k]
|
||||||
|
|
||||||
bb.utils.mkdirhier(os.path.dirname(sigfile))
|
|
||||||
|
|
||||||
data = {}
|
data = {}
|
||||||
data['basewhitelist'] = self.basewhitelist
|
data['basewhitelist'] = self.basewhitelist
|
||||||
data['taskwhitelist'] = self.taskwhitelist
|
data['taskwhitelist'] = self.taskwhitelist
|
||||||
@@ -190,23 +157,11 @@ class SignatureGeneratorBasic(SignatureGenerator):
|
|||||||
if k not in self.taskhash:
|
if k not in self.taskhash:
|
||||||
continue
|
continue
|
||||||
if dataCache.basetaskhash[k] != self.basehash[k]:
|
if dataCache.basetaskhash[k] != self.basehash[k]:
|
||||||
bb.error("Bitbake's cached basehash does not match the one we just generated (%s)!" % k)
|
bb.error("Bitbake's cached basehash does not match the one we just generated!")
|
||||||
bb.error("The mismatched hashes were %s and %s" % (dataCache.basetaskhash[k], self.basehash[k]))
|
bb.error("The mismatched hashes were %s and %s" % (dataCache.basetaskhash[k], self.basehash[k]))
|
||||||
self.dump_sigtask(fn, task, dataCache.stamp[fn], True)
|
self.dump_sigtask(fn, task, dataCache.stamp[fn], True)
|
||||||
|
|
||||||
class SignatureGeneratorBasicHash(SignatureGeneratorBasic):
|
|
||||||
name = "basichash"
|
|
||||||
|
|
||||||
def stampfile(self, stampbase, fn, taskname, extrainfo):
|
|
||||||
if taskname != "do_setscene" and taskname.endswith("_setscene"):
|
|
||||||
k = fn + "." + taskname[:-9]
|
|
||||||
else:
|
|
||||||
k = fn + "." + taskname
|
|
||||||
h = self.taskhash[k]
|
|
||||||
return ("%s.%s.%s.%s" % (stampbase, taskname, h, extrainfo)).rstrip('.')
|
|
||||||
|
|
||||||
def dump_this_task(outfile, d):
|
def dump_this_task(outfile, d):
|
||||||
import bb.parse
|
|
||||||
fn = d.getVar("BB_FILENAME", True)
|
fn = d.getVar("BB_FILENAME", True)
|
||||||
task = "do_" + d.getVar("BB_CURRENTTASK", True)
|
task = "do_" + d.getVar("BB_CURRENTTASK", True)
|
||||||
bb.parse.siggen.dump_sigtask(fn, task, outfile, "customfile")
|
bb.parse.siggen.dump_sigtask(fn, task, outfile, "customfile")
|
||||||
@@ -217,6 +172,10 @@ def compare_sigfiles(a, b):
|
|||||||
p2 = pickle.Unpickler(file(b, "rb"))
|
p2 = pickle.Unpickler(file(b, "rb"))
|
||||||
b_data = p2.load()
|
b_data = p2.load()
|
||||||
|
|
||||||
|
#print "Checking"
|
||||||
|
#print str(a_data)
|
||||||
|
#print str(b_data)
|
||||||
|
|
||||||
def dict_diff(a, b):
|
def dict_diff(a, b):
|
||||||
sa = set(a.keys())
|
sa = set(a.keys())
|
||||||
sb = set(b.keys())
|
sb = set(b.keys())
|
||||||
@@ -257,20 +216,18 @@ def compare_sigfiles(a, b):
|
|||||||
if changed:
|
if changed:
|
||||||
for dep in changed:
|
for dep in changed:
|
||||||
print "Variable %s value changed from %s to %s" % (dep, a_data['varvals'][dep], b_data['varvals'][dep])
|
print "Variable %s value changed from %s to %s" % (dep, a_data['varvals'][dep], b_data['varvals'][dep])
|
||||||
|
#if added:
|
||||||
|
# print "Dependency on variable %s was added (value %s)" % (dep, b_data['gendeps'][dep])
|
||||||
|
#if removed:
|
||||||
|
# print "Dependency on Variable %s was removed (value %s)" % (dep, a_data['gendeps'][dep])
|
||||||
|
|
||||||
if 'runtaskhashes' in a_data and 'runtaskhashes' in b_data:
|
if 'runtaskdeps' in a_data and 'runtaskdeps' in b_data and a_data['runtaskdeps'] != b_data['runtaskdeps']:
|
||||||
changed, added, removed = dict_diff(a_data['runtaskhashes'], b_data['runtaskhashes'])
|
print "Tasks this task depends on changed from %s to %s" % (a_data['taskdeps'], b_data['taskdeps'])
|
||||||
if added:
|
|
||||||
for dep in added:
|
if 'runtaskhashes' in a_data:
|
||||||
print "Dependency on task %s was added" % (dep)
|
for dep in a_data['runtaskhashes']:
|
||||||
if removed:
|
if a_data['runtaskhashes'][dep] != b_data['runtaskhashes'][dep]:
|
||||||
for dep in removed:
|
|
||||||
print "Dependency on task %s was removed" % (dep)
|
|
||||||
if changed:
|
|
||||||
for dep in changed:
|
|
||||||
print "Hash for dependent task %s changed from %s to %s" % (dep, a_data['runtaskhashes'][dep], b_data['runtaskhashes'][dep])
|
print "Hash for dependent task %s changed from %s to %s" % (dep, a_data['runtaskhashes'][dep], b_data['runtaskhashes'][dep])
|
||||||
elif 'runtaskdeps' in a_data and 'runtaskdeps' in b_data and sorted(a_data['runtaskdeps']) != sorted(b_data['runtaskdeps']):
|
|
||||||
print "Tasks this task depends on changed from %s to %s" % (sorted(a_data['runtaskdeps']), sorted(b_data['runtaskdeps']))
|
|
||||||
|
|
||||||
def dump_sigfile(a):
|
def dump_sigfile(a):
|
||||||
p1 = pickle.Unpickler(file(a, "rb"))
|
p1 = pickle.Unpickler(file(a, "rb"))
|
||||||
@@ -296,3 +253,8 @@ def dump_sigfile(a):
|
|||||||
if 'runtaskhashes' in a_data:
|
if 'runtaskhashes' in a_data:
|
||||||
for dep in a_data['runtaskhashes']:
|
for dep in a_data['runtaskhashes']:
|
||||||
print "Hash for dependent task %s is %s" % (dep, a_data['runtaskhashes'][dep])
|
print "Hash for dependent task %s is %s" % (dep, a_data['runtaskhashes'][dep])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -23,19 +23,20 @@ Task data collection and handling
|
|||||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
import logging
|
|
||||||
import re
|
|
||||||
import bb
|
import bb
|
||||||
|
|
||||||
logger = logging.getLogger("BitBake.TaskData")
|
|
||||||
|
|
||||||
def re_match_strings(target, strings):
|
def re_match_strings(target, strings):
|
||||||
"""
|
"""
|
||||||
Whether or not the string 'target' matches
|
Whether or not the string 'target' matches
|
||||||
any one string of the strings which can be regular expression string
|
any one string of the strings which can be regular expression string
|
||||||
"""
|
"""
|
||||||
return any(name == target or re.match(name, target)
|
import re
|
||||||
for name in strings)
|
|
||||||
|
for name in strings:
|
||||||
|
if (name==target or
|
||||||
|
re.search(name, target)!=None):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
class TaskData:
|
class TaskData:
|
||||||
"""
|
"""
|
||||||
@@ -181,7 +182,7 @@ class TaskData:
|
|||||||
if not fnid in self.depids:
|
if not fnid in self.depids:
|
||||||
dependids = {}
|
dependids = {}
|
||||||
for depend in dataCache.deps[fn]:
|
for depend in dataCache.deps[fn]:
|
||||||
logger.debug(2, "Added dependency %s for %s", depend, fn)
|
bb.msg.debug(2, bb.msg.domain.TaskData, "Added dependency %s for %s" % (depend, fn))
|
||||||
dependids[self.getbuild_id(depend)] = None
|
dependids[self.getbuild_id(depend)] = None
|
||||||
self.depids[fnid] = dependids.keys()
|
self.depids[fnid] = dependids.keys()
|
||||||
|
|
||||||
@@ -191,12 +192,12 @@ class TaskData:
|
|||||||
rdepends = dataCache.rundeps[fn]
|
rdepends = dataCache.rundeps[fn]
|
||||||
rrecs = dataCache.runrecs[fn]
|
rrecs = dataCache.runrecs[fn]
|
||||||
for package in rdepends:
|
for package in rdepends:
|
||||||
for rdepend in rdepends[package]:
|
for rdepend in bb.utils.explode_deps(rdepends[package]):
|
||||||
logger.debug(2, "Added runtime dependency %s for %s", rdepend, fn)
|
bb.msg.debug(2, bb.msg.domain.TaskData, "Added runtime dependency %s for %s" % (rdepend, fn))
|
||||||
rdependids[self.getrun_id(rdepend)] = None
|
rdependids[self.getrun_id(rdepend)] = None
|
||||||
for package in rrecs:
|
for package in rrecs:
|
||||||
for rdepend in rrecs[package]:
|
for rdepend in bb.utils.explode_deps(rrecs[package]):
|
||||||
logger.debug(2, "Added runtime recommendation %s for %s", rdepend, fn)
|
bb.msg.debug(2, bb.msg.domain.TaskData, "Added runtime recommendation %s for %s" % (rdepend, fn))
|
||||||
rdependids[self.getrun_id(rdepend)] = None
|
rdependids[self.getrun_id(rdepend)] = None
|
||||||
self.rdepids[fnid] = rdependids.keys()
|
self.rdepids[fnid] = rdependids.keys()
|
||||||
|
|
||||||
@@ -396,7 +397,7 @@ class TaskData:
|
|||||||
fnid = self.getfn_id(fn)
|
fnid = self.getfn_id(fn)
|
||||||
if fnid in self.failed_fnids:
|
if fnid in self.failed_fnids:
|
||||||
continue
|
continue
|
||||||
logger.debug(2, "adding %s to satisfy %s", fn, item)
|
bb.msg.debug(2, bb.msg.domain.Provider, "adding %s to satisfy %s" % (fn, item))
|
||||||
self.add_build_target(fn, item)
|
self.add_build_target(fn, item)
|
||||||
self.add_tasks(fn, dataCache)
|
self.add_tasks(fn, dataCache)
|
||||||
|
|
||||||
@@ -449,7 +450,7 @@ class TaskData:
|
|||||||
fnid = self.getfn_id(fn)
|
fnid = self.getfn_id(fn)
|
||||||
if fnid in self.failed_fnids:
|
if fnid in self.failed_fnids:
|
||||||
continue
|
continue
|
||||||
logger.debug(2, "adding '%s' to satisfy runtime '%s'", fn, item)
|
bb.msg.debug(2, bb.msg.domain.Provider, "adding '%s' to satisfy runtime '%s'" % (fn, item))
|
||||||
self.add_runtime_target(fn, item)
|
self.add_runtime_target(fn, item)
|
||||||
self.add_tasks(fn, dataCache)
|
self.add_tasks(fn, dataCache)
|
||||||
|
|
||||||
@@ -462,7 +463,7 @@ class TaskData:
|
|||||||
"""
|
"""
|
||||||
if fnid in self.failed_fnids:
|
if fnid in self.failed_fnids:
|
||||||
return
|
return
|
||||||
logger.debug(1, "File '%s' is unbuildable, removing...", self.fn_index[fnid])
|
bb.msg.debug(1, bb.msg.domain.Provider, "File '%s' is unbuildable, removing..." % self.fn_index[fnid])
|
||||||
self.failed_fnids.append(fnid)
|
self.failed_fnids.append(fnid)
|
||||||
for target in self.build_targets:
|
for target in self.build_targets:
|
||||||
if fnid in self.build_targets[target]:
|
if fnid in self.build_targets[target]:
|
||||||
@@ -484,12 +485,12 @@ class TaskData:
|
|||||||
missing_list = [self.build_names_index[targetid]]
|
missing_list = [self.build_names_index[targetid]]
|
||||||
else:
|
else:
|
||||||
missing_list = [self.build_names_index[targetid]] + missing_list
|
missing_list = [self.build_names_index[targetid]] + missing_list
|
||||||
logger.verbose("Target '%s' is unbuildable, removing...\nMissing or unbuildable dependency chain was: %s", self.build_names_index[targetid], missing_list)
|
bb.msg.note(2, bb.msg.domain.Provider, "Target '%s' is unbuildable, removing...\nMissing or unbuildable dependency chain was: %s" % (self.build_names_index[targetid], missing_list))
|
||||||
self.failed_deps.append(targetid)
|
self.failed_deps.append(targetid)
|
||||||
dependees = self.get_dependees(targetid)
|
dependees = self.get_dependees(targetid)
|
||||||
for fnid in dependees:
|
for fnid in dependees:
|
||||||
self.fail_fnid(fnid, missing_list)
|
self.fail_fnid(fnid, missing_list)
|
||||||
for taskid in xrange(len(self.tasks_idepends)):
|
for taskid in range(len(self.tasks_idepends)):
|
||||||
idepends = self.tasks_idepends[taskid]
|
idepends = self.tasks_idepends[taskid]
|
||||||
for (idependid, idependtask) in idepends:
|
for (idependid, idependtask) in idepends:
|
||||||
if idependid == targetid:
|
if idependid == targetid:
|
||||||
@@ -497,7 +498,7 @@ class TaskData:
|
|||||||
|
|
||||||
if self.abort and targetid in self.external_targets:
|
if self.abort and targetid in self.external_targets:
|
||||||
target = self.build_names_index[targetid]
|
target = self.build_names_index[targetid]
|
||||||
logger.error("Required build target '%s' has no buildable providers.\nMissing or unbuildable dependency chain was: %s", target, missing_list)
|
bb.msg.error(bb.msg.domain.Provider, "Required build target '%s' has no buildable providers.\nMissing or unbuildable dependency chain was: %s" % (target, missing_list))
|
||||||
raise bb.providers.NoProvider(target)
|
raise bb.providers.NoProvider(target)
|
||||||
|
|
||||||
def remove_runtarget(self, targetid, missing_list = []):
|
def remove_runtarget(self, targetid, missing_list = []):
|
||||||
@@ -510,7 +511,7 @@ class TaskData:
|
|||||||
else:
|
else:
|
||||||
missing_list = [self.run_names_index[targetid]] + missing_list
|
missing_list = [self.run_names_index[targetid]] + missing_list
|
||||||
|
|
||||||
logger.info("Runtime target '%s' is unbuildable, removing...\nMissing or unbuildable dependency chain was: %s", self.run_names_index[targetid], missing_list)
|
bb.msg.note(1, bb.msg.domain.Provider, "Runtime target '%s' is unbuildable, removing...\nMissing or unbuildable dependency chain was: %s" % (self.run_names_index[targetid], missing_list))
|
||||||
self.failed_rdeps.append(targetid)
|
self.failed_rdeps.append(targetid)
|
||||||
dependees = self.get_rdependees(targetid)
|
dependees = self.get_rdependees(targetid)
|
||||||
for fnid in dependees:
|
for fnid in dependees:
|
||||||
@@ -520,7 +521,7 @@ class TaskData:
|
|||||||
"""
|
"""
|
||||||
Resolve all unresolved build and runtime targets
|
Resolve all unresolved build and runtime targets
|
||||||
"""
|
"""
|
||||||
logger.info("Resolving any missing task queue dependencies")
|
bb.msg.note(1, bb.msg.domain.TaskData, "Resolving any missing task queue dependencies")
|
||||||
while True:
|
while True:
|
||||||
added = 0
|
added = 0
|
||||||
for target in self.get_unresolved_build_targets(dataCache):
|
for target in self.get_unresolved_build_targets(dataCache):
|
||||||
@@ -538,7 +539,7 @@ class TaskData:
|
|||||||
added = added + 1
|
added = added + 1
|
||||||
except bb.providers.NoRProvider:
|
except bb.providers.NoRProvider:
|
||||||
self.remove_runtarget(self.getrun_id(target))
|
self.remove_runtarget(self.getrun_id(target))
|
||||||
logger.debug(1, "Resolved " + str(added) + " extra dependencies")
|
bb.msg.debug(1, bb.msg.domain.TaskData, "Resolved " + str(added) + " extra dependencies")
|
||||||
if added == 0:
|
if added == 0:
|
||||||
break
|
break
|
||||||
# self.dump_data()
|
# self.dump_data()
|
||||||
@@ -547,40 +548,40 @@ class TaskData:
|
|||||||
"""
|
"""
|
||||||
Dump some debug information on the internal data structures
|
Dump some debug information on the internal data structures
|
||||||
"""
|
"""
|
||||||
logger.debug(3, "build_names:")
|
bb.msg.debug(3, bb.msg.domain.TaskData, "build_names:")
|
||||||
logger.debug(3, ", ".join(self.build_names_index))
|
bb.msg.debug(3, bb.msg.domain.TaskData, ", ".join(self.build_names_index))
|
||||||
|
|
||||||
logger.debug(3, "run_names:")
|
bb.msg.debug(3, bb.msg.domain.TaskData, "run_names:")
|
||||||
logger.debug(3, ", ".join(self.run_names_index))
|
bb.msg.debug(3, bb.msg.domain.TaskData, ", ".join(self.run_names_index))
|
||||||
|
|
||||||
logger.debug(3, "build_targets:")
|
bb.msg.debug(3, bb.msg.domain.TaskData, "build_targets:")
|
||||||
for buildid in xrange(len(self.build_names_index)):
|
for buildid in range(len(self.build_names_index)):
|
||||||
target = self.build_names_index[buildid]
|
target = self.build_names_index[buildid]
|
||||||
targets = "None"
|
targets = "None"
|
||||||
if buildid in self.build_targets:
|
if buildid in self.build_targets:
|
||||||
targets = self.build_targets[buildid]
|
targets = self.build_targets[buildid]
|
||||||
logger.debug(3, " (%s)%s: %s", buildid, target, targets)
|
bb.msg.debug(3, bb.msg.domain.TaskData, " (%s)%s: %s" % (buildid, target, targets))
|
||||||
|
|
||||||
logger.debug(3, "run_targets:")
|
bb.msg.debug(3, bb.msg.domain.TaskData, "run_targets:")
|
||||||
for runid in xrange(len(self.run_names_index)):
|
for runid in range(len(self.run_names_index)):
|
||||||
target = self.run_names_index[runid]
|
target = self.run_names_index[runid]
|
||||||
targets = "None"
|
targets = "None"
|
||||||
if runid in self.run_targets:
|
if runid in self.run_targets:
|
||||||
targets = self.run_targets[runid]
|
targets = self.run_targets[runid]
|
||||||
logger.debug(3, " (%s)%s: %s", runid, target, targets)
|
bb.msg.debug(3, bb.msg.domain.TaskData, " (%s)%s: %s" % (runid, target, targets))
|
||||||
|
|
||||||
logger.debug(3, "tasks:")
|
bb.msg.debug(3, bb.msg.domain.TaskData, "tasks:")
|
||||||
for task in xrange(len(self.tasks_name)):
|
for task in range(len(self.tasks_name)):
|
||||||
logger.debug(3, " (%s)%s - %s: %s",
|
bb.msg.debug(3, bb.msg.domain.TaskData, " (%s)%s - %s: %s" % (
|
||||||
task,
|
task,
|
||||||
self.fn_index[self.tasks_fnid[task]],
|
self.fn_index[self.tasks_fnid[task]],
|
||||||
self.tasks_name[task],
|
self.tasks_name[task],
|
||||||
self.tasks_tdepends[task])
|
self.tasks_tdepends[task]))
|
||||||
|
|
||||||
logger.debug(3, "dependency ids (per fn):")
|
bb.msg.debug(3, bb.msg.domain.TaskData, "dependency ids (per fn):")
|
||||||
for fnid in self.depids:
|
for fnid in self.depids:
|
||||||
logger.debug(3, " %s %s: %s", fnid, self.fn_index[fnid], self.depids[fnid])
|
bb.msg.debug(3, bb.msg.domain.TaskData, " %s %s: %s" % (fnid, self.fn_index[fnid], self.depids[fnid]))
|
||||||
|
|
||||||
logger.debug(3, "runtime dependency ids (per fn):")
|
bb.msg.debug(3, bb.msg.domain.TaskData, "runtime dependency ids (per fn):")
|
||||||
for fnid in self.rdepids:
|
for fnid in self.rdepids:
|
||||||
logger.debug(3, " %s %s: %s", fnid, self.fn_index[fnid], self.rdepids[fnid])
|
bb.msg.debug(3, bb.msg.domain.TaskData, " %s %s: %s" % (fnid, self.fn_index[fnid], self.rdepids[fnid]))
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Gtk+ UI pieces for BitBake
|
# BitBake UI Implementation
|
||||||
#
|
#
|
||||||
# Copyright (C) 2006-2007 Richard Purdie
|
# Copyright (C) 2006-2007 Richard Purdie
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -1,137 +0,0 @@
|
|||||||
#
|
|
||||||
# BitBake Graphical GTK User Interface
|
|
||||||
#
|
|
||||||
# Copyright (C) 2011 Intel Corporation
|
|
||||||
#
|
|
||||||
# Authored by Joshua Lock <josh@linux.intel.com>
|
|
||||||
#
|
|
||||||
# This program is free software; you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU General Public License version 2 as
|
|
||||||
# published by the Free Software Foundation.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License along
|
|
||||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
|
|
||||||
import gobject
|
|
||||||
from bb.ui.crumbs.progress import ProgressBar
|
|
||||||
|
|
||||||
progress_total = 0
|
|
||||||
|
|
||||||
class HobHandler(gobject.GObject):
|
|
||||||
|
|
||||||
"""
|
|
||||||
This object does BitBake event handling for the hob gui.
|
|
||||||
"""
|
|
||||||
__gsignals__ = {
|
|
||||||
"machines-updated" : (gobject.SIGNAL_RUN_LAST,
|
|
||||||
gobject.TYPE_NONE,
|
|
||||||
(gobject.TYPE_PYOBJECT,)),
|
|
||||||
"distros-updated" : (gobject.SIGNAL_RUN_LAST,
|
|
||||||
gobject.TYPE_NONE,
|
|
||||||
(gobject.TYPE_PYOBJECT,)),
|
|
||||||
"generating-data" : (gobject.SIGNAL_RUN_LAST,
|
|
||||||
gobject.TYPE_NONE,
|
|
||||||
()),
|
|
||||||
"data-generated" : (gobject.SIGNAL_RUN_LAST,
|
|
||||||
gobject.TYPE_NONE,
|
|
||||||
())
|
|
||||||
}
|
|
||||||
|
|
||||||
def __init__(self, taskmodel, server):
|
|
||||||
gobject.GObject.__init__(self)
|
|
||||||
|
|
||||||
self.model = taskmodel
|
|
||||||
self.server = server
|
|
||||||
self.current_command = None
|
|
||||||
self.building = False
|
|
||||||
|
|
||||||
self.command_map = {
|
|
||||||
"findConfigFilesDistro" : ("findConfigFiles", "MACHINE", "findConfigFilesMachine"),
|
|
||||||
"findConfigFilesMachine" : ("generateTargetsTree", "classes/image.bbclass", None),
|
|
||||||
"generateTargetsTree" : (None, None, None),
|
|
||||||
}
|
|
||||||
|
|
||||||
def run_next_command(self):
|
|
||||||
# FIXME: this is ugly and I *will* replace it
|
|
||||||
if self.current_command:
|
|
||||||
next_cmd = self.command_map[self.current_command]
|
|
||||||
command = next_cmd[0]
|
|
||||||
argument = next_cmd[1]
|
|
||||||
self.current_command = next_cmd[2]
|
|
||||||
if command == "generateTargetsTree":
|
|
||||||
self.emit("generating-data")
|
|
||||||
self.server.runCommand([command, argument])
|
|
||||||
|
|
||||||
def handle_event(self, event, running_build, pbar=None):
|
|
||||||
if not event:
|
|
||||||
return
|
|
||||||
|
|
||||||
# If we're running a build, use the RunningBuild event handler
|
|
||||||
if self.building:
|
|
||||||
running_build.handle_event(event)
|
|
||||||
elif isinstance(event, bb.event.TargetsTreeGenerated):
|
|
||||||
self.emit("data-generated")
|
|
||||||
if event._model:
|
|
||||||
self.model.populate(event._model)
|
|
||||||
|
|
||||||
elif isinstance(event, bb.event.ConfigFilesFound):
|
|
||||||
var = event._variable
|
|
||||||
if var == "distro":
|
|
||||||
distros = event._values
|
|
||||||
distros.sort()
|
|
||||||
self.emit("distros-updated", distros)
|
|
||||||
elif var == "machine":
|
|
||||||
machines = event._values
|
|
||||||
machines.sort()
|
|
||||||
self.emit("machines-updated", machines)
|
|
||||||
|
|
||||||
elif isinstance(event, bb.command.CommandCompleted):
|
|
||||||
self.run_next_command()
|
|
||||||
elif isinstance(event, bb.event.CacheLoadStarted) and pbar:
|
|
||||||
pbar.set_title("Loading cache")
|
|
||||||
bb.ui.crumbs.hobeventhandler.progress_total = event.total
|
|
||||||
pbar.update(0, bb.ui.crumbs.hobeventhandler.progress_total)
|
|
||||||
elif isinstance(event, bb.event.CacheLoadProgress) and pbar:
|
|
||||||
pbar.update(event.current, bb.ui.crumbs.hobeventhandler.progress_total)
|
|
||||||
elif isinstance(event, bb.event.CacheLoadCompleted) and pbar:
|
|
||||||
pbar.update(bb.ui.crumbs.hobeventhandler.progress_total, bb.ui.crumbs.hobeventhandler.progress_total)
|
|
||||||
elif isinstance(event, bb.event.ParseStarted) and pbar:
|
|
||||||
pbar.set_title("Processing recipes")
|
|
||||||
bb.ui.crumbs.hobeventhandler.progress_total = event.total
|
|
||||||
pbar.update(0, bb.ui.crumbs.hobeventhandler.progress_total)
|
|
||||||
elif isinstance(event, bb.event.ParseProgress) and pbar:
|
|
||||||
pbar.update(event.current, bb.ui.crumbs.hobeventhandler.progress_total)
|
|
||||||
elif isinstance(event, bb.event.ParseCompleted) and pbar:
|
|
||||||
pbar.hide()
|
|
||||||
|
|
||||||
return
|
|
||||||
|
|
||||||
def event_handle_idle_func (self, eventHandler, running_build, pbar):
|
|
||||||
# Consume as many messages as we can in the time available to us
|
|
||||||
event = eventHandler.getEvent()
|
|
||||||
while event:
|
|
||||||
self.handle_event(event, running_build, pbar)
|
|
||||||
event = eventHandler.getEvent()
|
|
||||||
return True
|
|
||||||
|
|
||||||
def set_machine(self, machine):
|
|
||||||
self.server.runCommand(["setVariable", "MACHINE", machine])
|
|
||||||
self.current_command = "findConfigFilesMachine"
|
|
||||||
self.run_next_command()
|
|
||||||
|
|
||||||
def set_distro(self, distro):
|
|
||||||
self.server.runCommand(["setVariable", "DISTRO", distro])
|
|
||||||
|
|
||||||
def run_build(self, targets):
|
|
||||||
self.building = True
|
|
||||||
self.server.runCommand(["buildTargets", targets, "build"])
|
|
||||||
|
|
||||||
def cancel_build(self):
|
|
||||||
# Note: this may not be the right way to stop an in-progress build
|
|
||||||
self.server.runCommand(["stateStop"])
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
import gtk
|
|
||||||
|
|
||||||
class ProgressBar(gtk.Dialog):
|
|
||||||
def __init__(self, parent):
|
|
||||||
|
|
||||||
gtk.Dialog.__init__(self, flags=(gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT))
|
|
||||||
self.set_title("Parsing metadata, please wait...")
|
|
||||||
self.set_default_size(500, 0)
|
|
||||||
self.set_transient_for(parent)
|
|
||||||
self.progress = gtk.ProgressBar()
|
|
||||||
self.vbox.pack_start(self.progress)
|
|
||||||
self.show_all()
|
|
||||||
|
|
||||||
def update(self, x, y):
|
|
||||||
self.progress.set_fraction(float(x)/float(y))
|
|
||||||
self.progress.set_text("%2d %%" % (x*100/y))
|
|
||||||
|
|
||||||
def pulse(self):
|
|
||||||
self.progress.set_text("Loading...")
|
|
||||||
self.progress.pulse()
|
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
#
|
#
|
||||||
# BitBake Graphical GTK User Interface
|
# BitBake Graphical GTK User Interface
|
||||||
#
|
#
|
||||||
@@ -21,20 +20,9 @@
|
|||||||
|
|
||||||
import gtk
|
import gtk
|
||||||
import gobject
|
import gobject
|
||||||
import logging
|
|
||||||
import time
|
|
||||||
import urllib
|
|
||||||
import urllib2
|
|
||||||
|
|
||||||
class Colors(object):
|
|
||||||
OK = "#ffffff"
|
|
||||||
RUNNING = "#aaffaa"
|
|
||||||
WARNING ="#f88017"
|
|
||||||
ERROR = "#ffaaaa"
|
|
||||||
|
|
||||||
class RunningBuildModel (gtk.TreeStore):
|
class RunningBuildModel (gtk.TreeStore):
|
||||||
(COL_LOG, COL_PACKAGE, COL_TASK, COL_MESSAGE, COL_ICON, COL_COLOR, COL_NUM_ACTIVE) = range(7)
|
(COL_TYPE, COL_PACKAGE, COL_TASK, COL_MESSAGE, COL_ICON, COL_ACTIVE) = (0, 1, 2, 3, 4, 5)
|
||||||
|
|
||||||
def __init__ (self):
|
def __init__ (self):
|
||||||
gtk.TreeStore.__init__ (self,
|
gtk.TreeStore.__init__ (self,
|
||||||
gobject.TYPE_STRING,
|
gobject.TYPE_STRING,
|
||||||
@@ -42,8 +30,7 @@ class RunningBuildModel (gtk.TreeStore):
|
|||||||
gobject.TYPE_STRING,
|
gobject.TYPE_STRING,
|
||||||
gobject.TYPE_STRING,
|
gobject.TYPE_STRING,
|
||||||
gobject.TYPE_STRING,
|
gobject.TYPE_STRING,
|
||||||
gobject.TYPE_STRING,
|
gobject.TYPE_BOOLEAN)
|
||||||
gobject.TYPE_INT)
|
|
||||||
|
|
||||||
class RunningBuild (gobject.GObject):
|
class RunningBuild (gobject.GObject):
|
||||||
__gsignals__ = {
|
__gsignals__ = {
|
||||||
@@ -61,7 +48,7 @@ class RunningBuild (gobject.GObject):
|
|||||||
gobject.GObject.__init__ (self)
|
gobject.GObject.__init__ (self)
|
||||||
self.model = RunningBuildModel()
|
self.model = RunningBuildModel()
|
||||||
|
|
||||||
def handle_event (self, event, pbar=None):
|
def handle_event (self, event):
|
||||||
# Handle an event from the event queue, this may result in updating
|
# Handle an event from the event queue, this may result in updating
|
||||||
# the model and thus the UI. Or it may be to tell us that the build
|
# the model and thus the UI. Or it may be to tell us that the build
|
||||||
# has finished successfully (or not, as the case may be.)
|
# has finished successfully (or not, as the case may be.)
|
||||||
@@ -76,42 +63,32 @@ class RunningBuild (gobject.GObject):
|
|||||||
# for the message.
|
# for the message.
|
||||||
if hasattr(event, 'pid'):
|
if hasattr(event, 'pid'):
|
||||||
pid = event.pid
|
pid = event.pid
|
||||||
if hasattr(event, 'process'):
|
if pid in self.pids_to_task:
|
||||||
pid = event.process
|
(package, task) = self.pids_to_task[pid]
|
||||||
|
parent = self.tasks_to_iter[(package, task)]
|
||||||
|
|
||||||
if pid and pid in self.pids_to_task:
|
if isinstance(event, bb.msg.Msg):
|
||||||
(package, task) = self.pids_to_task[pid]
|
# Set a pretty icon for the message based on it's type.
|
||||||
parent = self.tasks_to_iter[(package, task)]
|
if isinstance(event, bb.msg.MsgWarn):
|
||||||
|
|
||||||
if(isinstance(event, logging.LogRecord)):
|
|
||||||
if (event.msg.startswith ("Running task")):
|
|
||||||
return # don't add these to the list
|
|
||||||
|
|
||||||
if event.levelno >= logging.ERROR:
|
|
||||||
icon = "dialog-error"
|
|
||||||
color = Colors.ERROR
|
|
||||||
elif event.levelno >= logging.WARNING:
|
|
||||||
icon = "dialog-warning"
|
icon = "dialog-warning"
|
||||||
color = Colors.WARNING
|
elif isinstance(event, bb.msg.MsgErr):
|
||||||
|
icon = "dialog-error"
|
||||||
else:
|
else:
|
||||||
icon = None
|
icon = None
|
||||||
color = Colors.OK
|
|
||||||
|
|
||||||
# if we know which package we belong to, we'll append onto its list.
|
# Ignore the "Running task i of n .." messages
|
||||||
# otherwise, we'll jump to the top of the master list
|
if (event._message.startswith ("Running task")):
|
||||||
if parent:
|
return
|
||||||
tree_add = self.model.append
|
|
||||||
else:
|
|
||||||
tree_add = self.model.prepend
|
|
||||||
tree_add(parent,
|
|
||||||
(None,
|
|
||||||
package,
|
|
||||||
task,
|
|
||||||
event.getMessage(),
|
|
||||||
icon,
|
|
||||||
color,
|
|
||||||
0))
|
|
||||||
|
|
||||||
|
# Add the message to the tree either at the top level if parent is
|
||||||
|
# None otherwise as a descendent of a task.
|
||||||
|
self.model.append (parent,
|
||||||
|
(event.__name__.split()[-1], # e.g. MsgWarn, MsgError
|
||||||
|
package,
|
||||||
|
task,
|
||||||
|
event._message,
|
||||||
|
icon,
|
||||||
|
False))
|
||||||
elif isinstance(event, bb.build.TaskStarted):
|
elif isinstance(event, bb.build.TaskStarted):
|
||||||
(package, task) = (event._package, event._task)
|
(package, task) = (event._package, event._task)
|
||||||
|
|
||||||
@@ -124,142 +101,68 @@ class RunningBuild (gobject.GObject):
|
|||||||
if ((package, None) in self.tasks_to_iter):
|
if ((package, None) in self.tasks_to_iter):
|
||||||
parent = self.tasks_to_iter[(package, None)]
|
parent = self.tasks_to_iter[(package, None)]
|
||||||
else:
|
else:
|
||||||
parent = self.model.prepend(None, (None,
|
parent = self.model.append (None, (None,
|
||||||
package,
|
package,
|
||||||
None,
|
None,
|
||||||
"Package: %s" % (package),
|
"Package: %s" % (package),
|
||||||
None,
|
None,
|
||||||
Colors.OK,
|
False))
|
||||||
0))
|
|
||||||
self.tasks_to_iter[(package, None)] = parent
|
self.tasks_to_iter[(package, None)] = parent
|
||||||
|
|
||||||
# Because this parent package now has an active child mark it as
|
# Because this parent package now has an active child mark it as
|
||||||
# such.
|
# such.
|
||||||
# @todo if parent is already in error, don't mark it green
|
self.model.set(parent, self.model.COL_ICON, "gtk-execute")
|
||||||
self.model.set(parent, self.model.COL_ICON, "gtk-execute",
|
|
||||||
self.model.COL_COLOR, Colors.RUNNING)
|
|
||||||
|
|
||||||
# Add an entry in the model for this task
|
# Add an entry in the model for this task
|
||||||
i = self.model.append (parent, (None,
|
i = self.model.append (parent, (None,
|
||||||
package,
|
package,
|
||||||
task,
|
task,
|
||||||
"Task: %s" % (task),
|
"Task: %s" % (task),
|
||||||
"gtk-execute",
|
None,
|
||||||
Colors.RUNNING,
|
False))
|
||||||
0))
|
|
||||||
|
|
||||||
# update the parent's active task count
|
|
||||||
num_active = self.model.get(parent, self.model.COL_NUM_ACTIVE)[0] + 1
|
|
||||||
self.model.set(parent, self.model.COL_NUM_ACTIVE, num_active)
|
|
||||||
|
|
||||||
# Save out the iter so that we can find it when we have a message
|
# Save out the iter so that we can find it when we have a message
|
||||||
# that we need to attach to a task.
|
# that we need to attach to a task.
|
||||||
self.tasks_to_iter[(package, task)] = i
|
self.tasks_to_iter[(package, task)] = i
|
||||||
|
|
||||||
elif isinstance(event, bb.build.TaskBase):
|
# Mark this task as active.
|
||||||
current = self.tasks_to_iter[(package, task)]
|
self.model.set(i, self.model.COL_ICON, "gtk-execute")
|
||||||
parent = self.tasks_to_iter[(package, None)]
|
|
||||||
|
|
||||||
# remove this task from the parent's active count
|
elif isinstance(event, bb.build.Task):
|
||||||
num_active = self.model.get(parent, self.model.COL_NUM_ACTIVE)[0] - 1
|
|
||||||
self.model.set(parent, self.model.COL_NUM_ACTIVE, num_active)
|
|
||||||
|
|
||||||
if isinstance(event, bb.build.TaskFailed):
|
if isinstance(event, bb.build.TaskFailed):
|
||||||
# Mark the task and parent as failed
|
# Mark the task as failed
|
||||||
icon = "dialog-error"
|
i = self.tasks_to_iter[(package, task)]
|
||||||
color = Colors.ERROR
|
self.model.set(i, self.model.COL_ICON, "dialog-error")
|
||||||
|
|
||||||
logfile = event.logfile
|
# Mark the parent package as failed
|
||||||
if logfile and os.path.exists(logfile):
|
|
||||||
with open(logfile) as f:
|
|
||||||
logdata = f.read()
|
|
||||||
self.model.append(current, ('pastebin', None, None, logdata, 'gtk-error', Colors.OK, 0))
|
|
||||||
|
|
||||||
for i in (current, parent):
|
|
||||||
self.model.set(i, self.model.COL_ICON, icon,
|
|
||||||
self.model.COL_COLOR, color)
|
|
||||||
else:
|
|
||||||
icon = None
|
|
||||||
color = Colors.OK
|
|
||||||
|
|
||||||
# Mark the task as inactive
|
|
||||||
self.model.set(current, self.model.COL_ICON, icon,
|
|
||||||
self.model.COL_COLOR, color)
|
|
||||||
|
|
||||||
# Mark the parent package as inactive, but make sure to
|
|
||||||
# preserve error and active states
|
|
||||||
i = self.tasks_to_iter[(package, None)]
|
i = self.tasks_to_iter[(package, None)]
|
||||||
if self.model.get(parent, self.model.COL_ICON) != 'dialog-error':
|
self.model.set(i, self.model.COL_ICON, "dialog-error")
|
||||||
self.model.set(parent, self.model.COL_ICON, icon)
|
else:
|
||||||
if num_active == 0:
|
# Mark the task as inactive
|
||||||
self.model.set(parent, self.model.COL_COLOR, Colors.OK)
|
i = self.tasks_to_iter[(package, task)]
|
||||||
|
self.model.set(i, self.model.COL_ICON, None)
|
||||||
|
|
||||||
|
# Mark the parent package as inactive
|
||||||
|
i = self.tasks_to_iter[(package, None)]
|
||||||
|
self.model.set(i, self.model.COL_ICON, None)
|
||||||
|
|
||||||
|
|
||||||
# Clear the iters and the pids since when the task goes away the
|
# Clear the iters and the pids since when the task goes away the
|
||||||
# pid will no longer be used for messages
|
# pid will no longer be used for messages
|
||||||
del self.tasks_to_iter[(package, task)]
|
del self.tasks_to_iter[(package, task)]
|
||||||
del self.pids_to_task[pid]
|
del self.pids_to_task[pid]
|
||||||
|
|
||||||
elif isinstance(event, bb.event.BuildStarted):
|
|
||||||
|
|
||||||
self.model.prepend(None, (None,
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
"Build Started (%s)" % time.strftime('%m/%d/%Y %H:%M:%S'),
|
|
||||||
None,
|
|
||||||
Colors.OK,
|
|
||||||
0))
|
|
||||||
elif isinstance(event, bb.event.BuildCompleted):
|
elif isinstance(event, bb.event.BuildCompleted):
|
||||||
failures = int (event._failures)
|
failures = int (event._failures)
|
||||||
self.model.prepend(None, (None,
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
"Build Completed (%s)" % time.strftime('%m/%d/%Y %H:%M:%S'),
|
|
||||||
None,
|
|
||||||
Colors.OK,
|
|
||||||
0))
|
|
||||||
|
|
||||||
# Emit the appropriate signal depending on the number of failures
|
# Emit the appropriate signal depending on the number of failures
|
||||||
if (failures >= 1):
|
if (failures > 1):
|
||||||
self.emit ("build-failed")
|
self.emit ("build-failed")
|
||||||
else:
|
else:
|
||||||
self.emit ("build-succeeded")
|
self.emit ("build-succeeded")
|
||||||
|
|
||||||
elif isinstance(event, bb.event.CacheLoadStarted) and pbar:
|
|
||||||
pbar.set_title("Loading cache")
|
|
||||||
self.progress_total = event.total
|
|
||||||
pbar.update(0, self.progress_total)
|
|
||||||
elif isinstance(event, bb.event.CacheLoadProgress) and pbar:
|
|
||||||
pbar.update(event.current, self.progress_total)
|
|
||||||
elif isinstance(event, bb.event.CacheLoadCompleted) and pbar:
|
|
||||||
pbar.update(self.progress_total, self.progress_total)
|
|
||||||
|
|
||||||
elif isinstance(event, bb.event.ParseStarted) and pbar:
|
|
||||||
pbar.set_title("Processing recipes")
|
|
||||||
self.progress_total = event.total
|
|
||||||
pbar.update(0, self.progress_total)
|
|
||||||
elif isinstance(event, bb.event.ParseProgress) and pbar:
|
|
||||||
pbar.update(event.current, self.progress_total)
|
|
||||||
elif isinstance(event, bb.event.ParseCompleted) and pbar:
|
|
||||||
pbar.hide()
|
|
||||||
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
def do_pastebin(text):
|
|
||||||
url = 'http://pastebin.com/api_public.php'
|
|
||||||
params = {'paste_code': text, 'paste_format': 'text'}
|
|
||||||
|
|
||||||
req = urllib2.Request(url, urllib.urlencode(params))
|
|
||||||
response = urllib2.urlopen(req)
|
|
||||||
paste_url = response.read()
|
|
||||||
|
|
||||||
return paste_url
|
|
||||||
|
|
||||||
|
|
||||||
class RunningBuildTreeView (gtk.TreeView):
|
class RunningBuildTreeView (gtk.TreeView):
|
||||||
__gsignals__ = {
|
|
||||||
"button_press_event" : "override"
|
|
||||||
}
|
|
||||||
def __init__ (self):
|
def __init__ (self):
|
||||||
gtk.TreeView.__init__ (self)
|
gtk.TreeView.__init__ (self)
|
||||||
|
|
||||||
@@ -270,42 +173,6 @@ class RunningBuildTreeView (gtk.TreeView):
|
|||||||
self.append_column (col)
|
self.append_column (col)
|
||||||
|
|
||||||
# The message of the build.
|
# The message of the build.
|
||||||
self.message_renderer = gtk.CellRendererText ()
|
renderer = gtk.CellRendererText ()
|
||||||
self.message_column = gtk.TreeViewColumn ("Message", self.message_renderer, text=3)
|
col = gtk.TreeViewColumn ("Message", renderer, text=3)
|
||||||
self.message_column.add_attribute(self.message_renderer, 'background', 5)
|
self.append_column (col)
|
||||||
self.message_renderer.set_property('editable', 5)
|
|
||||||
self.append_column (self.message_column)
|
|
||||||
|
|
||||||
def do_button_press_event(self, event):
|
|
||||||
gtk.TreeView.do_button_press_event(self, event)
|
|
||||||
|
|
||||||
if event.button == 3:
|
|
||||||
selection = super(RunningBuildTreeView, self).get_selection()
|
|
||||||
(model, iter) = selection.get_selected()
|
|
||||||
if iter is not None:
|
|
||||||
can_paste = model.get(iter, model.COL_LOG)[0]
|
|
||||||
if can_paste == 'pastebin':
|
|
||||||
# build a simple menu with a pastebin option
|
|
||||||
menu = gtk.Menu()
|
|
||||||
menuitem = gtk.MenuItem("Send log to pastebin")
|
|
||||||
menu.append(menuitem)
|
|
||||||
menuitem.connect("activate", self.pastebin_handler, (model, iter))
|
|
||||||
menuitem.show()
|
|
||||||
menu.show()
|
|
||||||
menu.popup(None, None, None, event.button, event.time)
|
|
||||||
|
|
||||||
def pastebin_handler(self, widget, data):
|
|
||||||
"""
|
|
||||||
Send the log data to pastebin, then add the new paste url to the
|
|
||||||
clipboard.
|
|
||||||
"""
|
|
||||||
(model, iter) = data
|
|
||||||
paste_url = do_pastebin(model.get(iter, model.COL_MESSAGE)[0])
|
|
||||||
|
|
||||||
# @todo Provide visual feedback to the user that it is done and that
|
|
||||||
# it worked.
|
|
||||||
print paste_url
|
|
||||||
|
|
||||||
clipboard = gtk.clipboard_get()
|
|
||||||
clipboard.set_text(paste_url)
|
|
||||||
clipboard.store()
|
|
||||||
|
|||||||
@@ -1,346 +0,0 @@
|
|||||||
#
|
|
||||||
# BitBake Graphical GTK User Interface
|
|
||||||
#
|
|
||||||
# Copyright (C) 2011 Intel Corporation
|
|
||||||
#
|
|
||||||
# Authored by Joshua Lock <josh@linux.intel.com>
|
|
||||||
#
|
|
||||||
# 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 gtk
|
|
||||||
import gobject
|
|
||||||
|
|
||||||
class TaskListModel(gtk.ListStore):
|
|
||||||
"""
|
|
||||||
This class defines an gtk.ListStore subclass which will convert the output
|
|
||||||
of the bb.event.TargetsTreeGenerated event into a gtk.ListStore whilst also
|
|
||||||
providing convenience functions to access gtk.TreeModel subclasses which
|
|
||||||
provide filtered views of the data.
|
|
||||||
"""
|
|
||||||
(COL_NAME, COL_DESC, COL_LIC, COL_GROUP, COL_DEPS, COL_BINB, COL_TYPE, COL_INC) = range(8)
|
|
||||||
|
|
||||||
__gsignals__ = {
|
|
||||||
"tasklist-populated" : (gobject.SIGNAL_RUN_LAST,
|
|
||||||
gobject.TYPE_NONE,
|
|
||||||
())
|
|
||||||
}
|
|
||||||
|
|
||||||
"""
|
|
||||||
"""
|
|
||||||
def __init__(self):
|
|
||||||
self.contents = None
|
|
||||||
self.tasks = None
|
|
||||||
self.packages = None
|
|
||||||
self.images = None
|
|
||||||
|
|
||||||
gtk.ListStore.__init__ (self,
|
|
||||||
gobject.TYPE_STRING,
|
|
||||||
gobject.TYPE_STRING,
|
|
||||||
gobject.TYPE_STRING,
|
|
||||||
gobject.TYPE_STRING,
|
|
||||||
gobject.TYPE_STRING,
|
|
||||||
gobject.TYPE_STRING,
|
|
||||||
gobject.TYPE_STRING,
|
|
||||||
gobject.TYPE_BOOLEAN)
|
|
||||||
|
|
||||||
"""
|
|
||||||
Create, if required, and return a filtered gtk.TreeModel
|
|
||||||
containing only the items which are to be included in the
|
|
||||||
image
|
|
||||||
"""
|
|
||||||
def contents_model(self):
|
|
||||||
if not self.contents:
|
|
||||||
self.contents = self.filter_new()
|
|
||||||
self.contents.set_visible_column(self.COL_INC)
|
|
||||||
return self.contents
|
|
||||||
|
|
||||||
"""
|
|
||||||
Helper function to determine whether an item is a task
|
|
||||||
"""
|
|
||||||
def task_model_filter(self, model, it):
|
|
||||||
if model.get_value(it, self.COL_TYPE) == 'task':
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
return False
|
|
||||||
|
|
||||||
"""
|
|
||||||
Create, if required, and return a filtered gtk.TreeModel
|
|
||||||
containing only the items which are tasks
|
|
||||||
"""
|
|
||||||
def tasks_model(self):
|
|
||||||
if not self.tasks:
|
|
||||||
self.tasks = self.filter_new()
|
|
||||||
self.tasks.set_visible_func(self.task_model_filter)
|
|
||||||
return self.tasks
|
|
||||||
|
|
||||||
"""
|
|
||||||
Helper function to determine whether an item is an image
|
|
||||||
"""
|
|
||||||
def image_model_filter(self, model, it):
|
|
||||||
if model.get_value(it, self.COL_TYPE) == 'image':
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
return False
|
|
||||||
|
|
||||||
"""
|
|
||||||
Create, if required, and return a filtered gtk.TreeModel
|
|
||||||
containing only the items which are images
|
|
||||||
"""
|
|
||||||
def images_model(self):
|
|
||||||
if not self.images:
|
|
||||||
self.images = self.filter_new()
|
|
||||||
self.images.set_visible_func(self.image_model_filter)
|
|
||||||
return self.images
|
|
||||||
|
|
||||||
"""
|
|
||||||
Helper function to determine whether an item is a package
|
|
||||||
"""
|
|
||||||
def package_model_filter(self, model, it):
|
|
||||||
if model.get_value(it, self.COL_TYPE) == 'package':
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
return False
|
|
||||||
|
|
||||||
"""
|
|
||||||
Create, if required, and return a filtered gtk.TreeModel
|
|
||||||
containing only the items which are packages
|
|
||||||
"""
|
|
||||||
def packages_model(self):
|
|
||||||
if not self.packages:
|
|
||||||
self.packages = self.filter_new()
|
|
||||||
self.packages.set_visible_func(self.package_model_filter)
|
|
||||||
return self.packages
|
|
||||||
|
|
||||||
"""
|
|
||||||
The populate() function takes as input the data from a
|
|
||||||
bb.event.TargetsTreeGenerated event and populates the TaskList.
|
|
||||||
Once the population is done it emits gsignal tasklist-populated
|
|
||||||
to notify any listeners that the model is ready
|
|
||||||
"""
|
|
||||||
def populate(self, event_model):
|
|
||||||
for item in event_model["pn"]:
|
|
||||||
atype = 'package'
|
|
||||||
name = item
|
|
||||||
summary = event_model["pn"][item]["summary"]
|
|
||||||
license = event_model["pn"][item]["license"]
|
|
||||||
group = event_model["pn"][item]["section"]
|
|
||||||
|
|
||||||
depends = event_model["depends"].get(item, "")
|
|
||||||
rdepends = event_model["rdepends-pn"].get(item, "")
|
|
||||||
depends = depends + rdepends
|
|
||||||
self.squish(depends)
|
|
||||||
deps = " ".join(depends)
|
|
||||||
|
|
||||||
if name.count('task-') > 0:
|
|
||||||
atype = 'task'
|
|
||||||
elif name.count('-image-') > 0:
|
|
||||||
atype = 'image'
|
|
||||||
|
|
||||||
self.set(self.append(), self.COL_NAME, name, self.COL_DESC, summary,
|
|
||||||
self.COL_LIC, license, self.COL_GROUP, group,
|
|
||||||
self.COL_DEPS, deps, self.COL_BINB, "",
|
|
||||||
self.COL_TYPE, atype, self.COL_INC, False)
|
|
||||||
|
|
||||||
self.emit("tasklist-populated")
|
|
||||||
|
|
||||||
"""
|
|
||||||
squish lst so that it doesn't contain any duplicates
|
|
||||||
"""
|
|
||||||
def squish(self, lst):
|
|
||||||
seen = {}
|
|
||||||
for l in lst:
|
|
||||||
seen[l] = 1
|
|
||||||
return seen.keys()
|
|
||||||
|
|
||||||
"""
|
|
||||||
Mark the item at path as not included
|
|
||||||
NOTE:
|
|
||||||
path should be a gtk.TreeModelPath into self (not a filtered model)
|
|
||||||
"""
|
|
||||||
def remove_item_path(self, path):
|
|
||||||
self[path][self.COL_BINB] = ""
|
|
||||||
self[path][self.COL_INC] = False
|
|
||||||
|
|
||||||
"""
|
|
||||||
"""
|
|
||||||
def mark(self, path):
|
|
||||||
name = self[path][self.COL_NAME]
|
|
||||||
it = self.get_iter_first()
|
|
||||||
removals = []
|
|
||||||
#print("Removing %s" % name)
|
|
||||||
|
|
||||||
self.remove_item_path(path)
|
|
||||||
|
|
||||||
# Remove all dependent packages, update binb
|
|
||||||
while it:
|
|
||||||
path = self.get_path(it)
|
|
||||||
# FIXME: need to ensure partial name matching doesn't happen, regexp?
|
|
||||||
if self[path][self.COL_INC] and self[path][self.COL_DEPS].count(name):
|
|
||||||
#print("%s depended on %s, marking for removal" % (self[path][self.COL_NAME], name))
|
|
||||||
# found a dependency, remove it
|
|
||||||
self.mark(path)
|
|
||||||
if self[path][self.COL_INC] and self[path][self.COL_BINB].count(name):
|
|
||||||
binb = self.find_alt_dependency(self[path][self.COL_NAME])
|
|
||||||
#print("%s was brought in by %s, binb set to %s" % (self[path][self.COL_NAME], name, binb))
|
|
||||||
self[path][self.COL_BINB] = binb
|
|
||||||
it = self.iter_next(it)
|
|
||||||
|
|
||||||
"""
|
|
||||||
"""
|
|
||||||
def sweep_up(self):
|
|
||||||
removals = []
|
|
||||||
it = self.get_iter_first()
|
|
||||||
|
|
||||||
while it:
|
|
||||||
path = self.get_path(it)
|
|
||||||
binb = self[path][self.COL_BINB]
|
|
||||||
if binb == "" or binb is None:
|
|
||||||
#print("Sweeping up %s" % self[path][self.COL_NAME])
|
|
||||||
if not path in removals:
|
|
||||||
removals.extend(path)
|
|
||||||
it = self.iter_next(it)
|
|
||||||
|
|
||||||
while removals:
|
|
||||||
path = removals.pop()
|
|
||||||
self.mark(path)
|
|
||||||
|
|
||||||
"""
|
|
||||||
Remove an item from the contents
|
|
||||||
"""
|
|
||||||
def remove_item(self, path):
|
|
||||||
self.mark(path)
|
|
||||||
self.sweep_up()
|
|
||||||
|
|
||||||
"""
|
|
||||||
Find the name of an item in the image contents which depends on the item
|
|
||||||
at contents_path returns either an item name (str) or None
|
|
||||||
NOTE:
|
|
||||||
contents_path must be a path in the self.contents gtk.TreeModel
|
|
||||||
"""
|
|
||||||
def find_alt_dependency(self, name):
|
|
||||||
it = self.get_iter_first()
|
|
||||||
while it:
|
|
||||||
# iterate all items in the model
|
|
||||||
path = self.get_path(it)
|
|
||||||
deps = self[path][self.COL_DEPS]
|
|
||||||
itname = self[path][self.COL_NAME]
|
|
||||||
inc = self[path][self.COL_INC]
|
|
||||||
if itname != name and inc and deps.count(name) > 0:
|
|
||||||
# if this item depends on the item, return this items name
|
|
||||||
#print("%s depends on %s" % (itname, name))
|
|
||||||
return itname
|
|
||||||
it = self.iter_next(it)
|
|
||||||
return ""
|
|
||||||
|
|
||||||
"""
|
|
||||||
Convert a path in self to a path in the filtered contents model
|
|
||||||
"""
|
|
||||||
def contents_path_for_path(self, path):
|
|
||||||
return self.contents.convert_child_path_to_path(path)
|
|
||||||
|
|
||||||
"""
|
|
||||||
Check the self.contents gtk.TreeModel for an item
|
|
||||||
where COL_NAME matches item_name
|
|
||||||
Returns True if a match is found, False otherwise
|
|
||||||
"""
|
|
||||||
def contents_includes_name(self, item_name):
|
|
||||||
it = self.contents.get_iter_first()
|
|
||||||
while it:
|
|
||||||
path = self.contents.get_path(it)
|
|
||||||
if self.contents[path][self.COL_NAME] == item_name:
|
|
||||||
return True
|
|
||||||
it = self.contents.iter_next(it)
|
|
||||||
return False
|
|
||||||
|
|
||||||
"""
|
|
||||||
Add this item, and any of its dependencies, to the image contents
|
|
||||||
"""
|
|
||||||
def include_item(self, item_path, binb=""):
|
|
||||||
name = self[item_path][self.COL_NAME]
|
|
||||||
deps = self[item_path][self.COL_DEPS]
|
|
||||||
cur_inc = self[item_path][self.COL_INC]
|
|
||||||
#print("Adding %s for %s dependency" % (name, binb))
|
|
||||||
if not cur_inc:
|
|
||||||
self[item_path][self.COL_INC] = True
|
|
||||||
self[item_path][self.COL_BINB] = binb
|
|
||||||
if deps:
|
|
||||||
#print("Dependencies of %s are %s" % (name, deps))
|
|
||||||
# add all of the deps and set their binb to this item
|
|
||||||
for dep in deps.split(" "):
|
|
||||||
# FIXME: this skipping virtuals can't be right? Unless we choose only to show target
|
|
||||||
# packages? In which case we should handle this server side...
|
|
||||||
# If the contents model doesn't already contain dep, add it
|
|
||||||
if not dep.startswith("virtual") and not self.contents_includes_name(dep):
|
|
||||||
path = self.find_path_for_item(dep)
|
|
||||||
if path:
|
|
||||||
self.include_item(path, name)
|
|
||||||
else:
|
|
||||||
pass
|
|
||||||
|
|
||||||
"""
|
|
||||||
Find the model path for the item_name
|
|
||||||
Returns the path in the model or None
|
|
||||||
"""
|
|
||||||
def find_path_for_item(self, item_name):
|
|
||||||
it = self.get_iter_first()
|
|
||||||
path = None
|
|
||||||
while it:
|
|
||||||
path = self.get_path(it)
|
|
||||||
if (self[path][self.COL_NAME] == item_name):
|
|
||||||
return path
|
|
||||||
else:
|
|
||||||
it = self.iter_next(it)
|
|
||||||
return None
|
|
||||||
|
|
||||||
"""
|
|
||||||
Empty self.contents by setting the include of each entry to None
|
|
||||||
"""
|
|
||||||
def reset(self):
|
|
||||||
it = self.contents.get_iter_first()
|
|
||||||
while it:
|
|
||||||
path = self.contents.get_path(it)
|
|
||||||
opath = self.contents.convert_path_to_child_path(path)
|
|
||||||
self[opath][self.COL_INC] = False
|
|
||||||
self[opath][self.COL_BINB] = ""
|
|
||||||
# As we've just removed the first item...
|
|
||||||
it = self.contents.get_iter_first()
|
|
||||||
|
|
||||||
"""
|
|
||||||
Returns True if one of the selected tasks is an image, False otherwise
|
|
||||||
"""
|
|
||||||
def targets_contains_image(self):
|
|
||||||
it = self.images.get_iter_first()
|
|
||||||
while it:
|
|
||||||
path = self.images.get_path(it)
|
|
||||||
inc = self.images[path][self.COL_INC]
|
|
||||||
if inc:
|
|
||||||
return True
|
|
||||||
it = self.images.iter_next(it)
|
|
||||||
return False
|
|
||||||
|
|
||||||
"""
|
|
||||||
Return a list of all selected items which are not -native or -cross
|
|
||||||
"""
|
|
||||||
def get_targets(self):
|
|
||||||
tasks = []
|
|
||||||
|
|
||||||
it = self.contents.get_iter_first()
|
|
||||||
while it:
|
|
||||||
path = self.contents.get_path(it)
|
|
||||||
name = self.contents[path][self.COL_NAME]
|
|
||||||
stype = self.contents[path][self.COL_TYPE]
|
|
||||||
if not name.count('-native') and not name.count('-cross'):
|
|
||||||
tasks.append(name)
|
|
||||||
it = self.contents.iter_next(it)
|
|
||||||
return tasks
|
|
||||||
@@ -19,12 +19,8 @@
|
|||||||
|
|
||||||
import gobject
|
import gobject
|
||||||
import gtk
|
import gtk
|
||||||
import Queue
|
|
||||||
import threading
|
import threading
|
||||||
import xmlrpclib
|
import xmlrpclib
|
||||||
import bb
|
|
||||||
import bb.event
|
|
||||||
from bb.ui.crumbs.progress import ProgressBar
|
|
||||||
|
|
||||||
# Package Model
|
# Package Model
|
||||||
(COL_PKG_NAME) = (0)
|
(COL_PKG_NAME) = (0)
|
||||||
@@ -33,7 +29,6 @@ from bb.ui.crumbs.progress import ProgressBar
|
|||||||
(TYPE_DEP, TYPE_RDEP) = (0, 1)
|
(TYPE_DEP, TYPE_RDEP) = (0, 1)
|
||||||
(COL_DEP_TYPE, COL_DEP_PARENT, COL_DEP_PACKAGE) = (0, 1, 2)
|
(COL_DEP_TYPE, COL_DEP_PARENT, COL_DEP_PACKAGE) = (0, 1, 2)
|
||||||
|
|
||||||
|
|
||||||
class PackageDepView(gtk.TreeView):
|
class PackageDepView(gtk.TreeView):
|
||||||
def __init__(self, model, dep_type, label):
|
def __init__(self, model, dep_type, label):
|
||||||
gtk.TreeView.__init__(self)
|
gtk.TreeView.__init__(self)
|
||||||
@@ -54,7 +49,6 @@ class PackageDepView(gtk.TreeView):
|
|||||||
self.current = package
|
self.current = package
|
||||||
self.filter_model.refilter()
|
self.filter_model.refilter()
|
||||||
|
|
||||||
|
|
||||||
class PackageReverseDepView(gtk.TreeView):
|
class PackageReverseDepView(gtk.TreeView):
|
||||||
def __init__(self, model, label):
|
def __init__(self, model, label):
|
||||||
gtk.TreeView.__init__(self)
|
gtk.TreeView.__init__(self)
|
||||||
@@ -72,7 +66,6 @@ class PackageReverseDepView(gtk.TreeView):
|
|||||||
self.current = package
|
self.current = package
|
||||||
self.filter_model.refilter()
|
self.filter_model.refilter()
|
||||||
|
|
||||||
|
|
||||||
class DepExplorer(gtk.Window):
|
class DepExplorer(gtk.Window):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
gtk.Window.__init__(self)
|
gtk.Window.__init__(self)
|
||||||
@@ -82,9 +75,7 @@ class DepExplorer(gtk.Window):
|
|||||||
|
|
||||||
# Create the data models
|
# Create the data models
|
||||||
self.pkg_model = gtk.ListStore(gobject.TYPE_STRING)
|
self.pkg_model = gtk.ListStore(gobject.TYPE_STRING)
|
||||||
self.pkg_model.set_sort_column_id(COL_PKG_NAME, gtk.SORT_ASCENDING)
|
|
||||||
self.depends_model = gtk.ListStore(gobject.TYPE_INT, gobject.TYPE_STRING, gobject.TYPE_STRING)
|
self.depends_model = gtk.ListStore(gobject.TYPE_INT, gobject.TYPE_STRING, gobject.TYPE_STRING)
|
||||||
self.depends_model.set_sort_column_id(COL_DEP_PACKAGE, gtk.SORT_ASCENDING)
|
|
||||||
|
|
||||||
pane = gtk.HPaned()
|
pane = gtk.HPaned()
|
||||||
pane.set_position(250)
|
pane.set_position(250)
|
||||||
@@ -94,11 +85,9 @@ class DepExplorer(gtk.Window):
|
|||||||
scrolled = gtk.ScrolledWindow()
|
scrolled = gtk.ScrolledWindow()
|
||||||
scrolled.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
|
scrolled.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
|
||||||
scrolled.set_shadow_type(gtk.SHADOW_IN)
|
scrolled.set_shadow_type(gtk.SHADOW_IN)
|
||||||
|
|
||||||
self.pkg_treeview = gtk.TreeView(self.pkg_model)
|
self.pkg_treeview = gtk.TreeView(self.pkg_model)
|
||||||
self.pkg_treeview.get_selection().connect("changed", self.on_cursor_changed)
|
self.pkg_treeview.get_selection().connect("changed", self.on_cursor_changed)
|
||||||
column = gtk.TreeViewColumn("Package", gtk.CellRendererText(), text=COL_PKG_NAME)
|
self.pkg_treeview.append_column(gtk.TreeViewColumn("Package", gtk.CellRendererText(), text=COL_PKG_NAME))
|
||||||
self.pkg_treeview.append_column(column)
|
|
||||||
pane.add1(scrolled)
|
pane.add1(scrolled)
|
||||||
scrolled.add(self.pkg_treeview)
|
scrolled.add(self.pkg_treeview)
|
||||||
|
|
||||||
@@ -164,6 +153,7 @@ class DepExplorer(gtk.Window):
|
|||||||
|
|
||||||
|
|
||||||
def parse(depgraph, pkg_model, depends_model):
|
def parse(depgraph, pkg_model, depends_model):
|
||||||
|
|
||||||
for package in depgraph["pn"]:
|
for package in depgraph["pn"]:
|
||||||
pkg_model.set(pkg_model.append(), COL_PKG_NAME, package)
|
pkg_model.set(pkg_model.append(), COL_PKG_NAME, package)
|
||||||
|
|
||||||
@@ -181,6 +171,17 @@ def parse(depgraph, pkg_model, depends_model):
|
|||||||
COL_DEP_PARENT, package,
|
COL_DEP_PARENT, package,
|
||||||
COL_DEP_PACKAGE, rdepend)
|
COL_DEP_PACKAGE, rdepend)
|
||||||
|
|
||||||
|
class ProgressBar(gtk.Window):
|
||||||
|
def __init__(self):
|
||||||
|
|
||||||
|
gtk.Window.__init__(self)
|
||||||
|
self.set_title("Parsing .bb files, please wait...")
|
||||||
|
self.set_default_size(500, 0)
|
||||||
|
self.connect("delete-event", gtk.main_quit)
|
||||||
|
|
||||||
|
self.progress = gtk.ProgressBar()
|
||||||
|
self.add(self.progress)
|
||||||
|
self.show_all()
|
||||||
|
|
||||||
class gtkthread(threading.Thread):
|
class gtkthread(threading.Thread):
|
||||||
quit = threading.Event()
|
quit = threading.Event()
|
||||||
@@ -195,8 +196,8 @@ class gtkthread(threading.Thread):
|
|||||||
gtk.main()
|
gtk.main()
|
||||||
gtkthread.quit.set()
|
gtkthread.quit.set()
|
||||||
|
|
||||||
|
def init(server, eventHandler):
|
||||||
|
|
||||||
def main(server, eventHandler):
|
|
||||||
try:
|
try:
|
||||||
cmdline = server.runCommand(["getCmdLineAction"])
|
cmdline = server.runCommand(["getCmdLineAction"])
|
||||||
if not cmdline or cmdline[0] != "generateDotGraph":
|
if not cmdline or cmdline[0] != "generateDotGraph":
|
||||||
@@ -216,83 +217,46 @@ def main(server, eventHandler):
|
|||||||
gtkgui.start()
|
gtkgui.start()
|
||||||
|
|
||||||
gtk.gdk.threads_enter()
|
gtk.gdk.threads_enter()
|
||||||
|
pbar = ProgressBar()
|
||||||
dep = DepExplorer()
|
dep = DepExplorer()
|
||||||
pbar = ProgressBar(dep)
|
|
||||||
pbar.connect("delete-event", gtk.main_quit)
|
|
||||||
gtk.gdk.threads_leave()
|
gtk.gdk.threads_leave()
|
||||||
|
|
||||||
progress_total = 0
|
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
event = eventHandler.waitEvent(0.25)
|
event = eventHandler.waitEvent(0.25)
|
||||||
if gtkthread.quit.isSet():
|
if gtkthread.quit.isSet():
|
||||||
server.runCommand(["stateStop"])
|
|
||||||
break
|
break
|
||||||
|
|
||||||
if event is None:
|
if event is None:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if isinstance(event, bb.event.CacheLoadStarted):
|
|
||||||
progress_total = event.total
|
|
||||||
gtk.gdk.threads_enter()
|
|
||||||
pbar.set_title("Loading Cache")
|
|
||||||
pbar.update(0, progress_total)
|
|
||||||
gtk.gdk.threads_leave()
|
|
||||||
|
|
||||||
if isinstance(event, bb.event.CacheLoadProgress):
|
|
||||||
x = event.current
|
|
||||||
gtk.gdk.threads_enter()
|
|
||||||
pbar.update(x, progress_total)
|
|
||||||
gtk.gdk.threads_leave()
|
|
||||||
continue
|
|
||||||
|
|
||||||
if isinstance(event, bb.event.CacheLoadCompleted):
|
|
||||||
gtk.gdk.threads_enter()
|
|
||||||
pbar.update(progress_total, progress_total)
|
|
||||||
gtk.gdk.threads_leave()
|
|
||||||
continue
|
|
||||||
|
|
||||||
if isinstance(event, bb.event.ParseStarted):
|
|
||||||
progress_total = event.total
|
|
||||||
gtk.gdk.threads_enter()
|
|
||||||
pbar.set_title("Processing recipes")
|
|
||||||
pbar.update(0, progress_total)
|
|
||||||
gtk.gdk.threads_leave()
|
|
||||||
|
|
||||||
if isinstance(event, bb.event.ParseProgress):
|
if isinstance(event, bb.event.ParseProgress):
|
||||||
x = event.current
|
x = event.sofar
|
||||||
|
y = event.total
|
||||||
|
if x == y:
|
||||||
|
print(("\nParsing finished. %d cached, %d parsed, %d skipped, %d masked, %d errors."
|
||||||
|
% ( event.cached, event.parsed, event.skipped, event.masked, event.errors)))
|
||||||
|
pbar.hide()
|
||||||
gtk.gdk.threads_enter()
|
gtk.gdk.threads_enter()
|
||||||
pbar.update(x, progress_total)
|
pbar.progress.set_fraction(float(x)/float(y))
|
||||||
|
pbar.progress.set_text("%d/%d (%2d %%)" % (x, y, x*100/y))
|
||||||
gtk.gdk.threads_leave()
|
gtk.gdk.threads_leave()
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if isinstance(event, bb.event.ParseCompleted):
|
|
||||||
pbar.hide()
|
|
||||||
continue
|
|
||||||
|
|
||||||
if isinstance(event, bb.event.DepTreeGenerated):
|
if isinstance(event, bb.event.DepTreeGenerated):
|
||||||
gtk.gdk.threads_enter()
|
gtk.gdk.threads_enter()
|
||||||
parse(event._depgraph, dep.pkg_model, dep.depends_model)
|
parse(event._depgraph, dep.pkg_model, dep.depends_model)
|
||||||
gtk.gdk.threads_leave()
|
gtk.gdk.threads_leave()
|
||||||
|
|
||||||
if isinstance(event, bb.command.CommandCompleted):
|
if isinstance(event, bb.command.CookerCommandCompleted):
|
||||||
continue
|
continue
|
||||||
|
if isinstance(event, bb.command.CookerCommandFailed):
|
||||||
if isinstance(event, bb.command.CommandFailed):
|
|
||||||
print("Command execution failed: %s" % event.error)
|
print("Command execution failed: %s" % event.error)
|
||||||
return event.exitcode
|
break
|
||||||
|
|
||||||
if isinstance(event, bb.command.CommandExit):
|
|
||||||
return event.exitcode
|
|
||||||
|
|
||||||
if isinstance(event, bb.cooker.CookerExit):
|
if isinstance(event, bb.cooker.CookerExit):
|
||||||
break
|
break
|
||||||
|
|
||||||
continue
|
continue
|
||||||
except EnvironmentError as ioerror:
|
|
||||||
# ignore interrupted io
|
|
||||||
if ioerror.args[0] == 4:
|
|
||||||
pass
|
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
if shutdown == 2:
|
if shutdown == 2:
|
||||||
print("\nThird Keyboard Interrupt, exit.\n")
|
print("\nThird Keyboard Interrupt, exit.\n")
|
||||||
|
|||||||
@@ -22,34 +22,17 @@ import gobject
|
|||||||
import gtk
|
import gtk
|
||||||
import xmlrpclib
|
import xmlrpclib
|
||||||
from bb.ui.crumbs.runningbuild import RunningBuildTreeView, RunningBuild
|
from bb.ui.crumbs.runningbuild import RunningBuildTreeView, RunningBuild
|
||||||
from bb.ui.crumbs.progress import ProgressBar
|
|
||||||
|
|
||||||
import Queue
|
def event_handle_idle_func (eventHandler, build):
|
||||||
|
|
||||||
|
|
||||||
def event_handle_idle_func (eventHandler, build, pbar):
|
|
||||||
|
|
||||||
# Consume as many messages as we can in the time available to us
|
# Consume as many messages as we can in the time available to us
|
||||||
event = eventHandler.getEvent()
|
event = eventHandler.getEvent()
|
||||||
while event:
|
while event:
|
||||||
build.handle_event (event, pbar)
|
build.handle_event (event)
|
||||||
event = eventHandler.getEvent()
|
event = eventHandler.getEvent()
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def scroll_tv_cb (model, path, iter, view):
|
|
||||||
view.scroll_to_cell (path)
|
|
||||||
|
|
||||||
|
|
||||||
# @todo hook these into the GUI so the user has feedback...
|
|
||||||
def running_build_failed_cb (running_build):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
def running_build_succeeded_cb (running_build):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class MainWindow (gtk.Window):
|
class MainWindow (gtk.Window):
|
||||||
def __init__ (self):
|
def __init__ (self):
|
||||||
gtk.Window.__init__ (self, gtk.WINDOW_TOPLEVEL)
|
gtk.Window.__init__ (self, gtk.WINDOW_TOPLEVEL)
|
||||||
@@ -58,29 +41,21 @@ class MainWindow (gtk.Window):
|
|||||||
scrolled_window = gtk.ScrolledWindow ()
|
scrolled_window = gtk.ScrolledWindow ()
|
||||||
self.add (scrolled_window)
|
self.add (scrolled_window)
|
||||||
self.cur_build_tv = RunningBuildTreeView()
|
self.cur_build_tv = RunningBuildTreeView()
|
||||||
self.connect("delete-event", gtk.main_quit)
|
|
||||||
self.set_default_size(640, 480)
|
|
||||||
scrolled_window.add (self.cur_build_tv)
|
scrolled_window.add (self.cur_build_tv)
|
||||||
|
|
||||||
|
def init (server, eventHandler):
|
||||||
def main (server, eventHandler):
|
|
||||||
gobject.threads_init()
|
gobject.threads_init()
|
||||||
gtk.gdk.threads_init()
|
gtk.gdk.threads_init()
|
||||||
|
|
||||||
window = MainWindow ()
|
window = MainWindow ()
|
||||||
window.show_all ()
|
window.show_all ()
|
||||||
pbar = ProgressBar(window)
|
|
||||||
pbar.connect("delete-event", gtk.main_quit)
|
|
||||||
|
|
||||||
# Create the object for the current build
|
# Create the object for the current build
|
||||||
running_build = RunningBuild ()
|
running_build = RunningBuild ()
|
||||||
window.cur_build_tv.set_model (running_build.model)
|
window.cur_build_tv.set_model (running_build.model)
|
||||||
running_build.model.connect("row-inserted", scroll_tv_cb, window.cur_build_tv)
|
|
||||||
running_build.connect ("build-succeeded", running_build_succeeded_cb)
|
|
||||||
running_build.connect ("build-failed", running_build_failed_cb)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
cmdline = server.runCommand(["getCmdLineAction"])
|
cmdline = server.runCommand(["getCmdLineAction"])
|
||||||
|
print(cmdline)
|
||||||
if not cmdline:
|
if not cmdline:
|
||||||
return 1
|
return 1
|
||||||
ret = server.runCommand(cmdline)
|
ret = server.runCommand(cmdline)
|
||||||
@@ -93,18 +68,9 @@ def main (server, eventHandler):
|
|||||||
|
|
||||||
# Use a timeout function for probing the event queue to find out if we
|
# Use a timeout function for probing the event queue to find out if we
|
||||||
# have a message waiting for us.
|
# have a message waiting for us.
|
||||||
gobject.timeout_add (100,
|
gobject.timeout_add (200,
|
||||||
event_handle_idle_func,
|
event_handle_idle_func,
|
||||||
eventHandler,
|
eventHandler,
|
||||||
running_build,
|
running_build)
|
||||||
pbar)
|
|
||||||
|
|
||||||
try:
|
|
||||||
gtk.main()
|
|
||||||
except EnvironmentError as ioerror:
|
|
||||||
# ignore interrupted io
|
|
||||||
if ioerror.args[0] == 4:
|
|
||||||
pass
|
|
||||||
finally:
|
|
||||||
server.runCommand(["stateStop"])
|
|
||||||
|
|
||||||
|
gtk.main()
|
||||||
|
|||||||
@@ -1,596 +0,0 @@
|
|||||||
#
|
|
||||||
# BitBake Graphical GTK User Interface
|
|
||||||
#
|
|
||||||
# Copyright (C) 2011 Intel Corporation
|
|
||||||
#
|
|
||||||
# Authored by Joshua Lock <josh@linux.intel.com>
|
|
||||||
#
|
|
||||||
# This program is free software; you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU General Public License version 2 as
|
|
||||||
# published by the Free Software Foundation.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License along
|
|
||||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
|
|
||||||
import gobject
|
|
||||||
import gtk
|
|
||||||
from bb.ui.crumbs.progress import ProgressBar
|
|
||||||
from bb.ui.crumbs.tasklistmodel import TaskListModel
|
|
||||||
from bb.ui.crumbs.hobeventhandler import HobHandler
|
|
||||||
from bb.ui.crumbs.runningbuild import RunningBuildTreeView, RunningBuild
|
|
||||||
import xmlrpclib
|
|
||||||
import logging
|
|
||||||
import Queue
|
|
||||||
|
|
||||||
class MainWindow (gtk.Window):
|
|
||||||
|
|
||||||
def __init__(self, taskmodel, handler, curr_mach=None, curr_distro=None):
|
|
||||||
gtk.Window.__init__(self, gtk.WINDOW_TOPLEVEL)
|
|
||||||
self.model = taskmodel
|
|
||||||
self.model.connect("tasklist-populated", self.update_model)
|
|
||||||
self.curr_mach = curr_mach
|
|
||||||
self.curr_distro = curr_distro
|
|
||||||
self.handler = handler
|
|
||||||
self.set_border_width(10)
|
|
||||||
self.connect("delete-event", gtk.main_quit)
|
|
||||||
self.set_title("BitBake Image Creator")
|
|
||||||
self.set_default_size(700, 600)
|
|
||||||
|
|
||||||
self.build = RunningBuild()
|
|
||||||
self.build.connect("build-succeeded", self.running_build_succeeded_cb)
|
|
||||||
self.build.connect("build-failed", self.running_build_failed_cb)
|
|
||||||
|
|
||||||
createview = self.create_build_gui()
|
|
||||||
buildview = self.view_build_gui()
|
|
||||||
self.nb = gtk.Notebook()
|
|
||||||
self.nb.append_page(createview)
|
|
||||||
self.nb.append_page(buildview)
|
|
||||||
self.nb.set_current_page(0)
|
|
||||||
self.nb.set_show_tabs(False)
|
|
||||||
self.add(self.nb)
|
|
||||||
self.generating = False
|
|
||||||
|
|
||||||
def scroll_tv_cb(self, model, path, it, view):
|
|
||||||
view.scroll_to_cell(path)
|
|
||||||
|
|
||||||
def running_build_failed_cb(self, running_build):
|
|
||||||
# FIXME: handle this
|
|
||||||
return
|
|
||||||
|
|
||||||
def running_build_succeeded_cb(self, running_build):
|
|
||||||
label = gtk.Label("Build completed, start another build?")
|
|
||||||
dialog = gtk.Dialog("Build complete",
|
|
||||||
self,
|
|
||||||
gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
|
|
||||||
(gtk.STOCK_NO, gtk.RESPONSE_NO,
|
|
||||||
gtk.STOCK_YES, gtk.RESPONSE_YES))
|
|
||||||
dialog.vbox.pack_start(label)
|
|
||||||
label.show()
|
|
||||||
response = dialog.run()
|
|
||||||
dialog.destroy()
|
|
||||||
if not response == gtk.RESPONSE_YES:
|
|
||||||
self.model.reset() # NOTE: really?
|
|
||||||
self.nb.set_current_page(0)
|
|
||||||
return
|
|
||||||
|
|
||||||
def machine_combo_changed_cb(self, combo, handler):
|
|
||||||
mach = combo.get_active_text()
|
|
||||||
if mach != self.curr_mach:
|
|
||||||
self.curr_mach = mach
|
|
||||||
handler.set_machine(mach)
|
|
||||||
|
|
||||||
def update_machines(self, handler, machines):
|
|
||||||
active = 0
|
|
||||||
for machine in machines:
|
|
||||||
self.machine_combo.append_text(machine)
|
|
||||||
if machine == self.curr_mach:
|
|
||||||
self.machine_combo.set_active(active)
|
|
||||||
active = active + 1
|
|
||||||
self.machine_combo.connect("changed", self.machine_combo_changed_cb, handler)
|
|
||||||
|
|
||||||
def update_distros(self, handler, distros):
|
|
||||||
# FIXME: when we add UI for changing distro this will be used
|
|
||||||
return
|
|
||||||
|
|
||||||
def data_generated(self, handler):
|
|
||||||
self.generating = False
|
|
||||||
|
|
||||||
def spin_idle_func(self, pbar):
|
|
||||||
if self.generating:
|
|
||||||
pbar.pulse()
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
pbar.hide()
|
|
||||||
return False
|
|
||||||
|
|
||||||
def busy(self, handler):
|
|
||||||
self.generating = True
|
|
||||||
pbar = ProgressBar(self)
|
|
||||||
pbar.connect("delete-event", gtk.main_quit) # NOTE: questionable...
|
|
||||||
pbar.pulse()
|
|
||||||
gobject.timeout_add (200,
|
|
||||||
self.spin_idle_func,
|
|
||||||
pbar)
|
|
||||||
|
|
||||||
def update_model(self, model):
|
|
||||||
pkgsaz_model = gtk.TreeModelSort(self.model.packages_model())
|
|
||||||
pkgsaz_model.set_sort_column_id(self.model.COL_NAME, gtk.SORT_ASCENDING)
|
|
||||||
self.pkgsaz_tree.set_model(pkgsaz_model)
|
|
||||||
|
|
||||||
# FIXME: need to implement a custom sort function, as otherwise the column
|
|
||||||
# is re-ordered when toggling the inclusion state (COL_INC)
|
|
||||||
pkgsgrp_model = gtk.TreeModelSort(self.model.packages_model())
|
|
||||||
pkgsgrp_model.set_sort_column_id(self.model.COL_GROUP, gtk.SORT_ASCENDING)
|
|
||||||
self.pkgsgrp_tree.set_model(pkgsgrp_model)
|
|
||||||
|
|
||||||
self.contents_tree.set_model(self.model.contents_model())
|
|
||||||
self.images_tree.set_model(self.model.images_model())
|
|
||||||
self.tasks_tree.set_model(self.model.tasks_model())
|
|
||||||
|
|
||||||
def reset_clicked_cb(self, button):
|
|
||||||
label = gtk.Label("Are you sure you want to reset the image contents?")
|
|
||||||
dialog = gtk.Dialog("Confirm reset", self,
|
|
||||||
gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
|
|
||||||
(gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT,
|
|
||||||
gtk.STOCK_OK, gtk.RESPONSE_ACCEPT))
|
|
||||||
dialog.vbox.pack_start(label)
|
|
||||||
label.show()
|
|
||||||
response = dialog.run()
|
|
||||||
dialog.destroy()
|
|
||||||
if (response == gtk.RESPONSE_ACCEPT):
|
|
||||||
self.model.reset()
|
|
||||||
return
|
|
||||||
|
|
||||||
def bake_clicked_cb(self, button):
|
|
||||||
if not self.model.targets_contains_image():
|
|
||||||
label = gtk.Label("No image was selected. Just build the selected packages?")
|
|
||||||
dialog = gtk.Dialog("Warning, no image selected",
|
|
||||||
self,
|
|
||||||
gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
|
|
||||||
(gtk.STOCK_NO, gtk.RESPONSE_NO,
|
|
||||||
gtk.STOCK_YES, gtk.RESPONSE_YES))
|
|
||||||
dialog.vbox.pack_start(label)
|
|
||||||
label.show()
|
|
||||||
response = dialog.run()
|
|
||||||
dialog.destroy()
|
|
||||||
if not response == gtk.RESPONSE_YES:
|
|
||||||
return
|
|
||||||
|
|
||||||
# Note: We could "squash" the targets list to only include things not brought in by an image
|
|
||||||
task_list = self.model.get_targets()
|
|
||||||
if len(task_list):
|
|
||||||
tasks = " ".join(task_list)
|
|
||||||
# TODO: show a confirmation dialog
|
|
||||||
print("Including these extra tasks in IMAGE_INSTALL: %s" % tasks)
|
|
||||||
else:
|
|
||||||
return
|
|
||||||
|
|
||||||
self.nb.set_current_page(1)
|
|
||||||
self.handler.run_build(task_list)
|
|
||||||
|
|
||||||
return
|
|
||||||
|
|
||||||
def advanced_expander_cb(self, expander, param):
|
|
||||||
return
|
|
||||||
|
|
||||||
def images(self):
|
|
||||||
self.images_tree = gtk.TreeView()
|
|
||||||
self.images_tree.set_headers_visible(True)
|
|
||||||
self.images_tree.set_headers_clickable(False)
|
|
||||||
self.images_tree.set_enable_search(True)
|
|
||||||
self.images_tree.set_search_column(0)
|
|
||||||
self.images_tree.get_selection().set_mode(gtk.SELECTION_NONE)
|
|
||||||
|
|
||||||
col = gtk.TreeViewColumn('Package')
|
|
||||||
col1 = gtk.TreeViewColumn('Description')
|
|
||||||
col2 = gtk.TreeViewColumn('License')
|
|
||||||
col3 = gtk.TreeViewColumn('Include')
|
|
||||||
col3.set_resizable(False)
|
|
||||||
|
|
||||||
self.images_tree.append_column(col)
|
|
||||||
self.images_tree.append_column(col1)
|
|
||||||
self.images_tree.append_column(col2)
|
|
||||||
self.images_tree.append_column(col3)
|
|
||||||
|
|
||||||
cell = gtk.CellRendererText()
|
|
||||||
cell1 = gtk.CellRendererText()
|
|
||||||
cell2 = gtk.CellRendererText()
|
|
||||||
cell3 = gtk.CellRendererToggle()
|
|
||||||
cell3.set_property('activatable', True)
|
|
||||||
cell3.connect("toggled", self.toggle_include_cb, self.images_tree)
|
|
||||||
|
|
||||||
col.pack_start(cell, True)
|
|
||||||
col1.pack_start(cell1, True)
|
|
||||||
col2.pack_start(cell2, True)
|
|
||||||
col3.pack_start(cell3, True)
|
|
||||||
|
|
||||||
col.set_attributes(cell, text=self.model.COL_NAME)
|
|
||||||
col1.set_attributes(cell1, text=self.model.COL_DESC)
|
|
||||||
col2.set_attributes(cell2, text=self.model.COL_LIC)
|
|
||||||
col3.set_attributes(cell3, active=self.model.COL_INC)
|
|
||||||
|
|
||||||
self.images_tree.show()
|
|
||||||
|
|
||||||
scroll = gtk.ScrolledWindow()
|
|
||||||
scroll.set_policy(gtk.POLICY_NEVER, gtk.POLICY_ALWAYS)
|
|
||||||
scroll.set_shadow_type(gtk.SHADOW_IN)
|
|
||||||
scroll.add(self.images_tree)
|
|
||||||
|
|
||||||
return scroll
|
|
||||||
|
|
||||||
def toggle_package(self, path, model):
|
|
||||||
# Convert path to path in original model
|
|
||||||
opath = model.convert_path_to_child_path(path)
|
|
||||||
# current include status
|
|
||||||
inc = self.model[opath][self.model.COL_INC]
|
|
||||||
if inc:
|
|
||||||
self.model.mark(opath)
|
|
||||||
self.model.sweep_up()
|
|
||||||
#self.model.remove_package_full(cpath)
|
|
||||||
else:
|
|
||||||
self.model.include_item(opath)
|
|
||||||
return
|
|
||||||
|
|
||||||
def remove_package_cb(self, cell, path):
|
|
||||||
model = self.model.contents_model()
|
|
||||||
label = gtk.Label("Are you sure you want to remove this item?")
|
|
||||||
dialog = gtk.Dialog("Confirm removal", self,
|
|
||||||
gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
|
|
||||||
(gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT,
|
|
||||||
gtk.STOCK_OK, gtk.RESPONSE_ACCEPT))
|
|
||||||
dialog.vbox.pack_start(label)
|
|
||||||
label.show()
|
|
||||||
response = dialog.run()
|
|
||||||
dialog.destroy()
|
|
||||||
if (response == gtk.RESPONSE_ACCEPT):
|
|
||||||
self.toggle_package(path, model)
|
|
||||||
|
|
||||||
def toggle_include_cb(self, cell, path, tv):
|
|
||||||
model = tv.get_model()
|
|
||||||
self.toggle_package(path, model)
|
|
||||||
|
|
||||||
def toggle_pkg_include_cb(self, cell, path, tv):
|
|
||||||
# there's an extra layer of models in the packages case.
|
|
||||||
sort_model = tv.get_model()
|
|
||||||
cpath = sort_model.convert_path_to_child_path(path)
|
|
||||||
self.toggle_package(cpath, sort_model.get_model())
|
|
||||||
|
|
||||||
def pkgsaz(self):
|
|
||||||
self.pkgsaz_tree = gtk.TreeView()
|
|
||||||
self.pkgsaz_tree.set_headers_visible(True)
|
|
||||||
self.pkgsaz_tree.set_headers_clickable(True)
|
|
||||||
self.pkgsaz_tree.set_enable_search(True)
|
|
||||||
self.pkgsaz_tree.set_search_column(0)
|
|
||||||
self.pkgsaz_tree.get_selection().set_mode(gtk.SELECTION_NONE)
|
|
||||||
|
|
||||||
col = gtk.TreeViewColumn('Package')
|
|
||||||
col1 = gtk.TreeViewColumn('Description')
|
|
||||||
col1.set_resizable(True)
|
|
||||||
col2 = gtk.TreeViewColumn('License')
|
|
||||||
col2.set_resizable(True)
|
|
||||||
col3 = gtk.TreeViewColumn('Group')
|
|
||||||
col4 = gtk.TreeViewColumn('Include')
|
|
||||||
col4.set_resizable(False)
|
|
||||||
|
|
||||||
self.pkgsaz_tree.append_column(col)
|
|
||||||
self.pkgsaz_tree.append_column(col1)
|
|
||||||
self.pkgsaz_tree.append_column(col2)
|
|
||||||
self.pkgsaz_tree.append_column(col3)
|
|
||||||
self.pkgsaz_tree.append_column(col4)
|
|
||||||
|
|
||||||
cell = gtk.CellRendererText()
|
|
||||||
cell1 = gtk.CellRendererText()
|
|
||||||
cell1.set_property('width-chars', 20)
|
|
||||||
cell2 = gtk.CellRendererText()
|
|
||||||
cell2.set_property('width-chars', 20)
|
|
||||||
cell3 = gtk.CellRendererText()
|
|
||||||
cell4 = gtk.CellRendererToggle()
|
|
||||||
cell4.set_property('activatable', True)
|
|
||||||
cell4.connect("toggled", self.toggle_pkg_include_cb, self.pkgsaz_tree)
|
|
||||||
|
|
||||||
col.pack_start(cell, True)
|
|
||||||
col1.pack_start(cell1, True)
|
|
||||||
col2.pack_start(cell2, True)
|
|
||||||
col3.pack_start(cell3, True)
|
|
||||||
col4.pack_start(cell4, True)
|
|
||||||
|
|
||||||
col.set_attributes(cell, text=self.model.COL_NAME)
|
|
||||||
col1.set_attributes(cell1, text=self.model.COL_DESC)
|
|
||||||
col2.set_attributes(cell2, text=self.model.COL_LIC)
|
|
||||||
col3.set_attributes(cell3, text=self.model.COL_GROUP)
|
|
||||||
col4.set_attributes(cell4, active=self.model.COL_INC)
|
|
||||||
|
|
||||||
self.pkgsaz_tree.show()
|
|
||||||
|
|
||||||
scroll = gtk.ScrolledWindow()
|
|
||||||
scroll.set_policy(gtk.POLICY_NEVER, gtk.POLICY_ALWAYS)
|
|
||||||
scroll.set_shadow_type(gtk.SHADOW_IN)
|
|
||||||
scroll.add(self.pkgsaz_tree)
|
|
||||||
|
|
||||||
return scroll
|
|
||||||
|
|
||||||
def pkgsgrp(self):
|
|
||||||
self.pkgsgrp_tree = gtk.TreeView()
|
|
||||||
self.pkgsgrp_tree.set_headers_visible(True)
|
|
||||||
self.pkgsgrp_tree.set_headers_clickable(False)
|
|
||||||
self.pkgsgrp_tree.set_enable_search(True)
|
|
||||||
self.pkgsgrp_tree.set_search_column(0)
|
|
||||||
self.pkgsgrp_tree.get_selection().set_mode(gtk.SELECTION_NONE)
|
|
||||||
|
|
||||||
col = gtk.TreeViewColumn('Package')
|
|
||||||
col1 = gtk.TreeViewColumn('Description')
|
|
||||||
col1.set_resizable(True)
|
|
||||||
col2 = gtk.TreeViewColumn('License')
|
|
||||||
col2.set_resizable(True)
|
|
||||||
col3 = gtk.TreeViewColumn('Group')
|
|
||||||
col4 = gtk.TreeViewColumn('Include')
|
|
||||||
col4.set_resizable(False)
|
|
||||||
|
|
||||||
self.pkgsgrp_tree.append_column(col)
|
|
||||||
self.pkgsgrp_tree.append_column(col1)
|
|
||||||
self.pkgsgrp_tree.append_column(col2)
|
|
||||||
self.pkgsgrp_tree.append_column(col3)
|
|
||||||
self.pkgsgrp_tree.append_column(col4)
|
|
||||||
|
|
||||||
cell = gtk.CellRendererText()
|
|
||||||
cell1 = gtk.CellRendererText()
|
|
||||||
cell1.set_property('width-chars', 20)
|
|
||||||
cell2 = gtk.CellRendererText()
|
|
||||||
cell2.set_property('width-chars', 20)
|
|
||||||
cell3 = gtk.CellRendererText()
|
|
||||||
cell4 = gtk.CellRendererToggle()
|
|
||||||
cell4.set_property("activatable", True)
|
|
||||||
cell4.connect("toggled", self.toggle_pkg_include_cb, self.pkgsgrp_tree)
|
|
||||||
|
|
||||||
col.pack_start(cell, True)
|
|
||||||
col1.pack_start(cell1, True)
|
|
||||||
col2.pack_start(cell2, True)
|
|
||||||
col3.pack_start(cell3, True)
|
|
||||||
col4.pack_start(cell4, True)
|
|
||||||
|
|
||||||
col.set_attributes(cell, text=self.model.COL_NAME)
|
|
||||||
col1.set_attributes(cell1, text=self.model.COL_DESC)
|
|
||||||
col2.set_attributes(cell2, text=self.model.COL_LIC)
|
|
||||||
col3.set_attributes(cell3, text=self.model.COL_GROUP)
|
|
||||||
col4.set_attributes(cell4, active=self.model.COL_INC)
|
|
||||||
|
|
||||||
self.pkgsgrp_tree.show()
|
|
||||||
|
|
||||||
scroll = gtk.ScrolledWindow()
|
|
||||||
scroll.set_policy(gtk.POLICY_NEVER, gtk.POLICY_ALWAYS)
|
|
||||||
scroll.set_shadow_type(gtk.SHADOW_IN)
|
|
||||||
scroll.add(self.pkgsgrp_tree)
|
|
||||||
|
|
||||||
return scroll
|
|
||||||
|
|
||||||
def tasks(self):
|
|
||||||
self.tasks_tree = gtk.TreeView()
|
|
||||||
self.tasks_tree.set_headers_visible(True)
|
|
||||||
self.tasks_tree.set_headers_clickable(False)
|
|
||||||
self.tasks_tree.set_enable_search(True)
|
|
||||||
self.tasks_tree.set_search_column(0)
|
|
||||||
self.tasks_tree.get_selection().set_mode(gtk.SELECTION_NONE)
|
|
||||||
|
|
||||||
col = gtk.TreeViewColumn('Package')
|
|
||||||
col1 = gtk.TreeViewColumn('Description')
|
|
||||||
col2 = gtk.TreeViewColumn('Include')
|
|
||||||
col2.set_resizable(False)
|
|
||||||
|
|
||||||
self.tasks_tree.append_column(col)
|
|
||||||
self.tasks_tree.append_column(col1)
|
|
||||||
self.tasks_tree.append_column(col2)
|
|
||||||
|
|
||||||
cell = gtk.CellRendererText()
|
|
||||||
cell1 = gtk.CellRendererText()
|
|
||||||
cell2 = gtk.CellRendererToggle()
|
|
||||||
cell2.set_property('activatable', True)
|
|
||||||
cell2.connect("toggled", self.toggle_include_cb, self.tasks_tree)
|
|
||||||
|
|
||||||
col.pack_start(cell, True)
|
|
||||||
col1.pack_start(cell1, True)
|
|
||||||
col2.pack_start(cell2, True)
|
|
||||||
|
|
||||||
col.set_attributes(cell, text=self.model.COL_NAME)
|
|
||||||
col1.set_attributes(cell1, text=self.model.COL_DESC)
|
|
||||||
col2.set_attributes(cell2, active=self.model.COL_INC)
|
|
||||||
|
|
||||||
self.tasks_tree.show()
|
|
||||||
|
|
||||||
scroll = gtk.ScrolledWindow()
|
|
||||||
scroll.set_policy(gtk.POLICY_NEVER, gtk.POLICY_ALWAYS)
|
|
||||||
scroll.set_shadow_type(gtk.SHADOW_IN)
|
|
||||||
scroll.add(self.tasks_tree)
|
|
||||||
|
|
||||||
return scroll
|
|
||||||
|
|
||||||
def cancel_build(self, button):
|
|
||||||
label = gtk.Label("Do you really want to stop this build?")
|
|
||||||
dialog = gtk.Dialog("Cancel build",
|
|
||||||
self,
|
|
||||||
gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
|
|
||||||
(gtk.STOCK_NO, gtk.RESPONSE_NO,
|
|
||||||
gtk.STOCK_YES, gtk.RESPONSE_YES))
|
|
||||||
dialog.vbox.pack_start(label)
|
|
||||||
label.show()
|
|
||||||
response = dialog.run()
|
|
||||||
dialog.destroy()
|
|
||||||
if response == gtk.RESPONSE_YES:
|
|
||||||
self.handler.cancel_build()
|
|
||||||
return
|
|
||||||
|
|
||||||
def view_build_gui(self):
|
|
||||||
vbox = gtk.VBox(False, 6)
|
|
||||||
vbox.show()
|
|
||||||
build_tv = RunningBuildTreeView()
|
|
||||||
build_tv.show()
|
|
||||||
build_tv.set_model(self.build.model)
|
|
||||||
self.build.model.connect("row-inserted", self.scroll_tv_cb, build_tv)
|
|
||||||
scrolled_view = gtk.ScrolledWindow ()
|
|
||||||
scrolled_view.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
|
|
||||||
scrolled_view.add(build_tv)
|
|
||||||
scrolled_view.show()
|
|
||||||
vbox.pack_start(scrolled_view, expand=True, fill=True)
|
|
||||||
hbox = gtk.HBox(False, 6)
|
|
||||||
hbox.show()
|
|
||||||
vbox.pack_start(hbox, expand=False, fill=False)
|
|
||||||
cancel = gtk.Button(stock=gtk.STOCK_CANCEL)
|
|
||||||
cancel.connect("clicked", self.cancel_build)
|
|
||||||
cancel.show()
|
|
||||||
hbox.pack_end(cancel, expand=False, fill=False)
|
|
||||||
|
|
||||||
return vbox
|
|
||||||
|
|
||||||
def create_build_gui(self):
|
|
||||||
vbox = gtk.VBox(False, 6)
|
|
||||||
vbox.show()
|
|
||||||
hbox = gtk.HBox(False, 6)
|
|
||||||
hbox.show()
|
|
||||||
vbox.pack_start(hbox, expand=False, fill=False)
|
|
||||||
|
|
||||||
label = gtk.Label("Machine:")
|
|
||||||
label.show()
|
|
||||||
hbox.pack_start(label, expand=False, fill=False, padding=6)
|
|
||||||
self.machine_combo = gtk.combo_box_new_text()
|
|
||||||
self.machine_combo.set_active(0)
|
|
||||||
self.machine_combo.show()
|
|
||||||
self.machine_combo.set_tooltip_text("Selects the architecture of the target board for which you would like to build an image.")
|
|
||||||
hbox.pack_start(self.machine_combo, expand=False, fill=False, padding=6)
|
|
||||||
|
|
||||||
ins = gtk.Notebook()
|
|
||||||
vbox.pack_start(ins, expand=True, fill=True)
|
|
||||||
ins.set_show_tabs(True)
|
|
||||||
label = gtk.Label("Images")
|
|
||||||
label.show()
|
|
||||||
ins.append_page(self.images(), tab_label=label)
|
|
||||||
label = gtk.Label("Tasks")
|
|
||||||
label.show()
|
|
||||||
ins.append_page(self.tasks(), tab_label=label)
|
|
||||||
label = gtk.Label("Packages (by Group)")
|
|
||||||
label.show()
|
|
||||||
ins.append_page(self.pkgsgrp(), tab_label=label)
|
|
||||||
label = gtk.Label("Packages (by Name)")
|
|
||||||
label.show()
|
|
||||||
ins.append_page(self.pkgsaz(), tab_label=label)
|
|
||||||
ins.set_current_page(0)
|
|
||||||
ins.show_all()
|
|
||||||
|
|
||||||
hbox = gtk.HBox()
|
|
||||||
hbox.show()
|
|
||||||
vbox.pack_start(hbox, expand=False, fill=False)
|
|
||||||
label = gtk.Label("Image contents:")
|
|
||||||
label.show()
|
|
||||||
hbox.pack_start(label, expand=False, fill=False, padding=6)
|
|
||||||
con = self.contents()
|
|
||||||
con.show()
|
|
||||||
vbox.pack_start(con, expand=True, fill=True)
|
|
||||||
|
|
||||||
#advanced = gtk.Expander(label="Advanced")
|
|
||||||
#advanced.connect("notify::expanded", self.advanced_expander_cb)
|
|
||||||
#advanced.show()
|
|
||||||
#vbox.pack_start(advanced, expand=False, fill=False)
|
|
||||||
|
|
||||||
hbox = gtk.HBox()
|
|
||||||
hbox.show()
|
|
||||||
vbox.pack_start(hbox, expand=False, fill=False)
|
|
||||||
bake = gtk.Button("Bake")
|
|
||||||
bake.connect("clicked", self.bake_clicked_cb)
|
|
||||||
bake.show()
|
|
||||||
hbox.pack_end(bake, expand=False, fill=False, padding=6)
|
|
||||||
reset = gtk.Button("Reset")
|
|
||||||
reset.connect("clicked", self.reset_clicked_cb)
|
|
||||||
reset.show()
|
|
||||||
hbox.pack_end(reset, expand=False, fill=False, padding=6)
|
|
||||||
|
|
||||||
return vbox
|
|
||||||
|
|
||||||
def contents(self):
|
|
||||||
self.contents_tree = gtk.TreeView()
|
|
||||||
self.contents_tree.set_headers_visible(True)
|
|
||||||
self.contents_tree.get_selection().set_mode(gtk.SELECTION_NONE)
|
|
||||||
|
|
||||||
# allow searching in the package column
|
|
||||||
self.contents_tree.set_search_column(0)
|
|
||||||
|
|
||||||
col = gtk.TreeViewColumn('Package')
|
|
||||||
col.set_sort_column_id(0)
|
|
||||||
col1 = gtk.TreeViewColumn('Brought in by')
|
|
||||||
col1.set_resizable(True)
|
|
||||||
col2 = gtk.TreeViewColumn('Remove')
|
|
||||||
col2.set_expand(False)
|
|
||||||
|
|
||||||
self.contents_tree.append_column(col)
|
|
||||||
self.contents_tree.append_column(col1)
|
|
||||||
self.contents_tree.append_column(col2)
|
|
||||||
|
|
||||||
cell = gtk.CellRendererText()
|
|
||||||
cell1 = gtk.CellRendererText()
|
|
||||||
cell1.set_property('width-chars', 20)
|
|
||||||
cell2 = gtk.CellRendererToggle()
|
|
||||||
cell2.connect("toggled", self.remove_package_cb)
|
|
||||||
|
|
||||||
col.pack_start(cell, True)
|
|
||||||
col1.pack_start(cell1, True)
|
|
||||||
col2.pack_start(cell2, True)
|
|
||||||
|
|
||||||
col.set_attributes(cell, text=self.model.COL_NAME)
|
|
||||||
col1.set_attributes(cell1, text=self.model.COL_BINB)
|
|
||||||
col2.set_attributes(cell2, active=self.model.COL_INC)
|
|
||||||
|
|
||||||
self.contents_tree.show()
|
|
||||||
|
|
||||||
scroll = gtk.ScrolledWindow()
|
|
||||||
scroll.set_policy(gtk.POLICY_NEVER, gtk.POLICY_ALWAYS)
|
|
||||||
scroll.set_shadow_type(gtk.SHADOW_IN)
|
|
||||||
scroll.add(self.contents_tree)
|
|
||||||
|
|
||||||
return scroll
|
|
||||||
|
|
||||||
def main (server, eventHandler):
|
|
||||||
gobject.threads_init()
|
|
||||||
gtk.gdk.threads_init()
|
|
||||||
|
|
||||||
taskmodel = TaskListModel()
|
|
||||||
handler = HobHandler(taskmodel, server)
|
|
||||||
mach = server.runCommand(["getVariable", "MACHINE"])
|
|
||||||
distro = server.runCommand(["getVariable", "DISTRO"])
|
|
||||||
|
|
||||||
window = MainWindow(taskmodel, handler, mach, distro)
|
|
||||||
window.show_all ()
|
|
||||||
handler.connect("machines-updated", window.update_machines)
|
|
||||||
handler.connect("distros-updated", window.update_distros)
|
|
||||||
handler.connect("generating-data", window.busy)
|
|
||||||
handler.connect("data-generated", window.data_generated)
|
|
||||||
pbar = ProgressBar(window)
|
|
||||||
pbar.connect("delete-event", gtk.main_quit)
|
|
||||||
|
|
||||||
try:
|
|
||||||
# kick the while thing off
|
|
||||||
handler.current_command = "findConfigFilesDistro"
|
|
||||||
server.runCommand(["findConfigFiles", "DISTRO"])
|
|
||||||
except xmlrpclib.Fault:
|
|
||||||
print("XMLRPC Fault getting commandline:\n %s" % x)
|
|
||||||
return 1
|
|
||||||
|
|
||||||
# This timeout function regularly probes the event queue to find out if we
|
|
||||||
# have any messages waiting for us.
|
|
||||||
gobject.timeout_add (100,
|
|
||||||
handler.event_handle_idle_func,
|
|
||||||
eventHandler,
|
|
||||||
window.build,
|
|
||||||
pbar)
|
|
||||||
|
|
||||||
try:
|
|
||||||
gtk.main()
|
|
||||||
except EnvironmentError as ioerror:
|
|
||||||
# ignore interrupted io
|
|
||||||
if ioerror.args[0] == 4:
|
|
||||||
pass
|
|
||||||
finally:
|
|
||||||
server.runCommand(["stateStop"])
|
|
||||||
|
|
||||||
@@ -22,49 +22,15 @@ from __future__ import division
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
import itertools
|
||||||
import xmlrpclib
|
import xmlrpclib
|
||||||
import logging
|
from bb import ui
|
||||||
import progressbar
|
|
||||||
import bb.msg
|
|
||||||
from bb.ui import uihelper
|
from bb.ui import uihelper
|
||||||
|
|
||||||
logger = logging.getLogger("BitBake")
|
|
||||||
interactive = sys.stdout.isatty()
|
|
||||||
|
|
||||||
class BBProgress(progressbar.ProgressBar):
|
parsespin = itertools.cycle( r'|/-\\' )
|
||||||
def __init__(self, msg, maxval):
|
|
||||||
self.msg = msg
|
|
||||||
widgets = [progressbar.Percentage(), ' ', progressbar.Bar(), ' ',
|
|
||||||
progressbar.ETA()]
|
|
||||||
|
|
||||||
progressbar.ProgressBar.__init__(self, maxval, [self.msg + ": "] + widgets)
|
def init(server, eventHandler):
|
||||||
|
|
||||||
class NonInteractiveProgress(object):
|
|
||||||
fobj = sys.stdout
|
|
||||||
|
|
||||||
def __init__(self, msg, maxval):
|
|
||||||
self.msg = msg
|
|
||||||
self.maxval = maxval
|
|
||||||
|
|
||||||
def start(self):
|
|
||||||
self.fobj.write("%s..." % self.msg)
|
|
||||||
self.fobj.flush()
|
|
||||||
return self
|
|
||||||
|
|
||||||
def update(self, value):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def finish(self):
|
|
||||||
self.fobj.write("done.\n")
|
|
||||||
self.fobj.flush()
|
|
||||||
|
|
||||||
def new_progress(msg, maxval):
|
|
||||||
if interactive:
|
|
||||||
return BBProgress(msg, maxval)
|
|
||||||
else:
|
|
||||||
return NonInteractiveProgress(msg, maxval)
|
|
||||||
|
|
||||||
def main(server, eventHandler):
|
|
||||||
|
|
||||||
# Get values of variables which control our output
|
# Get values of variables which control our output
|
||||||
includelogs = server.runCommand(["getVariable", "BBINCLUDELOGS"])
|
includelogs = server.runCommand(["getVariable", "BBINCLUDELOGS"])
|
||||||
@@ -72,13 +38,9 @@ def main(server, eventHandler):
|
|||||||
|
|
||||||
helper = uihelper.BBUIHelper()
|
helper = uihelper.BBUIHelper()
|
||||||
|
|
||||||
console = logging.StreamHandler(sys.stdout)
|
|
||||||
format = bb.msg.BBLogFormatter("%(levelname)s: %(message)s")
|
|
||||||
console.setFormatter(format)
|
|
||||||
logger.addHandler(console)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
cmdline = server.runCommand(["getCmdLineAction"])
|
cmdline = server.runCommand(["getCmdLineAction"])
|
||||||
|
#print cmdline
|
||||||
if not cmdline:
|
if not cmdline:
|
||||||
return 1
|
return 1
|
||||||
ret = server.runCommand(cmdline)
|
ret = server.runCommand(cmdline)
|
||||||
@@ -89,9 +51,6 @@ def main(server, eventHandler):
|
|||||||
print("XMLRPC Fault getting commandline:\n %s" % x)
|
print("XMLRPC Fault getting commandline:\n %s" % x)
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
|
|
||||||
parseprogress = None
|
|
||||||
cacheprogress = None
|
|
||||||
shutdown = 0
|
shutdown = 0
|
||||||
return_value = 0
|
return_value = 0
|
||||||
while True:
|
while True:
|
||||||
@@ -99,6 +58,7 @@ def main(server, eventHandler):
|
|||||||
event = eventHandler.waitEvent(0.25)
|
event = eventHandler.waitEvent(0.25)
|
||||||
if event is None:
|
if event is None:
|
||||||
continue
|
continue
|
||||||
|
#print event
|
||||||
helper.eventHandler(event)
|
helper.eventHandler(event)
|
||||||
if isinstance(event, bb.runqueue.runQueueExitWait):
|
if isinstance(event, bb.runqueue.runQueueExitWait):
|
||||||
if not shutdown:
|
if not shutdown:
|
||||||
@@ -107,21 +67,31 @@ def main(server, eventHandler):
|
|||||||
activetasks, failedtasks = helper.getTasks()
|
activetasks, failedtasks = helper.getTasks()
|
||||||
if activetasks:
|
if activetasks:
|
||||||
print("Waiting for %s active tasks to finish:" % len(activetasks))
|
print("Waiting for %s active tasks to finish:" % len(activetasks))
|
||||||
for tasknum, task in enumerate(activetasks):
|
tasknum = 1
|
||||||
|
for task in activetasks:
|
||||||
print("%s: %s (pid %s)" % (tasknum, activetasks[task]["title"], task))
|
print("%s: %s (pid %s)" % (tasknum, activetasks[task]["title"], task))
|
||||||
|
tasknum = tasknum + 1
|
||||||
|
|
||||||
if isinstance(event, logging.LogRecord):
|
if isinstance(event, bb.msg.MsgPlain):
|
||||||
if event.levelno >= format.ERROR:
|
print(event._message)
|
||||||
return_value = 1
|
continue
|
||||||
# For "normal" logging conditions, don't show note logs from tasks
|
if isinstance(event, bb.msg.MsgDebug):
|
||||||
# but do show them if the user has changed the default log level to
|
print('DEBUG: ' + event._message)
|
||||||
# include verbose/debug messages
|
continue
|
||||||
if logger.getEffectiveLevel() > format.VERBOSE:
|
if isinstance(event, bb.msg.MsgNote):
|
||||||
if event.taskpid != 0 and event.levelno <= format.NOTE:
|
print('NOTE: ' + event._message)
|
||||||
continue
|
continue
|
||||||
logger.handle(event)
|
if isinstance(event, bb.msg.MsgWarn):
|
||||||
|
print('WARNING: ' + event._message)
|
||||||
|
continue
|
||||||
|
if isinstance(event, bb.msg.MsgError):
|
||||||
|
return_value = 1
|
||||||
|
print('ERROR: ' + event._message)
|
||||||
|
continue
|
||||||
|
if isinstance(event, bb.msg.MsgFatal):
|
||||||
|
return_value = 1
|
||||||
|
print('FATAL: ' + event._message)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if isinstance(event, bb.build.TaskFailed):
|
if isinstance(event, bb.build.TaskFailed):
|
||||||
return_value = 1
|
return_value = 1
|
||||||
logfile = event.logfile
|
logfile = event.logfile
|
||||||
@@ -147,47 +117,42 @@ def main(server, eventHandler):
|
|||||||
for line in lines:
|
for line in lines:
|
||||||
print(line)
|
print(line)
|
||||||
if isinstance(event, bb.build.TaskBase):
|
if isinstance(event, bb.build.TaskBase):
|
||||||
logger.info(event._message)
|
print("NOTE: %s" % event._message)
|
||||||
continue
|
|
||||||
if isinstance(event, bb.event.ParseStarted):
|
|
||||||
parseprogress = new_progress("Parsing recipes", event.total).start()
|
|
||||||
continue
|
continue
|
||||||
if isinstance(event, bb.event.ParseProgress):
|
if isinstance(event, bb.event.ParseProgress):
|
||||||
parseprogress.update(event.current)
|
x = event.sofar
|
||||||
continue
|
y = event.total
|
||||||
if isinstance(event, bb.event.ParseCompleted):
|
if os.isatty(sys.stdout.fileno()):
|
||||||
parseprogress.finish()
|
sys.stdout.write("\rNOTE: Handling BitBake files: %s (%04d/%04d) [%2d %%]" % ( next(parsespin), x, y, x*100//y ) )
|
||||||
print(("Parsing of %d .bb files complete (%d cached, %d parsed). %d targets, %d skipped, %d masked, %d errors."
|
sys.stdout.flush()
|
||||||
% ( event.total, event.cached, event.parsed, event.virtuals, event.skipped, event.masked, event.errors)))
|
else:
|
||||||
|
if x == 1:
|
||||||
|
sys.stdout.write("Parsing .bb files, please wait...")
|
||||||
|
sys.stdout.flush()
|
||||||
|
if x == y:
|
||||||
|
sys.stdout.write("done.")
|
||||||
|
sys.stdout.flush()
|
||||||
|
if x == y:
|
||||||
|
print(("\nParsing of %d .bb files complete (%d cached, %d parsed). %d targets, %d skipped, %d masked, %d errors."
|
||||||
|
% ( event.total, event.cached, event.parsed, event.virtuals, event.skipped, event.masked, event.errors)))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if isinstance(event, bb.event.CacheLoadStarted):
|
if isinstance(event, bb.command.CookerCommandCompleted):
|
||||||
cacheprogress = new_progress("Loading cache", event.total).start()
|
|
||||||
continue
|
|
||||||
if isinstance(event, bb.event.CacheLoadProgress):
|
|
||||||
cacheprogress.update(event.current)
|
|
||||||
continue
|
|
||||||
if isinstance(event, bb.event.CacheLoadCompleted):
|
|
||||||
cacheprogress.finish()
|
|
||||||
print("Loaded %d entries from dependency cache." % event.num_entries)
|
|
||||||
continue
|
|
||||||
|
|
||||||
if isinstance(event, bb.command.CommandCompleted):
|
|
||||||
break
|
break
|
||||||
if isinstance(event, bb.command.CommandFailed):
|
if isinstance(event, bb.command.CookerCommandSetExitCode):
|
||||||
return_value = event.exitcode
|
|
||||||
logger.error("Command execution failed: %s", event.error)
|
|
||||||
break
|
|
||||||
if isinstance(event, bb.command.CommandExit):
|
|
||||||
return_value = event.exitcode
|
return_value = event.exitcode
|
||||||
continue
|
continue
|
||||||
|
if isinstance(event, bb.command.CookerCommandFailed):
|
||||||
|
return_value = 1
|
||||||
|
print("Command execution failed: %s" % event.error)
|
||||||
|
break
|
||||||
if isinstance(event, bb.cooker.CookerExit):
|
if isinstance(event, bb.cooker.CookerExit):
|
||||||
break
|
break
|
||||||
if isinstance(event, bb.event.MultipleProviders):
|
if isinstance(event, bb.event.MultipleProviders):
|
||||||
logger.info("multiple providers are available for %s%s (%s)", event._is_runtime and "runtime " or "",
|
print("NOTE: multiple providers are available for %s%s (%s)" % (event._is_runtime and "runtime " or "",
|
||||||
event._item,
|
event._item,
|
||||||
", ".join(event._candidates))
|
", ".join(event._candidates)))
|
||||||
logger.info("consider defining a PREFERRED_PROVIDER entry to match %s", event._item)
|
print("NOTE: consider defining a PREFERRED_PROVIDER entry to match %s" % event._item)
|
||||||
continue
|
continue
|
||||||
if isinstance(event, bb.event.NoProvider):
|
if isinstance(event, bb.event.NoProvider):
|
||||||
if event._runtime:
|
if event._runtime:
|
||||||
@@ -196,26 +161,9 @@ def main(server, eventHandler):
|
|||||||
r = ""
|
r = ""
|
||||||
|
|
||||||
if event._dependees:
|
if event._dependees:
|
||||||
logger.error("Nothing %sPROVIDES '%s' (but %s %sDEPENDS on or otherwise requires it)", r, event._item, ", ".join(event._dependees), r)
|
print("ERROR: Nothing %sPROVIDES '%s' (but %s %sDEPENDS on or otherwise requires it)" % (r, event._item, ", ".join(event._dependees), r))
|
||||||
else:
|
else:
|
||||||
logger.error("Nothing %sPROVIDES '%s'", r, event._item)
|
print("ERROR: Nothing %sPROVIDES '%s'" % (r, event._item))
|
||||||
continue
|
|
||||||
|
|
||||||
if isinstance(event, bb.runqueue.runQueueTaskStarted):
|
|
||||||
if event.noexec:
|
|
||||||
tasktype = 'noexec task'
|
|
||||||
else:
|
|
||||||
tasktype = 'task'
|
|
||||||
logger.info("Running %s %s of %s (ID: %s, %s)",
|
|
||||||
tasktype,
|
|
||||||
event.stats.completed + event.stats.active +
|
|
||||||
event.stats.failed + 1,
|
|
||||||
event.stats.total, event.taskid, event.taskstring)
|
|
||||||
continue
|
|
||||||
|
|
||||||
if isinstance(event, bb.runqueue.runQueueTaskFailed):
|
|
||||||
logger.error("Task %s (%s) failed with exit code '%s'",
|
|
||||||
event.taskid, event.taskstring, event.exitcode)
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# ignore
|
# ignore
|
||||||
@@ -227,12 +175,8 @@ def main(server, eventHandler):
|
|||||||
bb.runqueue.runQueueExitWait)):
|
bb.runqueue.runQueueExitWait)):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
logger.error("Unknown event: %s", event)
|
print("Unknown Event: %s" % event)
|
||||||
|
|
||||||
except EnvironmentError as ioerror:
|
|
||||||
# ignore interrupted io
|
|
||||||
if ioerror.args[0] == 4:
|
|
||||||
pass
|
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
if shutdown == 2:
|
if shutdown == 2:
|
||||||
print("\nThird Keyboard Interrupt, exit.\n")
|
print("\nThird Keyboard Interrupt, exit.\n")
|
||||||
|
|||||||
@@ -44,9 +44,8 @@
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
from __future__ import division
|
from __future__ import division
|
||||||
import logging
|
|
||||||
import os, sys, curses, itertools, time
|
import os, sys, curses, itertools, time
|
||||||
import bb
|
import bb
|
||||||
import xmlrpclib
|
import xmlrpclib
|
||||||
@@ -247,35 +246,29 @@ class NCursesUI:
|
|||||||
event = eventHandler.waitEvent(0.25)
|
event = eventHandler.waitEvent(0.25)
|
||||||
if not event:
|
if not event:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
helper.eventHandler(event)
|
helper.eventHandler(event)
|
||||||
|
#mw.appendText("%s\n" % event[0])
|
||||||
if isinstance(event, bb.build.TaskBase):
|
if isinstance(event, bb.build.TaskBase):
|
||||||
mw.appendText("NOTE: %s\n" % event._message)
|
mw.appendText("NOTE: %s\n" % event._message)
|
||||||
if isinstance(event, logging.LogRecord):
|
if isinstance(event, bb.msg.MsgDebug):
|
||||||
mw.appendText(logging.getLevelName(event.levelno) + ': ' + event.getMessage() + '\n')
|
mw.appendText('DEBUG: ' + event._message + '\n')
|
||||||
|
if isinstance(event, bb.msg.MsgNote):
|
||||||
if isinstance(event, bb.event.CacheLoadStarted):
|
mw.appendText('NOTE: ' + event._message + '\n')
|
||||||
self.parse_total = event.total
|
if isinstance(event, bb.msg.MsgWarn):
|
||||||
if isinstance(event, bb.event.CacheLoadProgress):
|
mw.appendText('WARNING: ' + event._message + '\n')
|
||||||
x = event.current
|
if isinstance(event, bb.msg.MsgError):
|
||||||
y = self.parse_total
|
mw.appendText('ERROR: ' + event._message + '\n')
|
||||||
mw.setStatus("Loading Cache: %s [%2d %%]" % ( next(parsespin), x*100/y ) )
|
if isinstance(event, bb.msg.MsgFatal):
|
||||||
if isinstance(event, bb.event.CacheLoadCompleted):
|
mw.appendText('FATAL: ' + event._message + '\n')
|
||||||
mw.setStatus("Idle")
|
|
||||||
mw.appendText("Loaded %d entries from dependency cache.\n"
|
|
||||||
% ( event.num_entries))
|
|
||||||
|
|
||||||
if isinstance(event, bb.event.ParseStarted):
|
|
||||||
self.parse_total = event.total
|
|
||||||
if isinstance(event, bb.event.ParseProgress):
|
if isinstance(event, bb.event.ParseProgress):
|
||||||
x = event.current
|
x = event.sofar
|
||||||
y = self.parse_total
|
y = event.total
|
||||||
mw.setStatus("Parsing Recipes: %s [%2d %%]" % ( next(parsespin), x*100/y ) )
|
if x == y:
|
||||||
if isinstance(event, bb.event.ParseCompleted):
|
mw.setStatus("Idle")
|
||||||
mw.setStatus("Idle")
|
mw.appendText("Parsing finished. %d cached, %d parsed, %d skipped, %d masked."
|
||||||
mw.appendText("Parsing finished. %d cached, %d parsed, %d skipped, %d masked.\n"
|
|
||||||
% ( event.cached, event.parsed, event.skipped, event.masked ))
|
% ( event.cached, event.parsed, event.skipped, event.masked ))
|
||||||
|
else:
|
||||||
|
mw.setStatus("Parsing: %s (%04d/%04d) [%2d %%]" % ( next(parsespin), x, y, x*100//y ) )
|
||||||
# if isinstance(event, bb.build.TaskFailed):
|
# if isinstance(event, bb.build.TaskFailed):
|
||||||
# if event.logfile:
|
# if event.logfile:
|
||||||
# if data.getVar("BBINCLUDELOGS", d):
|
# if data.getVar("BBINCLUDELOGS", d):
|
||||||
@@ -295,16 +288,12 @@ class NCursesUI:
|
|||||||
# else:
|
# else:
|
||||||
# bb.msg.error(bb.msg.domain.Build, "see log in %s" % logfile)
|
# bb.msg.error(bb.msg.domain.Build, "see log in %s" % logfile)
|
||||||
|
|
||||||
if isinstance(event, bb.command.CommandCompleted):
|
if isinstance(event, bb.command.CookerCommandCompleted):
|
||||||
# stop so the user can see the result of the build, but
|
exitflag = True
|
||||||
# also allow them to now exit with a single ^C
|
if isinstance(event, bb.command.CookerCommandFailed):
|
||||||
shutdown = 2
|
|
||||||
if isinstance(event, bb.command.CommandFailed):
|
|
||||||
mw.appendText("Command execution failed: %s" % event.error)
|
mw.appendText("Command execution failed: %s" % event.error)
|
||||||
time.sleep(2)
|
time.sleep(2)
|
||||||
exitflag = True
|
exitflag = True
|
||||||
if isinstance(event, bb.command.CommandExit):
|
|
||||||
exitflag = True
|
|
||||||
if isinstance(event, bb.cooker.CookerExit):
|
if isinstance(event, bb.cooker.CookerExit):
|
||||||
exitflag = True
|
exitflag = True
|
||||||
|
|
||||||
@@ -315,18 +304,13 @@ class NCursesUI:
|
|||||||
if activetasks:
|
if activetasks:
|
||||||
taw.appendText("Active Tasks:\n")
|
taw.appendText("Active Tasks:\n")
|
||||||
for task in activetasks.itervalues():
|
for task in activetasks.itervalues():
|
||||||
taw.appendText(task["title"] + '\n')
|
taw.appendText(task["title"])
|
||||||
if failedtasks:
|
if failedtasks:
|
||||||
taw.appendText("Failed Tasks:\n")
|
taw.appendText("Failed Tasks:\n")
|
||||||
for task in failedtasks:
|
for task in failedtasks:
|
||||||
taw.appendText(task["title"] + '\n')
|
taw.appendText(task["title"])
|
||||||
|
|
||||||
curses.doupdate()
|
curses.doupdate()
|
||||||
except EnvironmentError as ioerror:
|
|
||||||
# ignore interrupted io
|
|
||||||
if ioerror.args[0] == 4:
|
|
||||||
pass
|
|
||||||
|
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
if shutdown == 2:
|
if shutdown == 2:
|
||||||
mw.appendText("Third Keyboard Interrupt, exit.\n")
|
mw.appendText("Third Keyboard Interrupt, exit.\n")
|
||||||
@@ -340,7 +324,7 @@ class NCursesUI:
|
|||||||
shutdown = shutdown + 1
|
shutdown = shutdown + 1
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def main(server, eventHandler):
|
def init(server, eventHandler):
|
||||||
if not os.isatty(sys.stdout.fileno()):
|
if not os.isatty(sys.stdout.fileno()):
|
||||||
print("FATAL: Unable to run 'ncurses' UI without a TTY.")
|
print("FATAL: Unable to run 'ncurses' UI without a TTY.")
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -390,7 +390,7 @@ def running_build_failed_cb (running_build, manager):
|
|||||||
print("build failed")
|
print("build failed")
|
||||||
manager.notify_build_failed ()
|
manager.notify_build_failed ()
|
||||||
|
|
||||||
def main (server, eventHandler):
|
def init (server, eventHandler):
|
||||||
# Initialise threading...
|
# Initialise threading...
|
||||||
gobject.threads_init()
|
gobject.threads_init()
|
||||||
gtk.gdk.threads_init()
|
gtk.gdk.threads_init()
|
||||||
|
|||||||
@@ -63,20 +63,17 @@ class BBUIEventQueue:
|
|||||||
|
|
||||||
def queue_event(self, event):
|
def queue_event(self, event):
|
||||||
self.eventQueueLock.acquire()
|
self.eventQueueLock.acquire()
|
||||||
self.eventQueue.append(event)
|
self.eventQueue.append(pickle.loads(event))
|
||||||
self.eventQueueNotify.set()
|
self.eventQueueNotify.set()
|
||||||
self.eventQueueLock.release()
|
self.eventQueueLock.release()
|
||||||
|
|
||||||
def send_event(self, event):
|
|
||||||
self.queue_event(pickle.loads(event))
|
|
||||||
|
|
||||||
def startCallbackHandler(self):
|
def startCallbackHandler(self):
|
||||||
|
|
||||||
server = UIXMLRPCServer()
|
server = UIXMLRPCServer()
|
||||||
self.host, self.port = server.socket.getsockname()
|
self.host, self.port = server.socket.getsockname()
|
||||||
|
|
||||||
server.register_function( self.system_quit, "event.quit" )
|
server.register_function( self.system_quit, "event.quit" )
|
||||||
server.register_function( self.send_event, "event.send" )
|
server.register_function( self.queue_event, "event.send" )
|
||||||
server.socket.settimeout(1)
|
server.socket.settimeout(1)
|
||||||
|
|
||||||
self.EventHandle = self.BBServer.registerEventHandler(self.host, self.port)
|
self.EventHandle = self.BBServer.registerEventHandler(self.host, self.port)
|
||||||
|
|||||||
@@ -17,8 +17,6 @@
|
|||||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
import bb.build
|
|
||||||
|
|
||||||
class BBUIHelper:
|
class BBUIHelper:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.needUpdate = False
|
self.needUpdate = False
|
||||||
@@ -37,6 +35,16 @@ class BBUIHelper:
|
|||||||
self.failed_tasks.append( { 'title' : "%s %s" % (event._package, event._task)})
|
self.failed_tasks.append( { 'title' : "%s %s" % (event._package, event._task)})
|
||||||
self.needUpdate = True
|
self.needUpdate = True
|
||||||
|
|
||||||
|
# Add runqueue event handling
|
||||||
|
#if isinstance(event, bb.runqueue.runQueueTaskCompleted):
|
||||||
|
# a = 1
|
||||||
|
#if isinstance(event, bb.runqueue.runQueueTaskStarted):
|
||||||
|
# a = 1
|
||||||
|
#if isinstance(event, bb.runqueue.runQueueTaskFailed):
|
||||||
|
# a = 1
|
||||||
|
#if isinstance(event, bb.runqueue.runQueueExitWait):
|
||||||
|
# a = 1
|
||||||
|
|
||||||
def getTasks(self):
|
def getTasks(self):
|
||||||
self.needUpdate = False
|
self.needUpdate = False
|
||||||
return (self.running_tasks, self.failed_tasks)
|
return (self.running_tasks, self.failed_tasks)
|
||||||
|
|||||||
@@ -21,14 +21,10 @@ BitBake Utility Functions
|
|||||||
|
|
||||||
import re, fcntl, os, string, stat, shutil, time
|
import re, fcntl, os, string, stat, shutil, time
|
||||||
import sys
|
import sys
|
||||||
import errno
|
|
||||||
import logging
|
|
||||||
import bb
|
import bb
|
||||||
|
import errno
|
||||||
import bb.msg
|
import bb.msg
|
||||||
from commands import getstatusoutput
|
from commands import getstatusoutput
|
||||||
from contextlib import contextmanager
|
|
||||||
|
|
||||||
logger = logging.getLogger("BitBake.Util")
|
|
||||||
|
|
||||||
# Version comparison
|
# Version comparison
|
||||||
separators = ".-"
|
separators = ".-"
|
||||||
@@ -94,7 +90,7 @@ def vercmp(ta, tb):
|
|||||||
(ea, va, ra) = ta
|
(ea, va, ra) = ta
|
||||||
(eb, vb, rb) = tb
|
(eb, vb, rb) = tb
|
||||||
|
|
||||||
r = int(ea or 0) - int(eb or 0)
|
r = int(ea)-int(eb)
|
||||||
if (r == 0):
|
if (r == 0):
|
||||||
r = vercmp_part(va, vb)
|
r = vercmp_part(va, vb)
|
||||||
if (r == 0):
|
if (r == 0):
|
||||||
@@ -195,10 +191,10 @@ def vercmp_string(val1, val2):
|
|||||||
val2 = val2[0].split('.')
|
val2 = val2[0].split('.')
|
||||||
|
|
||||||
# add back decimal point so that .03 does not become "3" !
|
# add back decimal point so that .03 does not become "3" !
|
||||||
for x in xrange(1, len(val1)):
|
for x in range(1, len(val1)):
|
||||||
if val1[x][0] == '0' :
|
if val1[x][0] == '0' :
|
||||||
val1[x] = '.' + val1[x]
|
val1[x] = '.' + val1[x]
|
||||||
for x in xrange(1, len(val2)):
|
for x in range(1, len(val2)):
|
||||||
if val2[x][0] == '0' :
|
if val2[x][0] == '0' :
|
||||||
val2[x] = '.' + val2[x]
|
val2[x] = '.' + val2[x]
|
||||||
|
|
||||||
@@ -215,10 +211,10 @@ def vercmp_string(val1, val2):
|
|||||||
val2[-1] += '_' + val2_prepart
|
val2[-1] += '_' + val2_prepart
|
||||||
# The above code will extend version numbers out so they
|
# The above code will extend version numbers out so they
|
||||||
# have the same number of digits.
|
# have the same number of digits.
|
||||||
for x in xrange(0, len(val1)):
|
for x in range(0, len(val1)):
|
||||||
cmp1 = relparse(val1[x])
|
cmp1 = relparse(val1[x])
|
||||||
cmp2 = relparse(val2[x])
|
cmp2 = relparse(val2[x])
|
||||||
for y in xrange(0, 3):
|
for y in range(0, 3):
|
||||||
myret = cmp1[y] - cmp2[y]
|
myret = cmp1[y] - cmp2[y]
|
||||||
if myret != 0:
|
if myret != 0:
|
||||||
__vercmp_cache__[valkey] = myret
|
__vercmp_cache__[valkey] = myret
|
||||||
@@ -279,7 +275,7 @@ def explode_dep_versions(s):
|
|||||||
|
|
||||||
return r
|
return r
|
||||||
|
|
||||||
def join_deps(deps, commasep=True):
|
def join_deps(deps):
|
||||||
"""
|
"""
|
||||||
Take the result from explode_dep_versions and generate a dependency string
|
Take the result from explode_dep_versions and generate a dependency string
|
||||||
"""
|
"""
|
||||||
@@ -289,10 +285,18 @@ def join_deps(deps, commasep=True):
|
|||||||
result.append(dep + " (" + deps[dep] + ")")
|
result.append(dep + " (" + deps[dep] + ")")
|
||||||
else:
|
else:
|
||||||
result.append(dep)
|
result.append(dep)
|
||||||
if commasep:
|
return ", ".join(result)
|
||||||
return ", ".join(result)
|
|
||||||
else:
|
def extend_deps(dest, src):
|
||||||
return " ".join(result)
|
"""
|
||||||
|
Extend the results from explode_dep_versions by appending all of the items
|
||||||
|
in the second list, avoiding duplicates.
|
||||||
|
"""
|
||||||
|
for dep in src:
|
||||||
|
if dep not in dest:
|
||||||
|
dest[dep] = src[dep]
|
||||||
|
elif dest[dep] != src[dep]:
|
||||||
|
dest[dep] = src[dep]
|
||||||
|
|
||||||
def _print_trace(body, line):
|
def _print_trace(body, line):
|
||||||
"""
|
"""
|
||||||
@@ -300,12 +304,10 @@ def _print_trace(body, line):
|
|||||||
"""
|
"""
|
||||||
# print the environment of the method
|
# print the environment of the method
|
||||||
min_line = max(1, line-4)
|
min_line = max(1, line-4)
|
||||||
max_line = min(line + 4, len(body))
|
max_line = min(line + 4, len(body)-1)
|
||||||
for i in xrange(min_line, max_line + 1):
|
for i in range(min_line, max_line + 1):
|
||||||
if line == i:
|
bb.msg.error(bb.msg.domain.Util, "\t%.4d:%s" % (i, body[i-1]) )
|
||||||
logger.error(' *** %.4d:%s', i, body[i-1])
|
|
||||||
else:
|
|
||||||
logger.error(' %.4d:%s', i, body[i-1])
|
|
||||||
|
|
||||||
def better_compile(text, file, realfile, mode = "exec"):
|
def better_compile(text, file, realfile, mode = "exec"):
|
||||||
"""
|
"""
|
||||||
@@ -317,69 +319,50 @@ def better_compile(text, file, realfile, mode = "exec"):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
# split the text into lines again
|
# split the text into lines again
|
||||||
body = text.split('\n')
|
body = text.split('\n')
|
||||||
logger.error("Error in compiling python function in %s", realfile)
|
bb.msg.error(bb.msg.domain.Util, "Error in compiling python function in: %s" % (realfile))
|
||||||
logger.error(str(e))
|
bb.msg.error(bb.msg.domain.Util, str(e))
|
||||||
if e.lineno:
|
if e.lineno:
|
||||||
logger.error("The lines leading to this error were:")
|
bb.msg.error(bb.msg.domain.Util, "The lines leading to this error were:")
|
||||||
logger.error("\t%d:%s:'%s'", e.lineno, e.__class__.__name__, body[e.lineno-1])
|
bb.msg.error(bb.msg.domain.Util, "\t%d:%s:'%s'" % (e.lineno, e.__class__.__name__, body[e.lineno-1]))
|
||||||
_print_trace(body, e.lineno)
|
_print_trace(body, e.lineno)
|
||||||
else:
|
else:
|
||||||
logger.error("The function causing this error was:")
|
bb.msg.error(bb.msg.domain.Util, "The function causing this error was:")
|
||||||
for line in body:
|
for line in body:
|
||||||
logger.error(line)
|
bb.msg.error(bb.msg.domain.Util, line)
|
||||||
|
|
||||||
raise
|
raise
|
||||||
|
|
||||||
def better_exec(code, context, text, realfile = "<code>"):
|
def better_exec(code, context, text, realfile):
|
||||||
"""
|
"""
|
||||||
Similiar to better_compile, better_exec will
|
Similiar to better_compile, better_exec will
|
||||||
print the lines that are responsible for the
|
print the lines that are responsible for the
|
||||||
error.
|
error.
|
||||||
"""
|
"""
|
||||||
import bb.parse
|
import bb.parse
|
||||||
if not hasattr(code, "co_filename"):
|
|
||||||
code = better_compile(code, realfile, realfile)
|
|
||||||
try:
|
try:
|
||||||
exec(code, _context, context)
|
exec(code, _context, context)
|
||||||
except Exception:
|
except:
|
||||||
(t, value, tb) = sys.exc_info()
|
(t, value, tb) = sys.exc_info()
|
||||||
|
|
||||||
if t in [bb.parse.SkipPackage, bb.build.FuncFailed]:
|
if t in [bb.parse.SkipPackage, bb.build.FuncFailed]:
|
||||||
raise
|
raise
|
||||||
|
|
||||||
import traceback
|
# print the Header of the Error Message
|
||||||
exception = traceback.format_exception_only(t, value)
|
bb.msg.error(bb.msg.domain.Util, "Error in executing python function in: %s" % realfile)
|
||||||
logger.error('Error executing a python function in %s:\n%s',
|
bb.msg.error(bb.msg.domain.Util, "Exception:%s Message:%s" % (t, value))
|
||||||
realfile, ''.join(exception))
|
|
||||||
|
|
||||||
# Strip 'us' from the stack (better_exec call)
|
# Strip 'us' from the stack (better_exec call)
|
||||||
tb = tb.tb_next
|
tb = tb.tb_next
|
||||||
|
|
||||||
textarray = text.split('\n')
|
import traceback
|
||||||
linefailed = traceback.tb_lineno(tb)
|
|
||||||
|
|
||||||
tbextract = traceback.extract_tb(tb)
|
tbextract = traceback.extract_tb(tb)
|
||||||
tbformat = "\n".join(traceback.format_list(tbextract))
|
tbextract = "\n".join(traceback.format_list(tbextract))
|
||||||
logger.error("The stack trace of python calls that resulted in this exception/failure was:")
|
bb.msg.error(bb.msg.domain.Util, "Traceback:")
|
||||||
for line in tbformat.split('\n'):
|
for line in tbextract.split('\n'):
|
||||||
logger.error(line)
|
bb.msg.error(bb.msg.domain.Util, line)
|
||||||
|
|
||||||
logger.error("The code that was being executed was:")
|
line = traceback.tb_lineno(tb)
|
||||||
_print_trace(textarray, linefailed)
|
bb.msg.error(bb.msg.domain.Util, "The lines leading to this error were:")
|
||||||
logger.error("(file: '%s', lineno: %s, function: %s)", tbextract[0][0], tbextract[0][1], tbextract[0][2])
|
_print_trace( text.split('\n'), line )
|
||||||
|
|
||||||
# See if this is a function we constructed and has calls back into other functions in
|
|
||||||
# "text". If so, try and improve the context of the error by diving down the trace
|
|
||||||
level = 0
|
|
||||||
nexttb = tb.tb_next
|
|
||||||
while nexttb is not None:
|
|
||||||
if tbextract[level][0] == tbextract[level+1][0] and tbextract[level+1][2] == tbextract[level][0]:
|
|
||||||
_print_trace(textarray, tbextract[level+1][1])
|
|
||||||
logger.error("(file: '%s', lineno: %s, function: %s)", tbextract[level+1][0], tbextract[level+1][1], tbextract[level+1][2])
|
|
||||||
else:
|
|
||||||
break
|
|
||||||
nexttb = tb.tb_next
|
|
||||||
level = level + 1
|
|
||||||
|
|
||||||
raise
|
raise
|
||||||
|
|
||||||
@@ -389,37 +372,16 @@ def simple_exec(code, context):
|
|||||||
def better_eval(source, locals):
|
def better_eval(source, locals):
|
||||||
return eval(source, _context, locals)
|
return eval(source, _context, locals)
|
||||||
|
|
||||||
@contextmanager
|
def lockfile(name):
|
||||||
def fileslocked(files):
|
|
||||||
"""Context manager for locking and unlocking file locks."""
|
|
||||||
locks = []
|
|
||||||
if files:
|
|
||||||
for lockfile in files:
|
|
||||||
locks.append(bb.utils.lockfile(lockfile))
|
|
||||||
|
|
||||||
yield
|
|
||||||
|
|
||||||
for lock in locks:
|
|
||||||
bb.utils.unlockfile(lock)
|
|
||||||
|
|
||||||
def lockfile(name, shared=False):
|
|
||||||
"""
|
"""
|
||||||
Use the file fn as a lock file, return when the lock has been acquired.
|
Use the file fn as a lock file, return when the lock has been acquired.
|
||||||
Returns a variable to pass to unlockfile().
|
Returns a variable to pass to unlockfile().
|
||||||
"""
|
"""
|
||||||
path = os.path.dirname(name)
|
path = os.path.dirname(name)
|
||||||
if not os.path.isdir(path):
|
if not os.path.isdir(path):
|
||||||
logger.error("Lockfile destination directory '%s' does not exist", path)
|
bb.msg.error(bb.msg.domain.Util, "Error, lockfile path does not exist!: %s" % path)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
if not os.access(path, os.W_OK):
|
|
||||||
logger.error("Error, lockfile path is not writable!: %s" % path)
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
op = fcntl.LOCK_EX
|
|
||||||
if shared:
|
|
||||||
op = fcntl.LOCK_SH
|
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
# If we leave the lockfiles lying around there is no problem
|
# If we leave the lockfiles lying around there is no problem
|
||||||
# but we should clean up after ourselves. This gives potential
|
# but we should clean up after ourselves. This gives potential
|
||||||
@@ -432,31 +394,25 @@ def lockfile(name, shared=False):
|
|||||||
# lock is the most likely to win it.
|
# lock is the most likely to win it.
|
||||||
|
|
||||||
try:
|
try:
|
||||||
lf = open(name, 'a+')
|
lf = open(name, "a + ")
|
||||||
fileno = lf.fileno()
|
fcntl.flock(lf.fileno(), fcntl.LOCK_EX)
|
||||||
fcntl.flock(fileno, op)
|
statinfo = os.fstat(lf.fileno())
|
||||||
statinfo = os.fstat(fileno)
|
|
||||||
if os.path.exists(lf.name):
|
if os.path.exists(lf.name):
|
||||||
statinfo2 = os.stat(lf.name)
|
statinfo2 = os.stat(lf.name)
|
||||||
if statinfo.st_ino == statinfo2.st_ino:
|
if statinfo.st_ino == statinfo2.st_ino:
|
||||||
return lf
|
return lf
|
||||||
lf.close()
|
# File no longer exists or changed, retry
|
||||||
except Exception:
|
lf.close
|
||||||
|
except Exception as e:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
def unlockfile(lf):
|
def unlockfile(lf):
|
||||||
"""
|
"""
|
||||||
Unlock a file locked using lockfile()
|
Unlock a file locked using lockfile()
|
||||||
"""
|
"""
|
||||||
try:
|
os.unlink(lf.name)
|
||||||
# If we had a shared lock, we need to promote to exclusive before
|
|
||||||
# removing the lockfile. Attempt this, ignore failures.
|
|
||||||
fcntl.flock(lf.fileno(), fcntl.LOCK_EX|fcntl.LOCK_NB)
|
|
||||||
os.unlink(lf.name)
|
|
||||||
except (IOError, OSError):
|
|
||||||
pass
|
|
||||||
fcntl.flock(lf.fileno(), fcntl.LOCK_UN)
|
fcntl.flock(lf.fileno(), fcntl.LOCK_UN)
|
||||||
lf.close()
|
lf.close
|
||||||
|
|
||||||
def md5_file(filename):
|
def md5_file(filename):
|
||||||
"""
|
"""
|
||||||
@@ -490,25 +446,13 @@ def sha256_file(filename):
|
|||||||
s.update(line)
|
s.update(line)
|
||||||
return s.hexdigest()
|
return s.hexdigest()
|
||||||
|
|
||||||
def preserved_envvars_exported():
|
def preserved_envvars_list():
|
||||||
"""Variables which are taken from the environment and placed in and exported
|
|
||||||
from the metadata"""
|
|
||||||
return [
|
return [
|
||||||
|
'BBPATH',
|
||||||
|
'BB_PRESERVE_ENV',
|
||||||
|
'BB_ENV_WHITELIST',
|
||||||
|
'BB_ENV_EXTRAWHITE',
|
||||||
'BB_TASKHASH',
|
'BB_TASKHASH',
|
||||||
'HOME',
|
|
||||||
'LOGNAME',
|
|
||||||
'PATH',
|
|
||||||
'PWD',
|
|
||||||
'SHELL',
|
|
||||||
'TERM',
|
|
||||||
'USER',
|
|
||||||
'USERNAME',
|
|
||||||
]
|
|
||||||
|
|
||||||
def preserved_envvars_exported_interactive():
|
|
||||||
"""Variables which are taken from the environment and placed in and exported
|
|
||||||
from the metadata, for interactive tasks"""
|
|
||||||
return [
|
|
||||||
'COLORTERM',
|
'COLORTERM',
|
||||||
'DBUS_SESSION_BUS_ADDRESS',
|
'DBUS_SESSION_BUS_ADDRESS',
|
||||||
'DESKTOP_SESSION',
|
'DESKTOP_SESSION',
|
||||||
@@ -518,26 +462,23 @@ def preserved_envvars_exported_interactive():
|
|||||||
'GNOME_KEYRING_SOCKET',
|
'GNOME_KEYRING_SOCKET',
|
||||||
'GPG_AGENT_INFO',
|
'GPG_AGENT_INFO',
|
||||||
'GTK_RC_FILES',
|
'GTK_RC_FILES',
|
||||||
|
'HOME',
|
||||||
|
'LANG',
|
||||||
|
'LOGNAME',
|
||||||
|
'PATH',
|
||||||
|
'PWD',
|
||||||
'SESSION_MANAGER',
|
'SESSION_MANAGER',
|
||||||
'KRB5CCNAME',
|
'SHELL',
|
||||||
'SSH_AUTH_SOCK',
|
'SSH_AUTH_SOCK',
|
||||||
|
'TERM',
|
||||||
|
'USER',
|
||||||
|
'USERNAME',
|
||||||
|
'_',
|
||||||
'XAUTHORITY',
|
'XAUTHORITY',
|
||||||
'XDG_DATA_DIRS',
|
'XDG_DATA_DIRS',
|
||||||
'XDG_SESSION_COOKIE',
|
'XDG_SESSION_COOKIE',
|
||||||
]
|
]
|
||||||
|
|
||||||
def preserved_envvars():
|
|
||||||
"""Variables which are taken from the environment and placed in the metadata"""
|
|
||||||
v = [
|
|
||||||
'BBPATH',
|
|
||||||
'BB_PRESERVE_ENV',
|
|
||||||
'BB_ENV_WHITELIST',
|
|
||||||
'BB_ENV_EXTRAWHITE',
|
|
||||||
'LANG',
|
|
||||||
'_',
|
|
||||||
]
|
|
||||||
return v + preserved_envvars_exported() + preserved_envvars_exported_interactive()
|
|
||||||
|
|
||||||
def filter_environment(good_vars):
|
def filter_environment(good_vars):
|
||||||
"""
|
"""
|
||||||
Create a pristine environment for bitbake. This will remove variables that
|
Create a pristine environment for bitbake. This will remove variables that
|
||||||
@@ -554,14 +495,10 @@ def filter_environment(good_vars):
|
|||||||
del os.environ[key]
|
del os.environ[key]
|
||||||
|
|
||||||
if len(removed_vars):
|
if len(removed_vars):
|
||||||
logger.debug(1, "Removed the following variables from the environment: %s", ", ".join(removed_vars))
|
bb.msg.debug(1, bb.msg.domain.Util, "Removed the following variables from the environment: %s" % (", ".join(removed_vars)))
|
||||||
|
|
||||||
return removed_vars
|
return removed_vars
|
||||||
|
|
||||||
def create_interactive_env(d):
|
|
||||||
for k in preserved_envvars_exported_interactive():
|
|
||||||
os.setenv(k, bb.data.getVar(k, d, True))
|
|
||||||
|
|
||||||
def clean_environment():
|
def clean_environment():
|
||||||
"""
|
"""
|
||||||
Clean up any spurious environment variables. This will remove any
|
Clean up any spurious environment variables. This will remove any
|
||||||
@@ -571,7 +508,7 @@ def clean_environment():
|
|||||||
if 'BB_ENV_WHITELIST' in os.environ:
|
if 'BB_ENV_WHITELIST' in os.environ:
|
||||||
good_vars = os.environ['BB_ENV_WHITELIST'].split()
|
good_vars = os.environ['BB_ENV_WHITELIST'].split()
|
||||||
else:
|
else:
|
||||||
good_vars = preserved_envvars()
|
good_vars = preserved_envvars_list()
|
||||||
if 'BB_ENV_EXTRAWHITE' in os.environ:
|
if 'BB_ENV_EXTRAWHITE' in os.environ:
|
||||||
good_vars.extend(os.environ['BB_ENV_EXTRAWHITE'].split())
|
good_vars.extend(os.environ['BB_ENV_EXTRAWHITE'].split())
|
||||||
filter_environment(good_vars)
|
filter_environment(good_vars)
|
||||||
@@ -594,20 +531,6 @@ def build_environment(d):
|
|||||||
if export:
|
if export:
|
||||||
os.environ[var] = bb.data.getVar(var, d, True) or ""
|
os.environ[var] = bb.data.getVar(var, d, True) or ""
|
||||||
|
|
||||||
def remove(path, recurse=False):
|
|
||||||
"""Equivalent to rm -f or rm -rf"""
|
|
||||||
if not path:
|
|
||||||
return
|
|
||||||
import os, errno, shutil, glob
|
|
||||||
for name in glob.glob(path):
|
|
||||||
try:
|
|
||||||
os.unlink(name)
|
|
||||||
except OSError as exc:
|
|
||||||
if recurse and exc.errno == errno.EISDIR:
|
|
||||||
shutil.rmtree(name)
|
|
||||||
elif exc.errno != errno.ENOENT:
|
|
||||||
raise
|
|
||||||
|
|
||||||
def prunedir(topdir):
|
def prunedir(topdir):
|
||||||
# Delete everything reachable from the directory named in 'topdir'.
|
# Delete everything reachable from the directory named in 'topdir'.
|
||||||
# CAUTION: This is dangerous!
|
# CAUTION: This is dangerous!
|
||||||
@@ -633,13 +556,15 @@ def prune_suffix(var, suffixes, d):
|
|||||||
return var.replace(suffix, "")
|
return var.replace(suffix, "")
|
||||||
return var
|
return var
|
||||||
|
|
||||||
def mkdirhier(directory):
|
def mkdirhier(dir):
|
||||||
"""Create a directory like 'mkdir -p', but does not complain if
|
"""Create a directory like 'mkdir -p', but does not complain if
|
||||||
directory already exists like os.makedirs
|
directory already exists like os.makedirs
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
bb.msg.debug(3, bb.msg.domain.Util, "mkdirhier(%s)" % dir)
|
||||||
try:
|
try:
|
||||||
os.makedirs(directory)
|
os.makedirs(dir)
|
||||||
|
bb.msg.debug(2, bb.msg.domain.Util, "created " + dir)
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
if e.errno != errno.EEXIST:
|
if e.errno != errno.EEXIST:
|
||||||
raise e
|
raise e
|
||||||
@@ -773,23 +698,16 @@ def copyfile(src, dest, newmtime = None, sstat = None):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
if stat.S_ISREG(sstat[stat.ST_MODE]):
|
if stat.S_ISREG(sstat[stat.ST_MODE]):
|
||||||
try:
|
os.chmod(src, stat.S_IRUSR) # Make sure we can read it
|
||||||
srcchown = False
|
try: # For safety copy then move it over.
|
||||||
if not os.access(src, os.R_OK):
|
|
||||||
# Make sure we can read it
|
|
||||||
srcchown = True
|
|
||||||
os.chmod(src, sstat[stat.ST_MODE] | stat.S_IRUSR)
|
|
||||||
|
|
||||||
# For safety copy then move it over.
|
|
||||||
shutil.copyfile(src, dest + "#new")
|
shutil.copyfile(src, dest + "#new")
|
||||||
os.rename(dest + "#new", dest)
|
os.rename(dest + "#new", dest)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print('copyfile: copy', src, '->', dest, 'failed.', e)
|
print('copyfile: copy', src, '->', dest, 'failed.', e)
|
||||||
return False
|
return False
|
||||||
finally:
|
finally:
|
||||||
if srcchown:
|
os.chmod(src, sstat[stat.ST_MODE])
|
||||||
os.chmod(src, sstat[stat.ST_MODE])
|
os.utime(src, (sstat[stat.ST_ATIME], sstat[stat.ST_MTIME]))
|
||||||
os.utime(src, (sstat[stat.ST_ATIME], sstat[stat.ST_MTIME]))
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
#we don't yet handle special, so we need to fall back to /bin/mv
|
#we don't yet handle special, so we need to fall back to /bin/mv
|
||||||
@@ -832,24 +750,13 @@ def init_logger(logger, verbose, debug, debug_domains):
|
|||||||
Set verbosity and debug levels in the logger
|
Set verbosity and debug levels in the logger
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
if verbose:
|
||||||
|
logger.set_verbose(True)
|
||||||
|
|
||||||
if debug:
|
if debug:
|
||||||
bb.msg.set_debug_level(debug)
|
logger.set_debug_level(debug)
|
||||||
elif verbose:
|
|
||||||
bb.msg.set_verbose(True)
|
|
||||||
else:
|
else:
|
||||||
bb.msg.set_debug_level(0)
|
logger.set_debug_level(0)
|
||||||
|
|
||||||
if debug_domains:
|
if debug_domains:
|
||||||
bb.msg.set_debug_domains(debug_domains)
|
logger.set_debug_domains(debug_domains)
|
||||||
|
|
||||||
def to_boolean(string, default=None):
|
|
||||||
if not string:
|
|
||||||
return default
|
|
||||||
|
|
||||||
normalized = string.lower()
|
|
||||||
if normalized in ("y", "yes", "1", "true"):
|
|
||||||
return True
|
|
||||||
elif normalized in ("n", "no", "0", "false"):
|
|
||||||
return False
|
|
||||||
else:
|
|
||||||
raise ValueError("Invalid value for to_boolean: %s" % string)
|
|
||||||
|
|||||||
@@ -1,384 +0,0 @@
|
|||||||
#!/usr/bin/python
|
|
||||||
# -*- coding: iso-8859-1 -*-
|
|
||||||
#
|
|
||||||
# progressbar - Text progressbar library for python.
|
|
||||||
# Copyright (c) 2005 Nilton Volpato
|
|
||||||
#
|
|
||||||
# This library is free software; you can redistribute it and/or
|
|
||||||
# modify it under the terms of the GNU Lesser General Public
|
|
||||||
# License as published by the Free Software Foundation; either
|
|
||||||
# version 2.1 of the License, or (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This library 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
|
|
||||||
# Lesser General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser General Public
|
|
||||||
# License along with this library; if not, write to the Free Software
|
|
||||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
|
|
||||||
|
|
||||||
"""Text progressbar library for python.
|
|
||||||
|
|
||||||
This library provides a text mode progressbar. This is typically used
|
|
||||||
to display the progress of a long running operation, providing a
|
|
||||||
visual clue that processing is underway.
|
|
||||||
|
|
||||||
The ProgressBar class manages the progress, and the format of the line
|
|
||||||
is given by a number of widgets. A widget is an object that may
|
|
||||||
display diferently depending on the state of the progress. There are
|
|
||||||
three types of widget:
|
|
||||||
- a string, which always shows itself;
|
|
||||||
- a ProgressBarWidget, which may return a diferent value every time
|
|
||||||
it's update method is called; and
|
|
||||||
- a ProgressBarWidgetHFill, which is like ProgressBarWidget, except it
|
|
||||||
expands to fill the remaining width of the line.
|
|
||||||
|
|
||||||
The progressbar module is very easy to use, yet very powerful. And
|
|
||||||
automatically supports features like auto-resizing when available.
|
|
||||||
"""
|
|
||||||
|
|
||||||
from __future__ import division
|
|
||||||
|
|
||||||
__author__ = "Nilton Volpato"
|
|
||||||
__author_email__ = "first-name dot last-name @ gmail.com"
|
|
||||||
__date__ = "2006-05-07"
|
|
||||||
__version__ = "2.3-dev"
|
|
||||||
|
|
||||||
import sys, time, os
|
|
||||||
from array import array
|
|
||||||
try:
|
|
||||||
from fcntl import ioctl
|
|
||||||
import termios
|
|
||||||
except ImportError:
|
|
||||||
pass
|
|
||||||
import signal
|
|
||||||
try:
|
|
||||||
basestring
|
|
||||||
except NameError:
|
|
||||||
basestring = (str,)
|
|
||||||
|
|
||||||
class ProgressBarWidget(object):
|
|
||||||
"""This is an element of ProgressBar formatting.
|
|
||||||
|
|
||||||
The ProgressBar object will call it's update value when an update
|
|
||||||
is needed. It's size may change between call, but the results will
|
|
||||||
not be good if the size changes drastically and repeatedly.
|
|
||||||
"""
|
|
||||||
def update(self, pbar):
|
|
||||||
"""Returns the string representing the widget.
|
|
||||||
|
|
||||||
The parameter pbar is a reference to the calling ProgressBar,
|
|
||||||
where one can access attributes of the class for knowing how
|
|
||||||
the update must be made.
|
|
||||||
|
|
||||||
At least this function must be overriden."""
|
|
||||||
pass
|
|
||||||
|
|
||||||
class ProgressBarWidgetHFill(object):
|
|
||||||
"""This is a variable width element of ProgressBar formatting.
|
|
||||||
|
|
||||||
The ProgressBar object will call it's update value, informing the
|
|
||||||
width this object must the made. This is like TeX \\hfill, it will
|
|
||||||
expand to fill the line. You can use more than one in the same
|
|
||||||
line, and they will all have the same width, and together will
|
|
||||||
fill the line.
|
|
||||||
"""
|
|
||||||
def update(self, pbar, width):
|
|
||||||
"""Returns the string representing the widget.
|
|
||||||
|
|
||||||
The parameter pbar is a reference to the calling ProgressBar,
|
|
||||||
where one can access attributes of the class for knowing how
|
|
||||||
the update must be made. The parameter width is the total
|
|
||||||
horizontal width the widget must have.
|
|
||||||
|
|
||||||
At least this function must be overriden."""
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class ETA(ProgressBarWidget):
|
|
||||||
"Widget for the Estimated Time of Arrival"
|
|
||||||
def format_time(self, seconds):
|
|
||||||
return time.strftime('%H:%M:%S', time.gmtime(seconds))
|
|
||||||
def update(self, pbar):
|
|
||||||
if pbar.currval == 0:
|
|
||||||
return 'ETA: --:--:--'
|
|
||||||
elif pbar.finished:
|
|
||||||
return 'Time: %s' % self.format_time(pbar.seconds_elapsed)
|
|
||||||
else:
|
|
||||||
elapsed = pbar.seconds_elapsed
|
|
||||||
eta = elapsed * pbar.maxval / pbar.currval - elapsed
|
|
||||||
return 'ETA: %s' % self.format_time(eta)
|
|
||||||
|
|
||||||
class FileTransferSpeed(ProgressBarWidget):
|
|
||||||
"Widget for showing the transfer speed (useful for file transfers)."
|
|
||||||
def __init__(self, unit='B'):
|
|
||||||
self.unit = unit
|
|
||||||
self.fmt = '%6.2f %s'
|
|
||||||
self.prefixes = ['', 'K', 'M', 'G', 'T', 'P']
|
|
||||||
def update(self, pbar):
|
|
||||||
if pbar.seconds_elapsed < 2e-6:#== 0:
|
|
||||||
bps = 0.0
|
|
||||||
else:
|
|
||||||
bps = pbar.currval / pbar.seconds_elapsed
|
|
||||||
spd = bps
|
|
||||||
for u in self.prefixes:
|
|
||||||
if spd < 1000:
|
|
||||||
break
|
|
||||||
spd /= 1000
|
|
||||||
return self.fmt % (spd, u + self.unit + '/s')
|
|
||||||
|
|
||||||
class RotatingMarker(ProgressBarWidget):
|
|
||||||
"A rotating marker for filling the bar of progress."
|
|
||||||
def __init__(self, markers='|/-\\'):
|
|
||||||
self.markers = markers
|
|
||||||
self.curmark = -1
|
|
||||||
def update(self, pbar):
|
|
||||||
if pbar.finished:
|
|
||||||
return self.markers[0]
|
|
||||||
self.curmark = (self.curmark + 1) % len(self.markers)
|
|
||||||
return self.markers[self.curmark]
|
|
||||||
|
|
||||||
class Percentage(ProgressBarWidget):
|
|
||||||
"Just the percentage done."
|
|
||||||
def update(self, pbar):
|
|
||||||
return '%3d%%' % pbar.percentage()
|
|
||||||
|
|
||||||
class SimpleProgress(ProgressBarWidget):
|
|
||||||
"Returns what is already done and the total, e.g.: '5 of 47'"
|
|
||||||
def __init__(self, sep=' of '):
|
|
||||||
self.sep = sep
|
|
||||||
def update(self, pbar):
|
|
||||||
return '%d%s%d' % (pbar.currval, self.sep, pbar.maxval)
|
|
||||||
|
|
||||||
class Bar(ProgressBarWidgetHFill):
|
|
||||||
"The bar of progress. It will stretch to fill the line."
|
|
||||||
def __init__(self, marker='#', left='|', right='|'):
|
|
||||||
self.marker = marker
|
|
||||||
self.left = left
|
|
||||||
self.right = right
|
|
||||||
def _format_marker(self, pbar):
|
|
||||||
if isinstance(self.marker, basestring):
|
|
||||||
return self.marker
|
|
||||||
else:
|
|
||||||
return self.marker.update(pbar)
|
|
||||||
def update(self, pbar, width):
|
|
||||||
percent = pbar.percentage()
|
|
||||||
cwidth = width - len(self.left) - len(self.right)
|
|
||||||
marked_width = int(percent * cwidth // 100)
|
|
||||||
m = self._format_marker(pbar)
|
|
||||||
bar = (self.left + (m * marked_width).ljust(cwidth) + self.right)
|
|
||||||
return bar
|
|
||||||
|
|
||||||
class ReverseBar(Bar):
|
|
||||||
"The reverse bar of progress, or bar of regress. :)"
|
|
||||||
def update(self, pbar, width):
|
|
||||||
percent = pbar.percentage()
|
|
||||||
cwidth = width - len(self.left) - len(self.right)
|
|
||||||
marked_width = int(percent * cwidth // 100)
|
|
||||||
m = self._format_marker(pbar)
|
|
||||||
bar = (self.left + (m*marked_width).rjust(cwidth) + self.right)
|
|
||||||
return bar
|
|
||||||
|
|
||||||
default_widgets = [Percentage(), ' ', Bar()]
|
|
||||||
class ProgressBar(object):
|
|
||||||
"""This is the ProgressBar class, it updates and prints the bar.
|
|
||||||
|
|
||||||
A common way of using it is like:
|
|
||||||
>>> pbar = ProgressBar().start()
|
|
||||||
>>> for i in xrange(100):
|
|
||||||
... # do something
|
|
||||||
... pbar.update(i+1)
|
|
||||||
...
|
|
||||||
>>> pbar.finish()
|
|
||||||
|
|
||||||
You can also use a progressbar as an iterator:
|
|
||||||
>>> progress = ProgressBar()
|
|
||||||
>>> for i in progress(some_iterable):
|
|
||||||
... # do something
|
|
||||||
...
|
|
||||||
|
|
||||||
But anything you want to do is possible (well, almost anything).
|
|
||||||
You can supply different widgets of any type in any order. And you
|
|
||||||
can even write your own widgets! There are many widgets already
|
|
||||||
shipped and you should experiment with them.
|
|
||||||
|
|
||||||
The term_width parameter must be an integer or None. In the latter case
|
|
||||||
it will try to guess it, if it fails it will default to 80 columns.
|
|
||||||
|
|
||||||
When implementing a widget update method you may access any
|
|
||||||
attribute or function of the ProgressBar object calling the
|
|
||||||
widget's update method. The most important attributes you would
|
|
||||||
like to access are:
|
|
||||||
- currval: current value of the progress, 0 <= currval <= maxval
|
|
||||||
- maxval: maximum (and final) value of the progress
|
|
||||||
- finished: True if the bar has finished (reached 100%), False o/w
|
|
||||||
- start_time: the time when start() method of ProgressBar was called
|
|
||||||
- seconds_elapsed: seconds elapsed since start_time
|
|
||||||
- percentage(): percentage of the progress [0..100]. This is a method.
|
|
||||||
|
|
||||||
The attributes above are unlikely to change between different versions,
|
|
||||||
the other ones may change or cease to exist without notice, so try to rely
|
|
||||||
only on the ones documented above if you are extending the progress bar.
|
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = ('currval', 'fd', 'finished', 'last_update_time', 'maxval',
|
|
||||||
'next_update', 'num_intervals', 'seconds_elapsed',
|
|
||||||
'signal_set', 'start_time', 'term_width', 'update_interval',
|
|
||||||
'widgets', '_iterable')
|
|
||||||
|
|
||||||
_DEFAULT_MAXVAL = 100
|
|
||||||
|
|
||||||
def __init__(self, maxval=None, widgets=default_widgets, term_width=None,
|
|
||||||
fd=sys.stderr):
|
|
||||||
self.maxval = maxval
|
|
||||||
self.widgets = widgets
|
|
||||||
self.fd = fd
|
|
||||||
self.signal_set = False
|
|
||||||
if term_width is not None:
|
|
||||||
self.term_width = term_width
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
self._handle_resize(None, None)
|
|
||||||
signal.signal(signal.SIGWINCH, self._handle_resize)
|
|
||||||
self.signal_set = True
|
|
||||||
except (SystemExit, KeyboardInterrupt):
|
|
||||||
raise
|
|
||||||
except:
|
|
||||||
self.term_width = int(os.environ.get('COLUMNS', 80)) - 1
|
|
||||||
|
|
||||||
self.currval = 0
|
|
||||||
self.finished = False
|
|
||||||
self.start_time = None
|
|
||||||
self.last_update_time = None
|
|
||||||
self.seconds_elapsed = 0
|
|
||||||
self._iterable = None
|
|
||||||
|
|
||||||
def __call__(self, iterable):
|
|
||||||
try:
|
|
||||||
self.maxval = len(iterable)
|
|
||||||
except TypeError:
|
|
||||||
# If the iterable has no length, then rely on the value provided
|
|
||||||
# by the user, otherwise fail.
|
|
||||||
if not (isinstance(self.maxval, (int, long)) and self.maxval > 0):
|
|
||||||
raise RuntimeError('Could not determine maxval from iterable. '
|
|
||||||
'You must explicitly provide a maxval.')
|
|
||||||
self._iterable = iter(iterable)
|
|
||||||
self.start()
|
|
||||||
return self
|
|
||||||
|
|
||||||
def __iter__(self):
|
|
||||||
return self
|
|
||||||
|
|
||||||
def next(self):
|
|
||||||
try:
|
|
||||||
next = self._iterable.next()
|
|
||||||
self.update(self.currval + 1)
|
|
||||||
return next
|
|
||||||
except StopIteration:
|
|
||||||
self.finish()
|
|
||||||
raise
|
|
||||||
|
|
||||||
def _handle_resize(self, signum, frame):
|
|
||||||
h, w = array('h', ioctl(self.fd, termios.TIOCGWINSZ, '\0' * 8))[:2]
|
|
||||||
self.term_width = w
|
|
||||||
|
|
||||||
def percentage(self):
|
|
||||||
"Returns the percentage of the progress."
|
|
||||||
return self.currval * 100.0 / self.maxval
|
|
||||||
|
|
||||||
def _format_widgets(self):
|
|
||||||
r = []
|
|
||||||
hfill_inds = []
|
|
||||||
num_hfill = 0
|
|
||||||
currwidth = 0
|
|
||||||
for i, w in enumerate(self.widgets):
|
|
||||||
if isinstance(w, ProgressBarWidgetHFill):
|
|
||||||
r.append(w)
|
|
||||||
hfill_inds.append(i)
|
|
||||||
num_hfill += 1
|
|
||||||
elif isinstance(w, basestring):
|
|
||||||
r.append(w)
|
|
||||||
currwidth += len(w)
|
|
||||||
else:
|
|
||||||
weval = w.update(self)
|
|
||||||
currwidth += len(weval)
|
|
||||||
r.append(weval)
|
|
||||||
for iw in hfill_inds:
|
|
||||||
widget_width = int((self.term_width - currwidth) // num_hfill)
|
|
||||||
r[iw] = r[iw].update(self, widget_width)
|
|
||||||
return r
|
|
||||||
|
|
||||||
def _format_line(self):
|
|
||||||
return ''.join(self._format_widgets()).ljust(self.term_width)
|
|
||||||
|
|
||||||
def _next_update(self):
|
|
||||||
return int((int(self.num_intervals *
|
|
||||||
(self.currval / self.maxval)) + 1) *
|
|
||||||
self.update_interval)
|
|
||||||
|
|
||||||
def _need_update(self):
|
|
||||||
"""Returns true when the progressbar should print an updated line.
|
|
||||||
|
|
||||||
You can override this method if you want finer grained control over
|
|
||||||
updates.
|
|
||||||
|
|
||||||
The current implementation is optimized to be as fast as possible and
|
|
||||||
as economical as possible in the number of updates. However, depending
|
|
||||||
on your usage you may want to do more updates. For instance, if your
|
|
||||||
progressbar stays in the same percentage for a long time, and you want
|
|
||||||
to update other widgets, like ETA, then you could return True after
|
|
||||||
some time has passed with no updates.
|
|
||||||
|
|
||||||
Ideally you could call self._format_line() and see if it's different
|
|
||||||
from the previous _format_line() call, but calling _format_line() takes
|
|
||||||
around 20 times more time than calling this implementation of
|
|
||||||
_need_update().
|
|
||||||
"""
|
|
||||||
return self.currval >= self.next_update
|
|
||||||
|
|
||||||
def update(self, value):
|
|
||||||
"Updates the progress bar to a new value."
|
|
||||||
assert 0 <= value <= self.maxval, '0 <= %d <= %d' % (value, self.maxval)
|
|
||||||
self.currval = value
|
|
||||||
if not self._need_update():
|
|
||||||
return
|
|
||||||
if self.start_time is None:
|
|
||||||
raise RuntimeError('You must call start() before calling update()')
|
|
||||||
now = time.time()
|
|
||||||
self.seconds_elapsed = now - self.start_time
|
|
||||||
self.next_update = self._next_update()
|
|
||||||
self.fd.write(self._format_line() + '\r')
|
|
||||||
self.last_update_time = now
|
|
||||||
|
|
||||||
def start(self):
|
|
||||||
"""Starts measuring time, and prints the bar at 0%.
|
|
||||||
|
|
||||||
It returns self so you can use it like this:
|
|
||||||
>>> pbar = ProgressBar().start()
|
|
||||||
>>> for i in xrange(100):
|
|
||||||
... # do something
|
|
||||||
... pbar.update(i+1)
|
|
||||||
...
|
|
||||||
>>> pbar.finish()
|
|
||||||
"""
|
|
||||||
if self.maxval is None:
|
|
||||||
self.maxval = self._DEFAULT_MAXVAL
|
|
||||||
assert self.maxval > 0
|
|
||||||
|
|
||||||
self.num_intervals = max(100, self.term_width)
|
|
||||||
self.update_interval = self.maxval / self.num_intervals
|
|
||||||
self.next_update = 0
|
|
||||||
|
|
||||||
self.start_time = self.last_update_time = time.time()
|
|
||||||
self.update(0)
|
|
||||||
return self
|
|
||||||
|
|
||||||
def finish(self):
|
|
||||||
"""Used to tell the progress is finished."""
|
|
||||||
self.finished = True
|
|
||||||
self.update(self.maxval)
|
|
||||||
self.fd.write('\n')
|
|
||||||
if self.signal_set:
|
|
||||||
signal.signal(signal.SIGWINCH, signal.SIG_DFL)
|
|
||||||
@@ -7,7 +7,6 @@
|
|||||||
|
|
||||||
"""PLY grammar file.
|
"""PLY grammar file.
|
||||||
"""
|
"""
|
||||||
import os.path
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
import pyshlex
|
import pyshlex
|
||||||
@@ -649,10 +648,7 @@ def p_error(p):
|
|||||||
try:
|
try:
|
||||||
import pyshtables
|
import pyshtables
|
||||||
except ImportError:
|
except ImportError:
|
||||||
outputdir = os.path.dirname(__file__)
|
yacc.yacc(tabmodule = 'pyshtables')
|
||||||
if not os.access(outputdir, os.W_OK):
|
|
||||||
outputdir = ''
|
|
||||||
yacc.yacc(tabmodule = 'pyshtables', outputdir = outputdir, debug = 0)
|
|
||||||
else:
|
else:
|
||||||
yacc.yacc(tabmodule = 'pysh.pyshtables', write_tables = 0, debug = 0)
|
yacc.yacc(tabmodule = 'pysh.pyshtables', write_tables = 0, debug = 0)
|
||||||
|
|
||||||
@@ -708,9 +704,6 @@ def format_commands(v):
|
|||||||
if v.reverse_status:
|
if v.reverse_status:
|
||||||
name = '!' + name
|
name = '!' + name
|
||||||
return [name, format_commands(v.commands)]
|
return [name, format_commands(v.commands)]
|
||||||
elif isinstance(v, Case):
|
|
||||||
name = ['Case']
|
|
||||||
name += [v.name, format_commands(v.items)]
|
|
||||||
elif isinstance(v, SimpleCommand):
|
elif isinstance(v, SimpleCommand):
|
||||||
name = ['SimpleCommand']
|
name = ['SimpleCommand']
|
||||||
if v.words:
|
if v.words:
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
XSLTOPTS = --stringparam html.stylesheet style.css \
|
|
||||||
--stringparam chapter.autolabel 1 \
|
|
||||||
--stringparam appendix.autolabel A \
|
|
||||||
--stringparam section.autolabel 1 \
|
|
||||||
--stringparam section.label.includes.component.label 1 \
|
|
||||||
--xinclude
|
|
||||||
|
|
||||||
##
|
|
||||||
# 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: html pdf tarball
|
|
||||||
|
|
||||||
pdf:
|
|
||||||
../tools/poky-docbook-to-pdf adt-manual.xml ../template
|
|
||||||
|
|
||||||
##
|
|
||||||
# These URI should be rewritten by your distribution's xml catalog to
|
|
||||||
# match your localy installed XSL stylesheets.
|
|
||||||
|
|
||||||
html:
|
|
||||||
# See http://www.sagehill.net/docbookxsl/HtmlOutput.html
|
|
||||||
|
|
||||||
# xsltproc $(XSLTOPTS) -o adt-manual.html $(XSL_XHTML_URI) adt-manual.xml
|
|
||||||
xsltproc $(XSLTOPTS) -o adt-manual.html adt-manual-customization.xsl adt-manual.xml
|
|
||||||
|
|
||||||
tarball: html
|
|
||||||
tar -cvzf adt-manual.tgz adt-manual.html style.css figures/adt-title.png figures/yocto-project-transp.png
|
|
||||||
|
|
||||||
validate:
|
|
||||||
xmllint --postvalid --xinclude --noout adt-manual.xml
|
|
||||||
|
|
||||||
OUTPUTS = adt-manual.tgz adt-manual.html adt-manual.pdf
|
|
||||||
SOURCES = *.png *.xml *.css
|
|
||||||
|
|
||||||
publish:
|
|
||||||
scp -r $(OUTPUTS) $(SOURCES) o-hand.com:/srv/www/pokylinux.org/doc/
|
|
||||||
|
|
||||||
clean:
|
|
||||||
rm -f $(OUTPUTS)
|
|
||||||
@@ -1,66 +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='using-the-command-line'>
|
|
||||||
<title>Using the Command Line</title>
|
|
||||||
<para>
|
|
||||||
Recall that earlier we talked about how to use an existing toolchain
|
|
||||||
tarball that had been installed into <filename>/opt/poky</filename>,
|
|
||||||
which is outside of the Poky build environment
|
|
||||||
(see <xref linkend='using-an-existing-toolchain-tarball'>
|
|
||||||
“Using an Existing Toolchain Tarball”)</xref>.
|
|
||||||
And, that sourcing your architecture-specific environment setup script
|
|
||||||
initializes a suitable development environment.
|
|
||||||
This setup occurs by adding the compiler, QEMU scripts, QEMU binary,
|
|
||||||
a special version of <filename>pkgconfig</filename> and other useful
|
|
||||||
utilities to the <filename>PATH</filename> variable.
|
|
||||||
Variables to assist pkgconfig and autotools are also defined so that,
|
|
||||||
for example, <filename>configure.sh</filename> can find pre-generated
|
|
||||||
test results for tests that need target hardware on which to run.
|
|
||||||
These conditions allow you to easily use the toolchain outside of the
|
|
||||||
Poky build environment on both autotools-based projects and
|
|
||||||
makefile-based projects.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<section id='autotools-based-projects'>
|
|
||||||
<title>Autotools-Based Projects</title>
|
|
||||||
<para>
|
|
||||||
For an autotools-based project you can use the cross-toolchain by just
|
|
||||||
passing the appropriate host option to <filename>configure.sh</filename>.
|
|
||||||
The host option you use is derived from the name of the environment setup
|
|
||||||
script in <filename>/opt/poky</filename> resulting from unpacking the
|
|
||||||
cross-toolchain tarball.
|
|
||||||
For example, the host option for an ARM-based target that uses the GNU EABI
|
|
||||||
is <filename>armv5te-poky-linux-gnueabi</filename>.
|
|
||||||
Note that the name of the script is
|
|
||||||
<filename>environment-setup-armv5te-poky-linux-gnueabi</filename>.
|
|
||||||
Thus, the following command works:
|
|
||||||
<literallayout class='monospaced'>
|
|
||||||
$ configure ‐‐host-armv5te-poky-linux-gnueabi ‐‐with-libtool-sysroot=<sysroot-dir>
|
|
||||||
</literallayout>
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
This single command updates your project and rebuilds it using the appropriate
|
|
||||||
cross-toolchain tools.
|
|
||||||
</para>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section id='makefile-based-projects'>
|
|
||||||
<title>Makefile-Based Projects</title>
|
|
||||||
<para>
|
|
||||||
For a makefile-based project you use the cross-toolchain by making sure
|
|
||||||
the tools are used.
|
|
||||||
You can do this as follows:
|
|
||||||
<literallayout class='monospaced'>
|
|
||||||
CC=arm-poky-linux-gnueabi-gcc
|
|
||||||
LD=arm-poky-linux-gnueabi-ld
|
|
||||||
CFLAGS=”${CFLAGS} ‐‐sysroot=<sysroot-dir>”
|
|
||||||
CXXFLAGS=”${CXXFLAGS} ‐‐sysroot=<sysroot-dir>”
|
|
||||||
</literallayout>
|
|
||||||
</para>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
</chapter>
|
|
||||||
<!--
|
|
||||||
vim: expandtab tw=80 ts=4
|
|
||||||
-->
|
|
||||||
@@ -1,435 +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='adt-eclipse'>
|
|
||||||
<title>Working Within Eclipse</title>
|
|
||||||
<para>
|
|
||||||
The Eclipse IDE is a popular development environment and it fully supports
|
|
||||||
development using Yocto Project.
|
|
||||||
When you install and configure the Eclipse Yocto Project Plug-in into
|
|
||||||
the Eclipse IDE you maximize your Yocto Project design experience.
|
|
||||||
Installing and configuring the Plug-in results in an environment that
|
|
||||||
has extensions specifically designed to let you more easily develop software.
|
|
||||||
These extensions allow for cross-compilation and deployment and execution of
|
|
||||||
your output into a QEMU emulation session.
|
|
||||||
You can also perform cross-debugging and profiling.
|
|
||||||
The environment also has a suite of tools that allows you to perform
|
|
||||||
remote profiling, tracing, collection of power data, collection of
|
|
||||||
latency data, and collection of performance data.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
This section describes how to install and configure the Eclipse IDE
|
|
||||||
Yocto Plug-in and how to use it to develop your Yocto Project.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<section id='setting-up-the-eclipse-ide'>
|
|
||||||
<title>Setting Up the Eclipse IDE</title>
|
|
||||||
<para>
|
|
||||||
To develop within the Eclipse IDE you need to do the following:
|
|
||||||
<orderedlist>
|
|
||||||
<listitem><para>Be sure the optimal version of Eclipse IDE
|
|
||||||
is installed.</para></listitem>
|
|
||||||
<listitem><para>Install required Eclipse plug-ins prior to installing
|
|
||||||
the Eclipse Yocto Plug-in.</para></listitem>
|
|
||||||
<listitem><para>Configure the Eclipse Yocto Plug-in.</para></listitem>
|
|
||||||
</orderedlist>
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<section id='installing-eclipse-ide'>
|
|
||||||
<title>Installing Eclipse IDE</title>
|
|
||||||
<para>
|
|
||||||
It is recommended that you have the Helios 3.6.1 version of the
|
|
||||||
Eclipse IDE installed on your development system.
|
|
||||||
If you don’t have this version you can find it at
|
|
||||||
<ulink url='http://www.eclipse.org/downloads'></ulink>.
|
|
||||||
From that site, choose the Eclipse Classic version.
|
|
||||||
This version contains the Eclipse Platform, the Java Development
|
|
||||||
Tools (JDT), and the Plug-in Development Environment.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
Once you have downloaded the tarball, extract it into a clean
|
|
||||||
directory and complete the installation.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
One issue exists that you need to be aware of regarding the Java
|
|
||||||
Virtual machine’s garbage collection (GC) process.
|
|
||||||
The GC process does not clean up the permanent generation
|
|
||||||
space (PermGen).
|
|
||||||
This space stores meta-data descriptions of classes.
|
|
||||||
The default value is set too small and it could trigger an
|
|
||||||
out-of-memory error such as the following:
|
|
||||||
<literallayout class='monospaced'>
|
|
||||||
Java.lang.OutOfMemoryError: PermGen space
|
|
||||||
</literallayout>
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
This error causes the application to hang.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
To fix this issue you can use the ‐‐vmargs option when you start
|
|
||||||
Eclipse to increase the size of the permanent generation space:
|
|
||||||
<literallayout class='monospaced'>
|
|
||||||
eclipse ‐‐vmargs ‐‐XX:PermSize=256M
|
|
||||||
</literallayout>
|
|
||||||
</para>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section id='installing-required-plug-ins-and-the-eclipse-yocto-plug-in'>
|
|
||||||
<title>Installing Required Plug-ins and the Eclipse Yocto Plug-in</title>
|
|
||||||
<para>
|
|
||||||
Before installing the Yocto Plug-in you need to be sure that the
|
|
||||||
CDT 7.0, RSE 3.2, and Autotools plug-ins are all installed in the
|
|
||||||
following order.
|
|
||||||
After installing these three plug-ins, you can install the
|
|
||||||
Eclipse Yocto Plug-in.
|
|
||||||
Use the following URLs for the plug-ins:
|
|
||||||
<orderedlist>
|
|
||||||
<listitem><para><emphasis>CDT 7.0</emphasis> –
|
|
||||||
<ulink url='http://download.eclipse.org/tools/cdt/releases/helios/'></ulink>:
|
|
||||||
For CDT main features select the checkbox so you get all items.
|
|
||||||
For CDT optional features expand the selections and check
|
|
||||||
“C/C++ Remote Launch”.</para></listitem>
|
|
||||||
<listitem><para><emphasis>RSE 3.2</emphasis> –
|
|
||||||
<ulink url='http://download.eclipse.org/tm/updates/3.2'></ulink>:
|
|
||||||
Check the box next to “TM and RSE Main Features” so you select all
|
|
||||||
those items.
|
|
||||||
Note that all items in the main features depend on 3.2.1 version.
|
|
||||||
Expand the items under “TM and RSE Uncategorized 3.2.1” and
|
|
||||||
select the following: “Remote System Explorer End-User Runtime”,
|
|
||||||
“Remote System Explorer Extended SDK”, “Remote System Explorer User Actions”,
|
|
||||||
“RSE Core”, “RSE Terminals UI”, and “Target Management Terminal”.</para></listitem>
|
|
||||||
<listitem><para><emphasis>Autotools</emphasis> –
|
|
||||||
<ulink url='http://www.download.eclipse.org/technology/linuxtools/update/'></ulink>:
|
|
||||||
Expand the items under “Linux Tools” and select “Autotools support for
|
|
||||||
CDT (Incubation)”.</para></listitem>
|
|
||||||
<listitem><para><emphasis>Yocto Plug-in</emphasis> –
|
|
||||||
<ulink url='http://www.yoctoproject.org/downloads/eclipse-plugin/'></ulink>:
|
|
||||||
Check the box next to “Development tools & SDKs for Yocto Linux”
|
|
||||||
to select all the items.</para></listitem>
|
|
||||||
</orderedlist>
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
Follow these general steps to install a plug-in:
|
|
||||||
<orderedlist>
|
|
||||||
<listitem><para>From within the Eclipse IDE select the
|
|
||||||
“Install New Software” item from the “Help” menu.</para></listitem>
|
|
||||||
<listitem><para>Click “Add…” in the “Work with:” area.</para></listitem>
|
|
||||||
<listitem><para>Enter the URL for the repository and leave the “Name”
|
|
||||||
field blank.</para></listitem>
|
|
||||||
<listitem><para>Check the boxes next to the software you need to
|
|
||||||
install and then complete the installation.
|
|
||||||
For information on the specific software packages you need to include,
|
|
||||||
see the previous list.</para></listitem>
|
|
||||||
</orderedlist>
|
|
||||||
</para>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section id='configuring-the-plug-in'>
|
|
||||||
<title>Configuring the Plug-in</title>
|
|
||||||
<para>
|
|
||||||
Configuring the Eclipse Yocto Plug-in involves choosing the Cross
|
|
||||||
Compiler Options, selecting the Target Architecture, and choosing
|
|
||||||
the Target Options.
|
|
||||||
These settings are the default settings for all projects.
|
|
||||||
You do have opportunities to change them later if you choose to when
|
|
||||||
you configure the project.
|
|
||||||
See “Configuring the Cross Toolchain” section later in the manual.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
To start, you need to do the following from within the Eclipse IDE:
|
|
||||||
<itemizedlist>
|
|
||||||
<listitem><para>Choose Windows -> Preferences to display
|
|
||||||
the Preferences Dialog</para></listitem>
|
|
||||||
<listitem><para>Click “Yocto SDK”</para></listitem>
|
|
||||||
</itemizedlist>
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<section id='configuring-the-cross-compiler-options'>
|
|
||||||
<title>Configuring the Cross-Compiler Options</title>
|
|
||||||
<para>
|
|
||||||
Choose between ‘SDK Root Mode’ and ‘Poky Tree Mode’ for Cross
|
|
||||||
Compiler Options.
|
|
||||||
<itemizedlist>
|
|
||||||
<listitem><para><emphasis>SDK Root Mode</emphasis> – Select this mode
|
|
||||||
when you are not concerned with building an image or you do not have
|
|
||||||
a Poky build tree on your system.
|
|
||||||
For example, suppose you are an application developer and do not
|
|
||||||
need to build an image.
|
|
||||||
You just want to use an architecture-specific toolchain on an
|
|
||||||
existing kernel and root filesystem.
|
|
||||||
When you use SDK Root Mode you are using the toolchain installed
|
|
||||||
in the <filename>/opt/poky</filename> directory.</para></listitem>
|
|
||||||
<listitem><para><emphasis>Poky Tree Mode</emphasis> – Select this mode
|
|
||||||
if you are concerned with building images for hardware or your
|
|
||||||
development environment already has a build tree.
|
|
||||||
In this case you likely already have a Poky build tree installed on
|
|
||||||
your system or you (or someone else) will be building one.
|
|
||||||
When you use the Poky Tree Mode you are using the toolchain bundled
|
|
||||||
inside the Poky build tree.
|
|
||||||
If you use this mode you must also supply the Poky Root Location
|
|
||||||
in the Preferences Dialog.</para></listitem>
|
|
||||||
</itemizedlist>
|
|
||||||
</para>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section id='configuring-the-sysroot'>
|
|
||||||
<title>Configuring the Sysroot</title>
|
|
||||||
<para>
|
|
||||||
Specify the sysroot, which is used by both the QEMU user-space
|
|
||||||
NFS boot process and by the cross-toolchain regardless of the
|
|
||||||
mode you select (SDK Root Mode or Poky Tree Mode).
|
|
||||||
For example, sysroot is the location to which you extract the
|
|
||||||
downloaded image’s root filesystem to through the ADT Installer.
|
|
||||||
</para>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section id='selecting-the-target-architecture'>
|
|
||||||
<title>Selecting the Target Architecture</title>
|
|
||||||
<para>
|
|
||||||
Use the pull-down Target Architecture menu and select the
|
|
||||||
target architecture.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
The Target Architecture is the type of hardware you are
|
|
||||||
going to use or emulate.
|
|
||||||
This pull-down menu should have the supported architectures.
|
|
||||||
If the architecture you need is not listed in the menu then you
|
|
||||||
will need to re-visit
|
|
||||||
<xref linkend='adt-prepare'>
|
|
||||||
“Preparing to Use the Application Development Toolkit (ADT)”</xref>
|
|
||||||
section earlier in this document.
|
|
||||||
</para>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section id='choosing-the-target-options'>
|
|
||||||
<title>Choosing the Target Options</title>
|
|
||||||
<para>
|
|
||||||
You can choose to emulate hardware using the QEMU emulator, or you
|
|
||||||
can choose to use actual hardware.
|
|
||||||
<itemizedlist>
|
|
||||||
<listitem><para><emphasis>External HW</emphasis> – Select this option
|
|
||||||
if you will be using actual hardware.</para></listitem>
|
|
||||||
<listitem><para><emphasis>QEMU</emphasis> – Select this option if
|
|
||||||
you will be using the QEMU emulator.
|
|
||||||
If you are using the emulator you also need to locate the Kernel
|
|
||||||
and you can specify custom options.</para>
|
|
||||||
<para>In Poky Tree Mode the kernel you built will be located in the
|
|
||||||
Poky Build tree in <filename>tmp/deploy/images</filename> directory.
|
|
||||||
In SDK Root Mode the pre-built kernel you downloaded is located
|
|
||||||
in the directory you specified when you downloaded the image.</para>
|
|
||||||
<para>Most custom options are for advanced QEMU users to further
|
|
||||||
customize their QEMU instance.
|
|
||||||
These options are specified between paired angled brackets.
|
|
||||||
Some options must be specified outside the brackets.
|
|
||||||
In particular, the options <filename>serial</filename>,
|
|
||||||
<filename>nographic</filename>, and <filename>kvm</filename> must all
|
|
||||||
be outside the brackets.
|
|
||||||
Use the <filename>man qemu</filename> command to get help on all the options
|
|
||||||
and their use.
|
|
||||||
The following is an example:
|
|
||||||
<literallayout class='monospaced'>
|
|
||||||
serial ‘<-m 256 -full-screen>’
|
|
||||||
</literallayout>
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
Regardless of the mode, Sysroot is already defined in the “Sysroot”
|
|
||||||
field.</para></listitem>
|
|
||||||
</itemizedlist>
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
Click the “OK” button to save your plug-in configurations.
|
|
||||||
</para>
|
|
||||||
</section>
|
|
||||||
</section>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section id='creating-the-project'>
|
|
||||||
<title>Creating the Project</title>
|
|
||||||
<para>
|
|
||||||
You can create two types of projects: Autotools-based, or Makefile-based.
|
|
||||||
This section describes how to create autotools-based projects from within
|
|
||||||
the Eclipse IDE.
|
|
||||||
For information on creating projects in a terminal window see
|
|
||||||
<xref linkend='using-the-command-line'> “Using the Command Line”</xref>
|
|
||||||
section.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
To create a project based on a Yocto template and then display the source code,
|
|
||||||
follow these steps:
|
|
||||||
<orderedlist>
|
|
||||||
<listitem><para>Select File -> New -> Project.</para></listitem>
|
|
||||||
<listitem><para>Double click “CC++”.</para></listitem>
|
|
||||||
<listitem><para>Double click “C Project” to create the project.</para></listitem>
|
|
||||||
<listitem><para>Double click “Yocto SDK Project”.</para></listitem>
|
|
||||||
<listitem><para>Select “Hello World ANSI C Autotools Project”.
|
|
||||||
This is an Autotools-based project based on a Yocto Project template.</para></listitem>
|
|
||||||
<listitem><para>Put a name in the “Project name:” field.</para></listitem>
|
|
||||||
<listitem><para>Click “Next”.</para></listitem>
|
|
||||||
<listitem><para>Add information in the “Author” field.</para></listitem>
|
|
||||||
<listitem><para>Use “GNU General Public License v2.0” for the License.</para></listitem>
|
|
||||||
<listitem><para>Click “Finish”.</para></listitem>
|
|
||||||
<listitem><para>Answer ‘Yes” to the open perspective prompt.</para></listitem>
|
|
||||||
<listitem><para>In the Project Explorer expand your project.</para></listitem>
|
|
||||||
<listitem><para>Expand ‘src’.</para></listitem>
|
|
||||||
<listitem><para>Double click on your source file and the code appears
|
|
||||||
in the window.
|
|
||||||
This is the template.</para></listitem>
|
|
||||||
</orderedlist>
|
|
||||||
</para>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section id='configuring-the-cross-toolchains'>
|
|
||||||
<title>Configuring the Cross-Toolchains</title>
|
|
||||||
<para>
|
|
||||||
The previous section, <xref linkend='configuring-the-cross-compiler-options'>
|
|
||||||
“Configuring the Cross-Compiler Options”</xref>, set up the default project
|
|
||||||
configurations.
|
|
||||||
You can change these settings for a given project by following these steps:
|
|
||||||
<orderedlist>
|
|
||||||
<listitem><para>Select Project -> Invoke Yocto Tools -> Reconfigure Yocto.
|
|
||||||
This brings up the project Yocto Settings Dialog.
|
|
||||||
Settings are inherited from the default project configuration.
|
|
||||||
The information in this dialogue is identical to that chosen earlier
|
|
||||||
for the Cross Compiler Option (SDK Root Mode or Poky Tree Mode),
|
|
||||||
the Target Architecture, and the Target Options.
|
|
||||||
The settings are inherited from the Yocto Plug-in configuration performed
|
|
||||||
after installing the plug-in.</para></listitem>
|
|
||||||
<listitem><para>Select Project -> Reconfigure Project.
|
|
||||||
This runs the <filename>autogen.sh</filename> in the workspace for your project.
|
|
||||||
The script runs <filename>libtoolize</filename>, <filename>aclocal</filename>,
|
|
||||||
<filename>autoconf</filename>, <filename>autoheader</filename>,
|
|
||||||
<filename>automake ‐‐a</filename>, and
|
|
||||||
<filename>./configure</filename>.</para></listitem>
|
|
||||||
</orderedlist>
|
|
||||||
</para>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section id='building-the-project'>
|
|
||||||
<title>Building the Project</title>
|
|
||||||
<para>
|
|
||||||
To build the project, select Project -> Build Project.
|
|
||||||
You should see the console updated and you can note the cross-compiler you are using.
|
|
||||||
</para>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section id='starting-qemu-in-user-space-nfs-mode'>
|
|
||||||
<title>Starting QEMU in User Space NFS Mode</title>
|
|
||||||
<para>
|
|
||||||
To start the QEMU emulator from within Eclipse, follow these steps:
|
|
||||||
<orderedlist>
|
|
||||||
<listitem><para>Select Run -> External Tools -> External Tools Configurations...
|
|
||||||
This selection brings up the External Tools Configurations Dialogue.</para></listitem>
|
|
||||||
<listitem><para>Go to the left navigation area and expand ‘Program’.
|
|
||||||
You should find the image listed.
|
|
||||||
For example, qemu-x86_64-poky-linux.</para></listitem>
|
|
||||||
<listitem><para>Click on the image.
|
|
||||||
This brings up a new environment in the main area of the External
|
|
||||||
Tools Configurations Dialogue.
|
|
||||||
The Main tab is selected.</para></listitem>
|
|
||||||
<listitem><para>Click “Run” next.
|
|
||||||
This brings up a shell window.</para></listitem>
|
|
||||||
<listitem><para>Enter your host root password in the shell window at the prompt.
|
|
||||||
This sets up a Tap 0 connection needed for running in user-space NFS mode.</para></listitem>
|
|
||||||
<listitem><para>Wait for QEMU to launch.</para></listitem>
|
|
||||||
<listitem><para>Once QEMU launches you need to determine the IP Address
|
|
||||||
for the user-space NFS.
|
|
||||||
You can do that by going to a terminal in the QEMU and entering the
|
|
||||||
<filename>ipconfig</filename> command.</para></listitem>
|
|
||||||
</orderedlist>
|
|
||||||
</para>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section id='deploying-and-debugging-the-application'>
|
|
||||||
<title>Deploying and Debugging the Application</title>
|
|
||||||
<para>
|
|
||||||
Once QEMU is running you can deploy your application and use the emulator
|
|
||||||
to perform debugging.
|
|
||||||
Follow these steps to deploy the application.
|
|
||||||
<orderedlist>
|
|
||||||
<listitem><para>Select Run -> Debug Configurations...</para></listitem>
|
|
||||||
<listitem><para>In the left area expand “C/C++Remote Application”.</para></listitem>
|
|
||||||
<listitem><para>Locate your project and select it to bring up a new
|
|
||||||
tabbed view in the Debug Configurations dialogue.</para></listitem>
|
|
||||||
<listitem><para>Enter the absolute path into which you want to deploy
|
|
||||||
the application.
|
|
||||||
Use the Remote Absolute File Path for C/C++Application:.
|
|
||||||
For example, enter <filename>/usr/bin/<programname></filename>.</para></listitem>
|
|
||||||
<listitem><para>Click on the Debugger tab to see the cross-tool debugger
|
|
||||||
you are using.</para></listitem>
|
|
||||||
<listitem><para>Create a new connection to the QEMU instance
|
|
||||||
by clicking on “new”.</para></listitem>
|
|
||||||
<listitem><para>Select “TCF, which means Target Communication Framework.</para></listitem>
|
|
||||||
<listitem><para>Click “Next”.</para></listitem>
|
|
||||||
<listitem><para>Clear out the “host name” field and enter the IP Address
|
|
||||||
determined earlier.</para></listitem>
|
|
||||||
<listitem><para>Click Finish to close the new connections dialogue.</para></listitem>
|
|
||||||
<listitem><para>Use the drop-down menu now in the “Connection” field and pick
|
|
||||||
the IP Address you entered.</para></listitem>
|
|
||||||
<listitem><para>Click “Debug” to bring up a login screen and login.</para></listitem>
|
|
||||||
<listitem><para>Accept the debug perspective.</para></listitem>
|
|
||||||
</orderedlist>
|
|
||||||
</para>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section id='running-user-space-tools'>
|
|
||||||
<title>Running User-Space Tools</title>
|
|
||||||
<para>
|
|
||||||
As mentioned earlier in the manual several tools exist that enhance
|
|
||||||
your development experience.
|
|
||||||
These tools are aids in developing and debugging applications and images.
|
|
||||||
You can run these user-space tools from within the Yocto Eclipse
|
|
||||||
Plug-in through the Window -> YoctoTools menu.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
Once you pick a tool you need to configure it for the remote target.
|
|
||||||
Every tool needs to have the connection configured.
|
|
||||||
You must select an existing TCF-based RSE connection to the remote target.
|
|
||||||
If one does not exist, click "New" to create one.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
Here are some specifics about the remote tools:
|
|
||||||
<itemizedlist>
|
|
||||||
<listitem><para><emphasis>OProfile:</emphasis> Selecting this tool causes
|
|
||||||
the oprofile-server on the remote target to launch on the local host machine.
|
|
||||||
The oprofile-viewer must be installed on the local host machine and the
|
|
||||||
oprofile-server must be installed on the remote target, respectively, in order
|
|
||||||
to use.
|
|
||||||
You can locate both the viewer and server from
|
|
||||||
<ulink url='http://git.pokylinux.org/cgit/cgit.cgi/oprofileui/'></ulink>.
|
|
||||||
You need to compile and install the oprofile-viewer from the source code
|
|
||||||
on your local host machine.
|
|
||||||
The oprofile-server is installed by default in the image.</para></listitem>
|
|
||||||
<listitem><para><emphasis>Lttng-ust:</emphasis> Selecting this tool runs
|
|
||||||
"usttrace" on the remote target, transfers the output data back to the
|
|
||||||
local host machine and uses "lttv-gui" to graphically display the output.
|
|
||||||
The "lttv-gui" must be installed on the local host machine to use this tool.
|
|
||||||
For information on how to use "lttng" to trace an application, see
|
|
||||||
<ulink url='http://lttng.org/files/ust/manual/ust.html'></ulink>.</para>
|
|
||||||
<para>For "Application" you must supply the absolute path name of the
|
|
||||||
application to be traced by user mode lttng.
|
|
||||||
For example, typing <filename>/path/to/foo</filename> triggers
|
|
||||||
<filename>usttrace /path/to/foo</filename> on the remote target to trace the
|
|
||||||
program <filename>/path/to/foo</filename>.</para>
|
|
||||||
<para>"Argument" is passed to <filename>usttrace</filename>
|
|
||||||
running on the remote target.</para></listitem>
|
|
||||||
<listitem><para><emphasis>PowerTOP:</emphasis> Selecting this tool runs
|
|
||||||
"PowerTOP" on the remote target machine and displays the results in a
|
|
||||||
new view called "powertop".</para>
|
|
||||||
<para>"Time to gather data(sec):" is the time passed in seconds before data
|
|
||||||
is gathered from the remote target for analysis.</para>
|
|
||||||
<para>"show pids in wakeups list:" corresponds to the -p argument
|
|
||||||
passed to "powertop".</para></listitem>
|
|
||||||
<listitem><para><emphasis>LatencyTOP and Perf:</emphasis> "LatencyTOP"
|
|
||||||
identifies system latency, while "perf" monitors the system's
|
|
||||||
performance counter registers.
|
|
||||||
Selecting either of these tools causes an RSE terminal view to appear
|
|
||||||
from which you can run the tools.
|
|
||||||
Both tools refresh the entire screen to display results while they run.</para></listitem>
|
|
||||||
</itemizedlist>
|
|
||||||
</para>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
</chapter>
|
|
||||||
<!--
|
|
||||||
vim: expandtab tw=80 ts=4
|
|
||||||
-->
|
|
||||||
@@ -1,117 +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='adt-intro'>
|
|
||||||
|
|
||||||
<title>Application Development Toolkit (ADT) User's Guide</title>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
Welcome to the Application Development Toolkit User’s Guide. This manual provides
|
|
||||||
information that lets you get going with the ADT to develop projects using the Yocto
|
|
||||||
Project.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<section id='book-intro'>
|
|
||||||
<title>Introducing the Application Development Toolkit (ADT)</title>
|
|
||||||
<para>
|
|
||||||
Fundamentally, the ADT consists of an architecture-specific cross-toolchain and
|
|
||||||
a matching sysroot that are both built by the Poky build system.
|
|
||||||
The toolchain and sysroot are based on a metadata configuration and extensions,
|
|
||||||
which allows you to cross develop for the target on the host machine.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
Additionally, to provide an effective development platform, the Yocto Project
|
|
||||||
makes available and suggests other tools as part of the ADT.
|
|
||||||
These other tools include the Eclipse IDE Yocto Plug-in, an emulator (QEMU),
|
|
||||||
and various user-space tools that greatly enhance your development experience.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
The resulting combination of the architecture-specific cross-toolchain and sysroot
|
|
||||||
along with these additional tools yields a custom-built, cross-development platform
|
|
||||||
for a user-targeted product.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<section id='the-cross-toolchain'>
|
|
||||||
<title>The Cross-Toolchain</title>
|
|
||||||
<para>
|
|
||||||
The cross-toolchain consists of a cross-compiler, cross-linker, and cross-debugger
|
|
||||||
that are all generated through a Poky build that is based on your metadata
|
|
||||||
configuration or extension for your targeted device.
|
|
||||||
The cross-toolchain works with a matching target sysroot.
|
|
||||||
</para>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section id='sysroot'>
|
|
||||||
<title>Sysroot</title>
|
|
||||||
<para>
|
|
||||||
The matching target sysroot contains needed headers and libraries for generating
|
|
||||||
binaries that run on the target architecture.
|
|
||||||
The sysroot is based on the target root filesystem image that is built by
|
|
||||||
Poky and uses the same metadata configuration used to build the cross-toolchain.
|
|
||||||
</para>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section id='the-qemu-emulator'>
|
|
||||||
<title>The QEMU Emulator</title>
|
|
||||||
<para>
|
|
||||||
The QEMU emulator allows you to simulate your hardware while running your
|
|
||||||
application or image.
|
|
||||||
QEMU is installed several ways: as part of the Poky tree, ADT installation
|
|
||||||
through a toolchain tarball, or through the ADT Installer.
|
|
||||||
</para>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section id='user-space-tools'>
|
|
||||||
<title>User-Space Tools</title>
|
|
||||||
<para>
|
|
||||||
User-space tools are included as part of the distribution.
|
|
||||||
You will find these tools helpful during development.
|
|
||||||
The tools include LatencyTOP, PowerTOP, OProfile, Perf, SystemTap, and Lttng-ust.
|
|
||||||
These tools are common development tools for the Linux platform.
|
|
||||||
<itemizedlist>
|
|
||||||
<listitem><para><emphasis>LatencyTOP</emphasis> – LatencyTOP focuses on latency
|
|
||||||
that causes skips in audio,
|
|
||||||
stutters in your desktop experience, or situations that overload your server
|
|
||||||
even when you have plenty of CPU power left.
|
|
||||||
You can find out more about LatencyTOP at
|
|
||||||
<ulink url='http://www.latencytop.org/'></ulink>.
|
|
||||||
</para></listitem>
|
|
||||||
<listitem><para><emphasis>PowerTOP</emphasis> – Helps you determine what
|
|
||||||
software is using the most power.
|
|
||||||
You can find out more about PowerTOP at
|
|
||||||
<ulink url='http://www.linuxpowertop.org/'></ulink>.
|
|
||||||
</para></listitem>
|
|
||||||
<listitem><para><emphasis>OProfile</emphasis> – A system-wide profiler for Linux
|
|
||||||
systems that is capable
|
|
||||||
of profiling all running code at low overhead.
|
|
||||||
You can find out more about OProfile at
|
|
||||||
<ulink url='http://oprofile.sourceforge.net/about/'></ulink>.
|
|
||||||
</para></listitem>
|
|
||||||
<listitem><para><emphasis>Perf</emphasis> – Performance counters for Linux used
|
|
||||||
to keep track of certain
|
|
||||||
types of hardware and software events.
|
|
||||||
For more information on these types of counters see
|
|
||||||
<ulink url='https://perf.wiki.kernel.org/index.php'></ulink> and click
|
|
||||||
on “Perf tools.”
|
|
||||||
</para></listitem>
|
|
||||||
<listitem><para><emphasis>SystemTap</emphasis> – A free software infrastructure
|
|
||||||
that simplifies
|
|
||||||
information gathering about a running Linux system.
|
|
||||||
This information helps you diagnose performance or functional problems.
|
|
||||||
SystemTap is not available as a user-space tool through the Yocto Eclipse IDE Plug-in.
|
|
||||||
See <ulink url='http://sourceware.org/systemtap'></ulink> for more information
|
|
||||||
on SystemTap.
|
|
||||||
</para></listitem>
|
|
||||||
<listitem><para><emphasis>Lttng-ust</emphasis> – A User-space Tracer designed to
|
|
||||||
provide detailed information on user-space activity.
|
|
||||||
See <ulink url='http://lttng.org/ust'></ulink> for more information on Lttng-ust.
|
|
||||||
</para></listitem>
|
|
||||||
</itemizedlist>
|
|
||||||
</para>
|
|
||||||
</section>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
</chapter>
|
|
||||||
<!--
|
|
||||||
vim: expandtab tw=80 ts=4
|
|
||||||
-->
|
|
||||||
@@ -1,8 +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="generate.toc" select="'article nop'"></xsl:param> -->
|
|
||||||
|
|
||||||
</xsl:stylesheet>
|
|
||||||
@@ -1,70 +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='adt-manual' lang='en'
|
|
||||||
xmlns:xi="http://www.w3.org/2003/XInclude"
|
|
||||||
xmlns="http://docbook.org/ns/docbook"
|
|
||||||
>
|
|
||||||
<bookinfo>
|
|
||||||
|
|
||||||
<mediaobject>
|
|
||||||
<imageobject>
|
|
||||||
<imagedata fileref='figures/adt-title.png'
|
|
||||||
format='SVG'
|
|
||||||
align='left' scalefit='1' width='100%'/>
|
|
||||||
</imageobject>
|
|
||||||
</mediaobject>
|
|
||||||
|
|
||||||
<title></title>
|
|
||||||
|
|
||||||
<authorgroup>
|
|
||||||
<author>
|
|
||||||
<firstname>Jessica</firstname> <surname>Zhang</surname>
|
|
||||||
<affiliation>
|
|
||||||
<orgname>Intel Corporation</orgname>
|
|
||||||
</affiliation>
|
|
||||||
<email>jessica.zhang@intel.com</email>
|
|
||||||
</author>
|
|
||||||
</authorgroup>
|
|
||||||
|
|
||||||
<revhistory>
|
|
||||||
<revision>
|
|
||||||
<revnumber>1.0</revnumber>
|
|
||||||
<date>6 April 2011</date>
|
|
||||||
<revremark>Initial Document released with Yocto Project 1.0 on 6 April 2011.</revremark>
|
|
||||||
</revision>
|
|
||||||
</revhistory>
|
|
||||||
|
|
||||||
<copyright>
|
|
||||||
<year>2010-2011</year>
|
|
||||||
<holder>Linux Foundation</holder>
|
|
||||||
</copyright>
|
|
||||||
|
|
||||||
<legalnotice>
|
|
||||||
<para>
|
|
||||||
Permission is granted to copy, distribute and/or modify this document under
|
|
||||||
the terms of the <ulink type="http" url="http://creativecommons.org/licenses/by-sa/2.0/uk/">Creative Commons Attribution-Share Alike 2.0 UK: England & Wales</ulink> as published by Creative Commons.
|
|
||||||
</para>
|
|
||||||
</legalnotice>
|
|
||||||
|
|
||||||
</bookinfo>
|
|
||||||
|
|
||||||
<xi:include href="adt-intro.xml"/>
|
|
||||||
|
|
||||||
<xi:include href="adt-prepare.xml"/>
|
|
||||||
|
|
||||||
<xi:include href="adt-package.xml"/>
|
|
||||||
|
|
||||||
<xi:include href="adt-eclipse.xml"/>
|
|
||||||
|
|
||||||
<xi:include href="adt-command.xml"/>
|
|
||||||
|
|
||||||
<!-- <index id='index'>
|
|
||||||
<title>Index</title>
|
|
||||||
</index>
|
|
||||||
-->
|
|
||||||
|
|
||||||
</book>
|
|
||||||
<!--
|
|
||||||
vim: expandtab tw=80 ts=4
|
|
||||||
-->
|
|
||||||
@@ -1,82 +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='adt-package'>
|
|
||||||
<title>Optionally Customizing the Development Packages Installation</title>
|
|
||||||
<para>
|
|
||||||
Because the Yocto Project is suited for embedded Linux development it is
|
|
||||||
likely that you will need to customize your development packages installation.
|
|
||||||
For example, if you are developing a minimal image then you might not need
|
|
||||||
certain packages (e.g. graphics support packages).
|
|
||||||
Thus, you would like to be able to remove those packages from your sysroot.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<section id='package-management-systems'>
|
|
||||||
<title>Package Management Systems</title>
|
|
||||||
<para>
|
|
||||||
The Yocto Project supports the generation of root filesystem files using
|
|
||||||
three different Package Management Systems (PMS):
|
|
||||||
<itemizedlist>
|
|
||||||
<listitem><para><emphasis>OPKG</emphasis> – A less well known PMS whose use
|
|
||||||
originated in the OpenEmbedded and OpenWrt embedded Linux projects.
|
|
||||||
This PMS works with files packaged in an <filename>.ipk</filename> format.
|
|
||||||
See <ulink url='http://en.wikipedia.org/wiki/Opkg'></ulink> for more
|
|
||||||
information about OPKG.</para></listitem>
|
|
||||||
<listitem><para><emphasis>RPM</emphasis> – A more widely known PMS intended for GNU/Linux
|
|
||||||
distributions.
|
|
||||||
This PMS works with files packaged in an <filename>.rms</filename> format.
|
|
||||||
The Yocto Project currently installs through this PMS by default.
|
|
||||||
See <ulink url='http://en.wikipedia.org/wiki/RPM_Package_Manager'></ulink>
|
|
||||||
for more information about RPM.</para></listitem>
|
|
||||||
<listitem><para><emphasis>Debian</emphasis> – The PMS for Debian-based systems
|
|
||||||
is built on many PMS tools.
|
|
||||||
The lower-level PMS tool dpkg forms the base of the Debian PMS.
|
|
||||||
For information on dpkg see
|
|
||||||
<ulink url='http://en.wikipedia.org/wiki/Dpkg'></ulink>.</para></listitem>
|
|
||||||
</itemizedlist>
|
|
||||||
</para>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section id='configuring-the-pms'>
|
|
||||||
<title>Configuring the PMS</title>
|
|
||||||
<para>
|
|
||||||
Whichever PMS you are using you need to be sure that the
|
|
||||||
<filename>PACKAGE_CLASSES</filename> variable in the <filename>conf/local.conf</filename>
|
|
||||||
file is set to reflect that system.
|
|
||||||
The first value you choose for the variable specifies the package file format for the root
|
|
||||||
filesystem.
|
|
||||||
Additional values specify additional formats for convenience or testing.
|
|
||||||
See the configuration file for details.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
As an example, consider a scenario where you are using OPKG and you want to add
|
|
||||||
the libglade package to sysroot.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
First, you should generate the ipk file for the libglade package and add it
|
|
||||||
into a working opkg repository.
|
|
||||||
Use these commands:
|
|
||||||
<literallayout class='monospaced'>
|
|
||||||
$ bitbake libglade
|
|
||||||
$ bitbake package-index
|
|
||||||
</literallayout>
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
Next, source the environment setup script.
|
|
||||||
Follow that by setting up the installation destination to point to your
|
|
||||||
sysroot as <filename><sysroot dir></filename>.
|
|
||||||
Finally, have an opkg configuration file <filename><conf file></filename>
|
|
||||||
that corresponds to the opkg repository you have just created.
|
|
||||||
The following command forms should now work:
|
|
||||||
<literallayout class='monospaced'>
|
|
||||||
$ opkg-cl –f <conf file> -o <sysroot dir> update
|
|
||||||
$ opkg-cl –f <conf file>> -o <sysroot dir> --force-overwrite install libglade
|
|
||||||
$ opkg-cl –f <conf file> -o <sysroot dir> --force-overwrite install libglade-dbg
|
|
||||||
$ opkg-cl –f <conf file> -o <sysroot dir> --force-overwrite install libglade-dev
|
|
||||||
</literallayout>
|
|
||||||
</para>
|
|
||||||
</section>
|
|
||||||
</chapter>
|
|
||||||
<!--
|
|
||||||
vim: expandtab tw=80 ts=4
|
|
||||||
-->
|
|
||||||
@@ -1,244 +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='adt-prepare'>
|
|
||||||
|
|
||||||
<title>Preparing to Use the Application Development Toolkit (ADT)</title>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
In order to use the ADT it must be installed, the environment setup script must be
|
|
||||||
sourced, and the kernel and filesystem image specific to the target architecture must exist.
|
|
||||||
This section describes how to install the ADT, set up the environment, and provides
|
|
||||||
some reference information on kernels and filesystem images.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<section id='installing-the-adt'>
|
|
||||||
<title>Installing the ADT</title>
|
|
||||||
<para>
|
|
||||||
You can install the ADT three ways.
|
|
||||||
However, we recommend configuring and running the ADT Installer script.
|
|
||||||
Running this script automates much of the process for you.
|
|
||||||
For example, the script allows you to install the QEMU emulator and
|
|
||||||
user-space NFS, define which root filesystem profiles to download,
|
|
||||||
and allows you to define the target sysroot location.
|
|
||||||
</para>
|
|
||||||
<note>
|
|
||||||
If you need to generate the ADT tarball you can do so using the following command:
|
|
||||||
<literallayout class='monospaced'>
|
|
||||||
$ bitbake adt-installer
|
|
||||||
</literallayout>
|
|
||||||
This command generates the file <filename>adt-installer.tar.bz2</filename>
|
|
||||||
in the <filename>../build/tmp/deploy/sdk</filename> directory.
|
|
||||||
</note>
|
|
||||||
|
|
||||||
<section id='configuring-and-running-the-adt-installer'>
|
|
||||||
<title>Configuring and Running the ADT Installer</title>
|
|
||||||
<para>
|
|
||||||
The ADT Installer is contained in a tarball that can be built using
|
|
||||||
<filename>bitbake adt-installer</filename>.
|
|
||||||
Yocto Project has a pre-built ADT Installer tarball that you can download
|
|
||||||
from <filename>tmp/deploy/sdk</filename> located in the build directory.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<note>
|
|
||||||
You can install and run the ADT Installer tarball in any directory you want.
|
|
||||||
</note>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
Before running the ADT Installer you need to configure it by editing
|
|
||||||
the <filename>adt-installer.conf</filename> file, which is located in the
|
|
||||||
directory where the ADT Installer tarball was installed.
|
|
||||||
Your configurations determine which kernel and filesystem image are downloaded.
|
|
||||||
The following list describes the variables you can define for the ADT Installer.
|
|
||||||
For configuration values and restrictions see the comments in
|
|
||||||
the <filename>adt-installer.conf</filename> file:
|
|
||||||
|
|
||||||
<itemizedlist>
|
|
||||||
<listitem><para><filename>YOCTOADT_IPKG_REPO</filename> – This area
|
|
||||||
includes the IPKG-based packages and the root filesystem upon which
|
|
||||||
the installation is based.
|
|
||||||
If you want to set up your own IPKG repository pointed to by
|
|
||||||
<filename>YOCTOADT_IPKG_REPO</filename>, you need to be sure that the
|
|
||||||
directory structure follows the same layout as the reference directory
|
|
||||||
set up at <ulink url='http://adtrepo.yoctoproject.org'></ulink>.
|
|
||||||
Also, your repository needs to be accessible through HTTP.
|
|
||||||
</para></listitem>
|
|
||||||
<listitem><para><filename>YOCTOADT-TARGETS</filename> – The machine
|
|
||||||
target architectures for which you want to set up cross-development
|
|
||||||
environments.
|
|
||||||
</para></listitem>
|
|
||||||
<listitem><para><filename>YOCTOADT_QEMU</filename> – Indicates whether
|
|
||||||
or not to install the emulator QEMU.
|
|
||||||
</para></listitem>
|
|
||||||
<listitem><para><filename>YOCTOADT_NFS_UTIL</filename> – Indicates whether
|
|
||||||
or not to install user-mode NFS.
|
|
||||||
If you plan to use the Yocto Eclipse IDE plug-in against QEMU,
|
|
||||||
you should install NFS.
|
|
||||||
<note>
|
|
||||||
To boot QEMU images using our userspace NFS server, you need
|
|
||||||
to be running portmap or rpcbind.
|
|
||||||
If you are running rpcbind, you will also need to add the -i
|
|
||||||
option when rpcbind starts up.
|
|
||||||
Please make sure you understand the security implications of doing this.
|
|
||||||
Your firewall settings may also have to be modified to allow
|
|
||||||
NFS booting to work.
|
|
||||||
</note>
|
|
||||||
</para></listitem>
|
|
||||||
<listitem><para><filename>YOCTOADT_ROOTFS_<arch></filename> - The root
|
|
||||||
filesystem images you want to download.
|
|
||||||
</para></listitem>
|
|
||||||
<listitem><para><filename>YOCTOADT_TARGET_SYSROOT_IMAGE_<arch></filename> - The
|
|
||||||
root filesystem used to extract and create the target sysroot.
|
|
||||||
</para></listitem>
|
|
||||||
<listitem><para><filename>YOCTOADT_TARGET_SYSROOT_LOC_<arch></filename> - The
|
|
||||||
location of the target sysroot that will be set up on the development machine.
|
|
||||||
</para></listitem>
|
|
||||||
</itemizedlist>
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
After you have configured the <filename>adt-installer.conf</filename> file,
|
|
||||||
run the installer using the following command:
|
|
||||||
<literallayout class='monospaced'>
|
|
||||||
$ adt_installer
|
|
||||||
</literallayout>
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
Once the installer begins to run you are asked whether you want to run in
|
|
||||||
interactive or silent mode.
|
|
||||||
If you want to closely monitor the installation then choose “I” for interactive
|
|
||||||
mode rather than “S” for silent mode.
|
|
||||||
Follow the prompts from the script to complete the installation.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
Once the installation completes, the cross-toolchain is installed in
|
|
||||||
<filename>/opt/poky/$SDKVERSION</filename>.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
Before using the ADT you need to run the environment setup script for
|
|
||||||
your target architecture also located in <filename>/opt/poky/$SDKVERSION</filename>.
|
|
||||||
See the <xref linkend='setting-up-the-environment'>“Setting Up the Environment”</xref>
|
|
||||||
section for information.
|
|
||||||
</para>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section id='using-an-existing-toolchain-tarball'>
|
|
||||||
<title>Using an Existing Toolchain Tarball</title>
|
|
||||||
<para>
|
|
||||||
If you do not want to use the ADT Installer you can install the toolchain
|
|
||||||
and the sysroot by hand.
|
|
||||||
Follow these steps:
|
|
||||||
<orderedlist>
|
|
||||||
<listitem><para>Locate and download the architecture-specific toolchain
|
|
||||||
tarball from <ulink url='http://autobuilder.yoctoproject.org/downloads/yocto-1.0'></ulink>.
|
|
||||||
Look in the ‘toolchain’ folder and then open up the folder that matches your
|
|
||||||
host development system (i.e. 'i686' for 32-bit machines or 'x86_64'
|
|
||||||
for 64-bit machines).
|
|
||||||
Then, select the toolchain tarball whose name includes the appropriate
|
|
||||||
target architecture.
|
|
||||||
<note>
|
|
||||||
If you need to build the toolchain tarball use the
|
|
||||||
<filename>bitbake meta-toolchain</filename> command after you have
|
|
||||||
sourced the poky-build-init script.
|
|
||||||
The tarball will be located in the build directory at
|
|
||||||
<filename>tmp/deploy/sdk</filename> after the build.
|
|
||||||
</note>
|
|
||||||
</para></listitem>
|
|
||||||
<listitem><para>Make sure you are in the root directory and then expand
|
|
||||||
the tarball.
|
|
||||||
The tarball expands into the <filename>/opt/poky/$SDKVERSION</filename> directory.
|
|
||||||
</para></listitem>
|
|
||||||
<listitem><para>Set up the environment by sourcing the environment set up
|
|
||||||
script.
|
|
||||||
See the <xref linkend='setting-up-the-environment'>“Setting Up the Environment”</xref>
|
|
||||||
for information.
|
|
||||||
</para></listitem>
|
|
||||||
</orderedlist>
|
|
||||||
</para>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section id='using-the-toolchain-from-within-the-build-tree'>
|
|
||||||
<title>Using the Toolchain from Within the Build Tree</title>
|
|
||||||
<para>
|
|
||||||
A final way of accessing the toolchain is from the build tree.
|
|
||||||
The build tree can be set up to contain the architecture-specific cross toolchain.
|
|
||||||
To populate the build tree with the toolchain you need to run the following command:
|
|
||||||
<literallayout class='monospaced'>
|
|
||||||
$ bitbake meta-ide-support
|
|
||||||
</literallayout>
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
Before running the command you need to be sure that the
|
|
||||||
<filename>conf/local.conf</filename> file in the build directory has
|
|
||||||
the desired architecture specified for the <filename>MACHINE</filename>
|
|
||||||
variable.
|
|
||||||
See the <filename>local.conf</filename> file for a list of values you
|
|
||||||
can supply for this variable.
|
|
||||||
You can populate the build tree with the cross-toolchains for more
|
|
||||||
than a single architecture.
|
|
||||||
You just need to edit the <filename>local.conf</filename> file and re-run
|
|
||||||
the BitBake command.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
Once the build tree has the toolchain you need to source the environment
|
|
||||||
setup script so that you can run the cross-tools without having to locate them.
|
|
||||||
See the <xref linkend='setting-up-the-environment'>“Setting Up the Environment”</xref>
|
|
||||||
for information.
|
|
||||||
</para>
|
|
||||||
</section>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section id='setting-up-the-environment'>
|
|
||||||
<title>Setting Up the Environment</title>
|
|
||||||
<para>
|
|
||||||
Before you can use the cross-toolchain you need to set up the environment by
|
|
||||||
sourcing the environment setup script.
|
|
||||||
If you used adt_installer or used an existing ADT tarball to install the ADT,
|
|
||||||
then you can find this script in the <filename>/opt/poky/$SDKVERSION</filename>
|
|
||||||
directory.
|
|
||||||
If you are using the ADT from a Poky build tree, then look in the build
|
|
||||||
directory in <filename>tmp</filename> for the setup script.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
Be sure to run the environment setup script that matches the architecture for
|
|
||||||
which you are developing.
|
|
||||||
Environment setup scripts begin with the string “environment-setup” and include as
|
|
||||||
part of their name the architecture.
|
|
||||||
For example, the environment setup script for a 64-bit IA-based architecture would
|
|
||||||
be the following:
|
|
||||||
<literallayout class='monospaced'>
|
|
||||||
/opt/poky/environment-setup-x86_64-poky-linux
|
|
||||||
</literallayout>
|
|
||||||
</para>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section id='kernels-and-filesystem-images'>
|
|
||||||
<title>Kernels and Filesystem Images</title>
|
|
||||||
<para>
|
|
||||||
You will need to have a kernel and filesystem image to boot using your
|
|
||||||
hardware or the QEMU emulator.
|
|
||||||
That means you either have to build them or know where to get them.
|
|
||||||
You can find lots of details on how to get or build images and kernels for your
|
|
||||||
architecture in the "Yocto Project Quick Start" found at
|
|
||||||
<ulink url='http://www.yoctoproject.org/docs/yocto-quick-start/yocto-project-qs.html'></ulink>.
|
|
||||||
<note>
|
|
||||||
Yocto Project provides basic kernels and filesystem images for several
|
|
||||||
architectures (x86, x86-64, mips, powerpc, and arm) that can be used
|
|
||||||
unaltered in the QEMU emulator.
|
|
||||||
These kernels and filesystem images reside in the Yocto Project release
|
|
||||||
area - <ulink url='http://autobuilder.yoctoproject.org/downloads/yocto-0.9/'></ulink>
|
|
||||||
and are ideal for experimentation within Yocto Project.
|
|
||||||
</note>
|
|
||||||
</para>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
</chapter>
|
|
||||||
<!--
|
|
||||||
vim: expandtab tw=80 ts=4
|
|
||||||
-->
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 14 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 8.4 KiB |
@@ -1,968 +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;
|
|
||||||
}
|
|
||||||
|
|
||||||
.reviewer {
|
|
||||||
color: red;
|
|
||||||
}
|
|
||||||
|
|
||||||
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: 80%;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
.authorgroup {
|
|
||||||
background-color: transparent;
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
padding-top: 256px;
|
|
||||||
background-image: url("figures/adt-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: #aaa;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.tip table th,
|
|
||||||
.warning table th,
|
|
||||||
.caution table th,
|
|
||||||
.note table th {
|
|
||||||
border-bottom-color: #aaa;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.warning {
|
|
||||||
background-color: #fea;
|
|
||||||
}
|
|
||||||
|
|
||||||
.caution {
|
|
||||||
background-color: #fea;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tip {
|
|
||||||
background-color: #eff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.note {
|
|
||||||
background-color: #dfc;
|
|
||||||
}
|
|
||||||
|
|
||||||
.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: #666666;
|
|
||||||
color: #fff;
|
|
||||||
padding: 20px;
|
|
||||||
margin: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tip h3,
|
|
||||||
.note h3 {
|
|
||||||
padding: 0em;
|
|
||||||
margin: 0em;
|
|
||||||
font-size: 2em;
|
|
||||||
font-weight: bold;
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tip a,
|
|
||||||
.note a {
|
|
||||||
color: #fff;
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
XSLTOPTS = --stringparam html.stylesheet style.css \
|
|
||||||
--stringparam chapter.autolabel 1 \
|
|
||||||
--stringparam section.autolabel 1 \
|
|
||||||
--stringparam section.label.includes.component.label 1 \
|
|
||||||
--xinclude
|
|
||||||
|
|
||||||
##
|
|
||||||
# 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: html pdf tarball
|
|
||||||
|
|
||||||
pdf:
|
|
||||||
../tools/poky-docbook-to-pdf bsp-guide.xml ../template
|
|
||||||
|
|
||||||
html:
|
|
||||||
# See http://www.sagehill.net/docbookxsl/HtmlOutput.html
|
|
||||||
xsltproc $(XSLTOPTS) -o bsp-guide.html bsp-guide-customization.xsl bsp-guide.xml
|
|
||||||
|
|
||||||
tarball: html
|
|
||||||
tar -cvzf bsp-guide.tgz style.css bsp-guide.html figures/bsp-title.png
|
|
||||||
|
|
||||||
validate:
|
|
||||||
xmllint --postvalid --xinclude --noout bsp-guide.xml
|
|
||||||
|
|
||||||
OUTPUTS = bsp-guide.pdf bsp-guide.html
|
|
||||||
SOURCES = *.png *.xml *.css *.svg
|
|
||||||
|
|
||||||
publish:
|
|
||||||
scp -r $(OUTPUTS) $(SOURCES) o-hand.com:/srv/www/pokylinux.org/doc/
|
|
||||||
|
|
||||||
clean:
|
|
||||||
rm -f $(OUTPUTS)
|
|
||||||
@@ -1,6 +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:stylesheet>
|
|
||||||
@@ -1,654 +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='bsp'>
|
|
||||||
|
|
||||||
<title>Board Support Packages (BSP) - Developers Guide</title>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
A Board Support Package (BSP) is a collection of information that
|
|
||||||
defines how to support a particular hardware device, set of devices, or
|
|
||||||
hardware platform.
|
|
||||||
The BSP includes information about the hardware features
|
|
||||||
present on the device and kernel configuration information along with any
|
|
||||||
additional hardware drivers required.
|
|
||||||
The BSP also lists any additional software
|
|
||||||
components required in addition to a generic Linux software stack for both
|
|
||||||
essential and optional platform features.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
This section (or document if you are reading the BSP Developer's Guide) defines
|
|
||||||
a structure for these components
|
|
||||||
so that BSPs follow a commonly understood layout.
|
|
||||||
Providing a common form allows end-users to understand and become familiar
|
|
||||||
with the layout.
|
|
||||||
A common form also encourages standardization
|
|
||||||
of software support of hardware.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
The proposed format does have elements that are specific to the Poky and
|
|
||||||
OpenEmbedded build systems.
|
|
||||||
It is intended that this information can be
|
|
||||||
used by other systems besides Poky and OpenEmbedded and that it will be simple
|
|
||||||
to extract information and convert it to other formats if required.
|
|
||||||
Poky, through its standard layers mechanism, can directly accept the format
|
|
||||||
described as a layer.
|
|
||||||
The BSP captures all
|
|
||||||
the hardware-specific details in one place in a standard format, which is
|
|
||||||
useful for any person wishing to use the hardware platform regardless of
|
|
||||||
the build system they are using.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
The BSP specification does not include a build system or other tools -
|
|
||||||
it is concerned with the hardware-specific components only.
|
|
||||||
At the end
|
|
||||||
distribution point you can ship the BSP combined with a build system
|
|
||||||
and other tools.
|
|
||||||
However, it is important to maintain the distinction that these
|
|
||||||
are separate components that happen to be combined in certain end products.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<section id="bsp-filelayout">
|
|
||||||
<title>Example Filesystem Layout</title>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
The BSP consists of a file structure inside a base directory, which uses the following
|
|
||||||
naming convention:
|
|
||||||
<literallayout class='monospaced'>
|
|
||||||
meta-<bsp_name>
|
|
||||||
</literallayout>
|
|
||||||
"bsp_name" is a placeholder for the machine or platform name.
|
|
||||||
Here are some example base directory names:
|
|
||||||
<literallayout class='monospaced'>
|
|
||||||
meta-emenlow
|
|
||||||
meta-intel_n450
|
|
||||||
meta-beagleboard
|
|
||||||
</literallayout>
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
Below is the common form for the file structure inside a base directory.
|
|
||||||
While you can use this basic form for the standard, realize that the actual structures
|
|
||||||
for specific BSPs could differ.
|
|
||||||
|
|
||||||
<programlisting>
|
|
||||||
meta-<bsp_name>/
|
|
||||||
meta-<bsp_name>/<bsp_license_file>
|
|
||||||
meta-<bsp_name>/README
|
|
||||||
meta-<bsp_name>/binary/<bootable_images>
|
|
||||||
meta-<bsp_name>/conf/layer.conf
|
|
||||||
meta-<bsp_name>/conf/machine/*.conf
|
|
||||||
meta-<bsp_name>/recipes-bsp/*
|
|
||||||
meta-<bsp_name>/recipes-graphics/*
|
|
||||||
meta-<bsp_name>/recipes-kernel/linux/linux-yocto_git.bbappend
|
|
||||||
</programlisting>
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
Below is an example of the crownbay BSP:
|
|
||||||
|
|
||||||
<programlisting>
|
|
||||||
meta-crownbay/COPYING.MIT
|
|
||||||
meta-crownbay/README
|
|
||||||
meta-crownbay/binary/.gitignore
|
|
||||||
meta-crownbay/conf/layer.conf
|
|
||||||
meta-crownbay/conf/machine/crownbay.conf
|
|
||||||
meta-crownbay/recipes-bsp/formfactor/formfactor/crownbay/machconfig
|
|
||||||
meta-crownbay/recipes-bsp/formfactor/formfactor_0.0.bbappend
|
|
||||||
meta-crownbay/recipes-graphics/xorg-xserver/xserver-xf86-config/crownbay/xcorg.conf
|
|
||||||
meta-crownbay/recipes-graphics/xorg-xserver/xserver-xf86-config_0.1.bbappend
|
|
||||||
meta-crownbay/recipes-graphics/xorg-xserver/xserver-xf86-emgd-bin/.gitignore
|
|
||||||
meta-crownbay/recipes-graphics/xorg-xserver/xserver-xf86-emgd-bin_1.7.99.2.bb
|
|
||||||
meta-crownbay/recipes-graphics/xorg-xserver/xserver-xf86-emgd/crosscompile.patch
|
|
||||||
meta-crownbay/recipes-graphics/xorg-xserver/xserver-xf86-emgd/fix_open_max_preprocessor_error.patch
|
|
||||||
meta-crownbay/recipes-graphics/xorg-xserver/xserver-xf86-emgd/macro_tweak.patch
|
|
||||||
meta-crownbay/recipes-graphics/xorg-xserver/xserver-xf86-emgd/nodolt.patch
|
|
||||||
meta-crownbay/recipes-graphics/xorg-xserver/xserver-xf86-emgd_1.7.99.2.bb
|
|
||||||
meta-crownbay/recipes-kernel/linux/linux-yocto_git.bbappend
|
|
||||||
</programlisting>
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
The following sections describe each part of the proposed BSP format.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<section id="bsp-filelayout-license">
|
|
||||||
<title>License Files</title>
|
|
||||||
<programlisting>
|
|
||||||
meta-<bsp_name>/<bsp_license_file>
|
|
||||||
</programlisting>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
These optional files satisfy licensing requirements for the BSP.
|
|
||||||
The type or types of files here can vary depending on the licensing requirements.
|
|
||||||
For example, in the crownbay BSP all licensing requirements are handled with the
|
|
||||||
<filename>COPYING.MIT</filename> file.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
Licensing files can be MIT, BSD, GPLv*, and so forth.
|
|
||||||
These files are recommended for the BSP but are optional and totally up to the BSP developer.
|
|
||||||
</para>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section id="bsp-filelayout-readme">
|
|
||||||
<title>README File</title>
|
|
||||||
<programlisting>
|
|
||||||
meta-<bsp_name>/README
|
|
||||||
</programlisting>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
This file provides information on how to boot the live images that are optionally
|
|
||||||
included in the <filename>/binary</filename> directory.
|
|
||||||
The <filename>README</filename> file also provides special information needed for
|
|
||||||
building the image.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
Technically speaking a <filename>README</filename> is optional but it is highly
|
|
||||||
recommended that every BSP has one.
|
|
||||||
</para>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section id="bsp-filelayout-binary">
|
|
||||||
<title>Pre-built User Binaries</title>
|
|
||||||
<programlisting>
|
|
||||||
meta-<bsp_name>/binary/<bootable_images>
|
|
||||||
</programlisting>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
This optional area contains useful pre-built kernels and user-space filesystem
|
|
||||||
images appropriate to the target system.
|
|
||||||
This directory contains the Application Development Toolkit (ADT) and minimal
|
|
||||||
live images when the BSP is has been "tar-balled" and placed on the Yocto Project website.
|
|
||||||
You can use these kernels and images to get a system running and quickly get started
|
|
||||||
on development tasks.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
The exact types of binaries present are highly hardware-dependent.
|
|
||||||
However, a README file should be present in the BSP file structure that explains how to use
|
|
||||||
the kernels and images with the target hardware.
|
|
||||||
If pre-built binaries are present, source code to meet licensing requirements must also
|
|
||||||
be provided in some form.
|
|
||||||
</para>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section id='bsp-filelayout-layer'>
|
|
||||||
<title>Layer Configuration File</title>
|
|
||||||
<programlisting>
|
|
||||||
meta-<bsp_name>/conf/layer.conf
|
|
||||||
</programlisting>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
This file identifies the structure as a Poky layer, identifies the
|
|
||||||
contents of the layer, and contains information about how Poky should use it.
|
|
||||||
Generally, a standard boilerplate file such as the following works.
|
|
||||||
In the following example you would replace "bsp" and "_bsp" with the actual name
|
|
||||||
of the BSP (i.e. <bsp_name> from the example template).
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
<programlisting>
|
|
||||||
# We have a conf directory, add to BBPATH
|
|
||||||
BBPATH := "${BBPATH}:${LAYERDIR}"
|
|
||||||
|
|
||||||
# We have a recipes directory containing .bb and .bbappend files, add to BBFILES
|
|
||||||
BBFILES := "${BBFILES} ${LAYERDIR}/recipes/*/*.bb \ ${LAYERDIR}/recipes/*/*.bbappend"
|
|
||||||
|
|
||||||
BBFILE_COLLECTIONS += "bsp"
|
|
||||||
BBFILE_PATTERN_bsp := "^${LAYERDIR}/"
|
|
||||||
BBFILE_PRIORITY_bsp = "5"
|
|
||||||
</programlisting>
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
This file simply makes BitBake aware of the recipes and configuration directories.
|
|
||||||
This file must exist so that Poky can recognize the BSP.
|
|
||||||
</para>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section id="bsp-filelayout-machine">
|
|
||||||
<title>Hardware Configuration Options</title>
|
|
||||||
<programlisting>
|
|
||||||
meta-<bsp_name>/conf/machine/*.conf
|
|
||||||
</programlisting>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
The machine files bind together all the information contained elsewhere
|
|
||||||
in the BSP into a format that Poky can understand.
|
|
||||||
If the BSP supports multiple machines, multiple machine configuration files
|
|
||||||
can be present.
|
|
||||||
These filenames correspond to the values to which users have set the MACHINE variable.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
These files define things such as the kernel package to use
|
|
||||||
(PREFERRED_PROVIDER of virtual/kernel), the hardware drivers to
|
|
||||||
include in different types of images, any special software components
|
|
||||||
that are needed, any bootloader information, and also any special image
|
|
||||||
format requirements.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
At least one machine file is required for a BSP layer.
|
|
||||||
However, you can supply more than one file.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
This directory could also contain shared hardware "tuning" definitions that are commonly used to
|
|
||||||
pass specific optimization flags to the compiler.
|
|
||||||
An example is <filename>tune-atom.inc</filename>:
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
<programlisting>
|
|
||||||
BASE_PACKAGE_ARCH = "core2"
|
|
||||||
TARGET_CC_ARCH = "-m32 -march=core2 -msse3 -mtune=generic -mfpmath=sse"
|
|
||||||
</programlisting>
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
This example defines a new package architecture called "core2" and uses the
|
|
||||||
specified optimization flags, which are carefully chosen to give best
|
|
||||||
performance on atom processors.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
The tune file would be included by the machine definition and can be
|
|
||||||
contained in the BSP or referenced from one of the standard core set of
|
|
||||||
files included with Poky itself.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
Both the base package architecture file and the tune file are optional for a Poky BSP layer.
|
|
||||||
</para>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section id='bsp-filelayout-misc-recipes'>
|
|
||||||
<title>Miscellaneous Recipe Files</title>
|
|
||||||
<programlisting>
|
|
||||||
meta-<bsp_name>/recipes-bsp/*
|
|
||||||
</programlisting>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
This optional directory contains miscellaneous recipe files for the BSP.
|
|
||||||
Most notably would be the formfactor files.
|
|
||||||
For example, in the crownbay BSP there is a <filename>machconfig</filename> file and a
|
|
||||||
<filename>formfactor_0.0.bbappend</filename> file:
|
|
||||||
<programlisting>
|
|
||||||
meta-crownbay/recipes-bsp/formfactor/formfactor/crownbay/machconfig
|
|
||||||
meta-crownbay/recipes-bsp/formfactor/formfactor_0.0.bbappend
|
|
||||||
</programlisting>
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<note><para>
|
|
||||||
If a BSP does not have a formfactor entry, defaults are established according to
|
|
||||||
the configuration script.
|
|
||||||
</para></note>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section id='bsp-filelayout-recipes-graphics'>
|
|
||||||
<title>Display Support Files</title>
|
|
||||||
<programlisting>
|
|
||||||
meta-<bsp_name>/recipes-graphics/*
|
|
||||||
</programlisting>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
This optional directory contains recipes for the BSP if it has
|
|
||||||
special requirements for graphics support.
|
|
||||||
All files that are needed for the BSP to support a display are kept here.
|
|
||||||
For example, in the crownbay BSP several display support files exist:
|
|
||||||
<programlisting>
|
|
||||||
meta-crownbay/recipes-graphics/xorg-xserver/xserver-xf86-config/crownbay/xcorg.conf
|
|
||||||
meta-crownbay/recipes-graphics/xorg-xserver/xserver-xf86-config_0.1.bbappend
|
|
||||||
meta-crownbay/recipes-graphics/xorg-xserver/xserver-xf86-emgd-bin/.gitignore
|
|
||||||
meta-crownbay/recipes-graphics/xorg-xserver/xserver-xf86-emgd-bin_1.7.99.2.bb
|
|
||||||
meta-crownbay/recipes-graphics/xorg-xserver/xserver-xf86-emgd/crosscompile.patch
|
|
||||||
meta-crownbay/recipes-graphics/xorg-xserver/xserver-xf86-emgd/fix_open_max_preprocessor_error.patch
|
|
||||||
meta-crownbay/recipes-graphics/xorg-xserver/xserver-xf86-emgd/macro_tweak.patch
|
|
||||||
meta-crownbay/recipes-graphics/xorg-xserver/xserver-xf86-emgd/nodolt.patch
|
|
||||||
meta-crownbay/recipes-graphics/xorg-xserver/xserver-xf86-emgd_1.7.99.2.bb
|
|
||||||
</programlisting>
|
|
||||||
</para>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section id='bsp-filelayout-kernel'>
|
|
||||||
<title>Linux Kernel Configuration</title>
|
|
||||||
<programlisting>
|
|
||||||
meta-<bsp_name>/recipes-kernel/linux/linux-yocto_git.bbappend
|
|
||||||
</programlisting>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
This file appends your specific changes to the kernel you are using.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
For your BSP you typically want to use an existing Poky kernel found in the
|
|
||||||
Poky repository at <filename class='directory'>meta/recipes-kernel/kernel</filename>.
|
|
||||||
You can append your specific changes to the kernel recipe by using an append file,
|
|
||||||
which is located in the
|
|
||||||
<filename class='directory'>meta-<bsp_name>/recipes-kernel/linux</filename>
|
|
||||||
directory.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
Suppose you use a BSP that uses the <filename>linux-yocto_git.bb</filename> kernel,
|
|
||||||
which is the preferred kernel to use for developing a new BSP using the Yocto Project.
|
|
||||||
In other words, you have selected the kernel in your
|
|
||||||
<filename><bsp_name>.conf</filename> file by adding the following statement:
|
|
||||||
<programlisting>
|
|
||||||
PREFERRED_PROVIDER_virtual/kernel ?= "linux-yocto"
|
|
||||||
</programlisting>
|
|
||||||
You would use the <filename>linux-yocto_git.bbappend</filename> file to append
|
|
||||||
specific BSP settings to the kernel, thus configuring the kernel for your particular BSP.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
Now take a look at the existing "crownbay" BSP.
|
|
||||||
The append file used is:
|
|
||||||
<programlisting>
|
|
||||||
meta-crownbay/recipes-kernel/linux/linux-yocto_git.bbappend
|
|
||||||
</programlisting>
|
|
||||||
The file contains the following:
|
|
||||||
<programlisting>
|
|
||||||
FILESEXTRAPATHS := "${THISDIR}/${PN}"
|
|
||||||
COMPATIBLE_MACHINE_crownbay = "crownbay"
|
|
||||||
KMACHINE_crownbay = "yocto/standard/crownbay"
|
|
||||||
</programlisting>
|
|
||||||
This append file adds "crownbay" as a compatible machine,
|
|
||||||
and additionally sets a Yocto Kernel-specific variable that identifies the name of the
|
|
||||||
BSP branch to use in the GIT repository to find configuration information.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
One thing missing in this particular BSP, which you will typically need when
|
|
||||||
developing a BSP, is the kernel configuration (.config) for your BSP.
|
|
||||||
When developing a BSP, you probably have a kernel configuration file or a set of kernel
|
|
||||||
configuration files that, when taken together, define the kernel configuration for your BSP.
|
|
||||||
You can accomplish this definition by putting the configurations in a file or a set of files
|
|
||||||
inside a directory located at the same level as your append file and having the same name
|
|
||||||
as the kernel.
|
|
||||||
With all these conditions met simply reference those files in a SRC_URI statement in the append
|
|
||||||
file.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
For example, suppose you had a set of configuration options in a file called
|
|
||||||
<filename>defconfig</filename>.
|
|
||||||
If you put that file inside a directory named
|
|
||||||
<filename class='directory'>/linux-yocto</filename> and then added
|
|
||||||
a SRC_URI statement such as the following to the append file, those configuration
|
|
||||||
options will be picked up and applied when the kernel is built.
|
|
||||||
<programlisting>
|
|
||||||
SRC_URI += "file://defconfig"
|
|
||||||
</programlisting>
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
As mentioned earlier, you can group related configurations into multiple files and
|
|
||||||
name them all in the SRC_URI statement as well.
|
|
||||||
For example, you could group separate configurations specifically for Ethernet and graphics
|
|
||||||
into their own files and add those by using a SRC_URI statement like the
|
|
||||||
following in your append file:
|
|
||||||
<programlisting>
|
|
||||||
SRC_URI += "file://defconfig \
|
|
||||||
file://eth.cfg \
|
|
||||||
file://gfx.cfg"
|
|
||||||
</programlisting>
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
The FILESEXTRAPATHS variable is in boilerplate form here in order to make it easy
|
|
||||||
to do that.
|
|
||||||
It basically allows those configuration files to be found by the build process.
|
|
||||||
</para>
|
|
||||||
<note><para>
|
|
||||||
Other methods exist to accomplish grouping and defining configuration options.
|
|
||||||
For example, you could directly add configuration options to the Yocto kernel
|
|
||||||
<filename class='directory'>meta</filename> branch for your BSP.
|
|
||||||
The configuration options will likely end up in that location anyway if the BSP gets
|
|
||||||
added to the Yocto Project.
|
|
||||||
For information on how to add these configurations directly, see the
|
|
||||||
"Yocto Project Kernel Architecture and Use Manual" on the
|
|
||||||
<ulink url="http://yoctoproject.org/community/documentation">Yocto Project website
|
|
||||||
Documentation Page</ulink>
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
In general, however, the Yocto Project maintainers take care of moving the SRC_URI-specified
|
|
||||||
configuration options to the <filename class='directory'>meta</filename> branch.
|
|
||||||
Not only is it easier for BSP developers to not have to worry about putting those
|
|
||||||
configurations in the branch, but having the maintainers do it allows them to apply
|
|
||||||
'global' knowledge about the kinds of common configuration options multiple BSPs in
|
|
||||||
the tree are typically using.
|
|
||||||
This allows for promotion of common configurations into common features.
|
|
||||||
</para></note>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<!-- <section id='bsp-filelayout-packages'>
|
|
||||||
<title>Other Software (meta-<bsp_name>/recipes-kernel/*)</title>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
This section describes other pieces of software that the hardware might need for best
|
|
||||||
operation.
|
|
||||||
Examples show some of the things you could encounter.
|
|
||||||
The examples are standard <filename>.bb</filename> file recipes in the
|
|
||||||
usual Poky format.
|
|
||||||
You can include the source directly by referring to it in the source control system or
|
|
||||||
the released tarballs of external software projects.
|
|
||||||
You only need to provide these types of files if the platform requires them.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
The following file is a bootloader recipe that can be used to generate a new
|
|
||||||
bootloader binary.
|
|
||||||
Sometimes these files are included in the final image format and are needed to re-flash hardware.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
<programlisting>
|
|
||||||
meta-Emenlow/recipes-kernel/bootloader/bootloader_0.1.bb
|
|
||||||
</programlisting>
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
These next two files are examples of a hardware driver and a hardware daemon that might need
|
|
||||||
to be included in images to make the hardware useful.
|
|
||||||
Although the example uses "modem" there may be other components needed, such as firmware.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
<programlisting>
|
|
||||||
meta-Emenlow/recipes-Emenlow/modem/modem-driver_0.1.bb
|
|
||||||
meta-Emenlow/recipes-Emenlow/modem/modem-daemon_0.1.bb
|
|
||||||
</programlisting>
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
Sometimes the device needs an image in a very specific format so that the update
|
|
||||||
mechanism can accept and re-flash it.
|
|
||||||
Recipes to build the tools needed to do this can be included with the BSP.
|
|
||||||
Following is an example.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
<programlisting>
|
|
||||||
meta-Emenlow/recipes-Emenlow/image-creator/image-creator-native_0.1.bb
|
|
||||||
</programlisting>
|
|
||||||
</para>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section id='bs-filelayout-bbappend'>
|
|
||||||
<title>Append BSP-Specific Information to Existing Recipes</title>
|
|
||||||
<para>
|
|
||||||
Suppose you have a recipe such as "pointercal" that requires machine-specific information.
|
|
||||||
At the same time, you have your new BSP code nicely partitioned into a layer through which
|
|
||||||
you would also like to specify any machine-specific information associated with your new machine.
|
|
||||||
Before the <filename>.bbappend</filename> extension was introduced, you would have to copy the whole
|
|
||||||
pointercal recipe and files into your layer and then add the single file for your machine.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
With the <filename>.bbappend</filename> extension, however, your work becomes much easier.
|
|
||||||
This extension allows you to easily merge BSP-specific information with the original recipe.
|
|
||||||
Whenever BitBake finds any <filename>.bbappend</filename> files BitBake will include them after
|
|
||||||
it loads the associated <filename>.bb</filename> file but before any finalize
|
|
||||||
or anonymous methods are run.
|
|
||||||
This allows the BSP layer to do whatever it might want to do to customize the original recipe.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
If your recipe needs to reference extra files it can use the FILESEXTRAPATHS variable
|
|
||||||
to specify their location.
|
|
||||||
The example below shows extra files contained in a folder called ${PN} (the package name).
|
|
||||||
</para>
|
|
||||||
<programlisting>
|
|
||||||
FILESEXTRAPATHS := "${THISDIR}/${PN}"
|
|
||||||
</programlisting>
|
|
||||||
<para>
|
|
||||||
This technique allows the BSP to add machine-specific configuration files to the layer directory,
|
|
||||||
which will be picked up by BitBake.
|
|
||||||
For an example see <filename>meta-emenlow/packages/formfactor</filename>.
|
|
||||||
</para>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section id="bsp-filelayout-prebuilds">
|
|
||||||
<title>Pre-build Data (meta-<bsp_name>/prebuilds/*)</title>
|
|
||||||
<para>
|
|
||||||
This location can contain precompiled representations of the source code
|
|
||||||
contained elsewhere in the BSP layer.
|
|
||||||
Assuming a compatible configuration is used, Poky can process and use these optional pre-compiled
|
|
||||||
representations to provide much faster build times.
|
|
||||||
</para>
|
|
||||||
</section> -->
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section id='bsp-click-through-licensing'>
|
|
||||||
<title>BSP 'Click-Through' Licensing Procedure</title>
|
|
||||||
|
|
||||||
<note><para> This section describes how
|
|
||||||
click-through licensing is expected to work.
|
|
||||||
Currently, this functionality is not yet implemented.
|
|
||||||
</para></note>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
In some cases, a BSP contains separately licensed IP
|
|
||||||
(Intellectual Property) for a component that imposes
|
|
||||||
upon the user a requirement to accept the terms of a
|
|
||||||
'click-through' license.
|
|
||||||
Once the license is accepted the
|
|
||||||
Poky build system can then build and include the
|
|
||||||
corresponding component in the final BSP image.
|
|
||||||
Some affected components might be essential to the normal
|
|
||||||
functioning of the system and have no 'free' replacement
|
|
||||||
(i.e. the resulting system would be non-functional
|
|
||||||
without them).
|
|
||||||
On the other hand, other components might be simply
|
|
||||||
'good-to-have' or purely elective, or if essential
|
|
||||||
nonetheless have a 'free' (possibly less-capable)
|
|
||||||
version that could be used as a in the BSP recipe.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
For cases where you can substitute something and still maintain functionality,
|
|
||||||
the Yocto Project website at
|
|
||||||
<ulink url='http://yoctoproject.org/download/board-support-package-bsp-downloads'></ulink>
|
|
||||||
will make available a 'de-featured' BSP completely free of the encumbered IP.
|
|
||||||
In that case you can use the substitution directly and without any further licensing
|
|
||||||
requirements.
|
|
||||||
If present, this fully 'de-featured' BSP will be named appropriately different
|
|
||||||
than the normal encumbered BSP.
|
|
||||||
If available, this substitution is the simplest and most preferred option.
|
|
||||||
This, of course, assumes the resulting functionality meets requirements.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
If however, a non-encumbered version is unavailable or the 'free' version
|
|
||||||
would provide unsuitable functionality or quality, you can use
|
|
||||||
an encumbered version.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
Several methods exist within the Poky build system to satisfy the licensing
|
|
||||||
requirements for an encumbered BSP.
|
|
||||||
The following list describes them in preferential order:
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<orderedlist>
|
|
||||||
<listitem>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
Get a license key (or keys) for the encumbered BSP by visiting
|
|
||||||
a website and providing the name of the BSP and your email address
|
|
||||||
through a web form.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<!--
|
|
||||||
<ulink url='https://pokylinux.org/bsp-keys.html'>https://pokylinux.org/bsp-keys.html</ulink>
|
|
||||||
and give the name of the BSP and your e-mail address in the web form.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
COMMENT: This link is not implemented at this point.
|
|
||||||
|
|
||||||
<programlisting>
|
|
||||||
[screenshot of dialog box]
|
|
||||||
</programlisting>
|
|
||||||
|
|
||||||
-->
|
|
||||||
|
|
||||||
<para>
|
|
||||||
After agreeing to any applicable license terms, the
|
|
||||||
BSP key(s) will be immediately sent to the address
|
|
||||||
you gave and you can use them by specifying BSPKEY_<keydomain>
|
|
||||||
environment variables when building the image:
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<programlisting>
|
|
||||||
$ BSPKEY_<keydomain>=<key> bitbake poky-image-sato
|
|
||||||
</programlisting>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
These steps allow the encumbered image to be built
|
|
||||||
with no change at all to the normal build process.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
Equivalently and probably more conveniently, a line
|
|
||||||
for each key can instead be put into the user's
|
|
||||||
<filename>local.conf</filename> file.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
The <keydomain> component of the
|
|
||||||
BSPKEY_<keydomain> is required because there
|
|
||||||
might be multiple licenses in effect for a given BSP.
|
|
||||||
In such cases, a given <keydomain> corresponds to
|
|
||||||
a particular license. In order for an encumbered
|
|
||||||
BSP that encompasses multiple key domains to be built
|
|
||||||
successfully, a <keydomain> entry for each
|
|
||||||
applicable license must be present in <filename>local.conf</filename> or
|
|
||||||
supplied on the command-line.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
Do nothing - build as you normally would.
|
|
||||||
When a license is needed the build will stop and prompt you with instructions.
|
|
||||||
Follow the license prompts that originate from the
|
|
||||||
encumbered BSP.
|
|
||||||
These prompts usually take the form of instructions
|
|
||||||
needed to manually fetch the encumbered package(s)
|
|
||||||
and md5 sums into the required directory
|
|
||||||
(e.g. the <filename>poky/build/downloads</filename>).
|
|
||||||
Once the manual package fetch has been
|
|
||||||
completed, restart the build to continue where
|
|
||||||
it left off.
|
|
||||||
During the build the prompt will not appear again since you have satisfied the
|
|
||||||
requirement.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
Get a full-featured BSP recipe rather than a key.
|
|
||||||
You can do this by visiting the applicable BSP download page from the Yocto
|
|
||||||
Project website at
|
|
||||||
<ulink url='http://yoctoproject.org/download/board-support-package-bsp-downloads'></ulink>.
|
|
||||||
BSP tarballs that have proprietary information can be downloaded after agreeing
|
|
||||||
to licensing requirements as part of the download process.
|
|
||||||
Obtaining the code this way allows you to build an encumbered image with
|
|
||||||
no changes at all as compared to the normal build.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
</orderedlist>
|
|
||||||
<para>
|
|
||||||
Note that the third method is also the only option available
|
|
||||||
when downloading pre-compiled images generated from non-free BSPs.
|
|
||||||
Those images are likewise available at from the Yocto Project website.
|
|
||||||
</para>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
</chapter>
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user