Compare commits

..

143 Commits

Author SHA1 Message Date
Scott Rifenbark
27af23e65f documentation: yocto-project-qs - Final changes before the 1.3 lockdown
Fixed used of "Source Directory" and Build Directory.

(From yocto-docs rev: a4d79c5a7e73003fc99c274d876fbea453a80d20)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-23 00:03:17 +01:00
Scott Rifenbark
f735e50c63 documentation: poky-ref-manual - Final changes before the 1.3 lockdown.
various changes as required.

(From yocto-docs rev: 7f166508337c9d4aadad23997470a8871c5e42a4)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-23 00:03:17 +01:00
Scott Rifenbark
be3c73bc02 documentation: dev-manual - Final changes before 1.3 lockdown.
Made minor changes as needed due to some new sections, links,
and capitalization standards.

(From yocto-docs rev: bc966e5a78dadd14ecf1896a36e40a9b256bae77)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-23 00:03:17 +01:00
Scott Rifenbark
0526e01ddf documentation: bsp-guide - Final edits before 1.3 lockdown
Updated some example text based on the latest source
repositories for crown bay.  Replaced fishriver example with
fri2. Updated some capitalization usage for source directory
and build directory.

(From yocto-docs rev: 65973f7b30699fbb82b4d7f1b907e947489ba7d0)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-23 00:03:16 +01:00
Scott Rifenbark
a4266b454c documentation: adt-manual - final edits before 1.3 lockdown.
Made some minor edits to the book before locking down the
files for 1.3.

(From yocto-docs rev: 2b941103585a31b5dbcb65b784cc3381467ed697)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-23 00:03:16 +01:00
Scott Rifenbark
b1c27ead60 documentation: dev-manual - fixed capitalization on Source Directory.
(From yocto-docs rev: 8cfbd4eb519b2b966626c9a1ffd8515c198c2abd)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-23 00:03:16 +01:00
Scott Rifenbark
504c22b9c9 documentation: kernel-manual - minor edits before lockdown
Fixed a few references and links.  Also standardized on the
capitalization for the term "Source Directory" where it
refers to the YP poky structure on the development machine.

(From yocto-docs rev: 1a20418d8791d754ad66c5a059e65bd68a4c6b32)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-23 00:03:16 +01:00
Scott Rifenbark
767b28ea55 documentation: dev-manual - Updates to Git workflow and kernel patch
I updated the sections on the "Git Workflow" in Chapter 4 and
the "Patching the Kernel" section in Chapter 5 per Tom
Zanussi's review comments.  Minor technical changes.

(From yocto-docs rev: fd8a291349c06328adebd37f8a9bbeaa49adb44c)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-23 00:03:16 +01:00
Scott Rifenbark
dfeea177d3 documentation: poky-ref-manual - new variable and edited variable
Added the DISTRO_EXTRAS_RDEPENDS variable to the glossary and
updated the DISTRO_EXTRAS_RRECOMMENDS variable per Paul
Eggleton's review.

(From yocto-docs rev: bb27fcb3b990bb335176d5da9fec420fdc31bf22)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-23 00:03:16 +01:00
Scott Rifenbark
48363d5a00 documentation: dev-manual - removed the wip.png figure
this figure used to be at the end of the development manual.
I have removed it from both figures directories and taken
it out of the TARFILE list in the Makefile.

(From yocto-docs rev: ad8fcfc4bddb6bcee0e1a4ece78cd87ab0d51b6c)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-22 09:49:10 +01:00
Scott Rifenbark
15b49e25dc documentation: poky-ref-manual - Updates to DEPENDS and RDEPENDS
Suggested changes to help clear up what the list of items
in each of these variables should be and how automatic
handling of libraries is dealt with.

Richard Purdie reviewed the changes.

(From yocto-docs rev: 53865f904d5d4675286419a57bbb9282edfc1d0b)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-22 09:49:10 +01:00
Scott Rifenbark
4cce3e4aba documentation: poky-ref-manual - edits to SUMMARY and DESCRIPTION
Some final edits to these two variable descriptions from
Paul Eggleton.

(From yocto-docs rev: b606eed0f6a326ef572cd831b642312bb827a8c5)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-19 17:38:58 +01:00
Scott Rifenbark
6c3cebfe6d documenation: poky-ref-manual - updates to the LICENSE variable.
(From yocto-docs rev: 68bb94ccb879401d65e652746f138a139eaa0ca4)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-19 17:38:58 +01:00
Scott Rifenbark
c7812938cb documentation: poky-ref-manual - updated the DESCRIPTION variable.
(From yocto-docs rev: 170ed775df6d22b9570806367cbc17e6050d1493)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-19 17:38:58 +01:00
Scott Rifenbark
3f377fcc45 documentation: poky-ref-manual - Updated SUMMARY variable description.
(From yocto-docs rev: 13e38a7cd887f03ce6fde688c89ac989587123ef)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-19 17:38:57 +01:00
Scott Rifenbark
e90d014a0a documentation: dev-manual - Updated compliance section.
Applied legal changes per Karen Copenhaver's suggestions.

(From yocto-docs rev: 73b68aa349530f6604c7edc87b503f1b614b2c46)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-19 17:38:57 +01:00
Scott Rifenbark
e7ecb7e61e documentation: poky-ref-manual - Edits to feature backfill
Final edits (I think) to this section from Paul Eggleton.

(From yocto-docs rev: 95fd830ffb668109631205df4538454ccf023b20)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-19 17:38:57 +01:00
Scott Rifenbark
94f0bd12cd documentation: poky-ref-manual - Backfill variables updated.
Updated the MACHINE_FEATURES_BACKFILL,
MACHINE_FEATURES_BACKFILL_CONSIDERED,
DISTRO_FEATURES_BACKFILL, and
DISTRO_FEATURES_BACKFILL_CONSIDERED variables to have
more comprehensive information.

(From yocto-docs rev: 355eb3ebe02fbe4a340adaf83bf29a46f7c8230f)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-19 17:38:57 +01:00
Scott Rifenbark
965d189933 documenation: poky-ref-manual - updates to variables.
Did some re-wording on the WiFi example in both the
MACHINE_EXTRA_RDEPENDS and MACHINE_EXTRA_RRECOMMENDS
variables.  Clunkiness fixed.

(From yocto-docs rev: 0c76ae0ee14cce62ff02b728b1c9ac21f4f3b385)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-19 17:38:56 +01:00
Scott Rifenbark
9235aec531 documentation: poky-ref-manual - updates to distros and machines
The sections that list the features you can provide with the
MACHINE_FEATURES and DISTR_FEATURES variables implied that
the set was finite.  It is not.  I added wording to that
effect.

(From yocto-docs rev: d8e79fdf909ba5586dc45320b7cca03de639f49b)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-19 17:38:56 +01:00
Scott Rifenbark
fb968f87a5 documentation: poky-ref-manual - edits to the features backfill section.
(From yocto-docs rev: 7507d73501830896602bb18677eb7b0710794f55)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-19 17:38:56 +01:00
Scott Rifenbark
5e68ca2ea4 documentation: poky-ref-manual - edits to *_FEATURES glossary
Changed wording so that the lists of features do not seem
to be finite.  But rather, the set shipped with YP.

(From yocto-docs rev: 68e1eba075819863d8137be0b4c70935b88cb1a3)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-19 17:38:56 +01:00
Scott Rifenbark
b7e951a842 documentation: poky-ref-manual - updates to feature backfill section.
(From yocto-docs rev: aaf1156398033d50add5ac3944aa575917c7f7de)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-19 17:38:55 +01:00
Scott Rifenbark
cc345014ba documentation: poky-ref-manual - Updates to MACHINE glossary entry.
(From yocto-docs rev: 666562a428f5db2b2fc18c7cd21d17247479b24c)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-19 17:38:55 +01:00
Scott Rifenbark
ed96f96db0 documentation: poky-ref-manual - edits to MACHINE type variables.
Did some editing that helps clarify variables that deal with
the MACHINE.

(From yocto-docs rev: f1f63acffc952cc7d755fc6dd555379572fddaf0)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-18 12:15:07 +01:00
Scott Rifenbark
26868e8050 documentation: poky-ref-manual - quoted section reference
For consistency.

(From yocto-docs rev: 7b51db2d3409d6a9c74a7a9b0b2cc39cf6622033)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-18 12:15:07 +01:00
Scott Rifenbark
dac3b30a2b documentation: poky-ref-manual - Updated build/conf/local.conf
I added the BB_NUMBER_THREAD and PARALLEL_MAKE variables into
the description for suggested variables to set if you edit
local.conf.

(From yocto-docs rev: 7345bbf6c10b823e6364e85a4e75a7ec60a29aef)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-18 12:15:06 +01:00
Scott Rifenbark
fae3759ad7 documentation: poky-ref-manual - updated the STAMP glossary description.
(From yocto-docs rev: 63720ee98bc9dd4eaa574784e7aa1ccd20822e80)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-18 12:15:06 +01:00
Scott Rifenbark
c9b61655e0 documentation: poky-ref-manual - small edit in wording.
Better wording for MULTIMACH_TARGET_SYS.

Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-17 17:32:54 +01:00
Scott Rifenbark
0497b035a2 documentation: poky-ref-manual - Added and updated variables.
Fixes [YOCTO_#3262]

* Added correct information to the STAMP variable glossary
  entry.

* Created a new variable glossary item for the
  MULTIMACH_TARGET_SYS variable.

* Created a new variable glossary item for the
  EXTENDPE variable.

Reported-by: Patrick Turley <patrickturley@gamestop.com>
(From yocto-docs rev: ea50e41dc71d3876dd1b00aeec663400ac4a5ced)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-17 17:32:54 +01:00
Scott Rifenbark
ba6aac3106 documentation: dev-manual - Edits to "Patching the Kernel" section.
Edits according to Darren Hart's feedback.

Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-17 17:32:54 +01:00
Scott Rifenbark
9b2c586aad documentation: dev-manual - lttng and Git workflow changes
* Updates to the Git Workflow section based on feedback from
  Darren Hart.  These changes simplify the flow and make it
  generic.

* Updates to the lttng user space tool used from within
  Eclipse.  The legacy version of the tool is no longer supported
  so it had to be edited out of the description and replaced
  with the 2.0 version.

(From yocto-docs rev: 81d2b79035fc99f92364bfef2c76076738cbaa52)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-17 17:32:54 +01:00
Robert P. J. Day
abbe518683 documentation: bsp-guide - minor edits.
One change resulted in changing out "include" for "require"
in code from the Crown Bay example.

(From yocto-docs rev: 69b21d5f62ad9020646a26ce13d349af50aee419)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-17 17:32:53 +01:00
Scott Rifenbark
4f6040ef2c documentation: poky-ref-manual - changes to required variables for recipes
Several variables are no longer needed in this section.  I have
removed them.

Reported-by: Paul Eggleton <paul.eggleton@intel.com>
(From yocto-docs rev: b627269d18d9c8b4342f8465966d780756ff5a22)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-17 17:32:53 +01:00
Scott Rifenbark
a8c43670d9 documentation: dev-manual - small edit to compliance section.
(From yocto-docs rev: 4c80b414645b1cb8750dd877a1f857807a9f1259)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-17 17:32:53 +01:00
Scott Rifenbark
d13dfa3b2d documentation: dev-manual - edits to the compliance section.
Feedback from Paul Eggleton suggested to not use the linked
term "Source Directory" in the last paragraph of this section.
Reasoning being that it is mis-leading in this case. People
reading this will be thinking more along the lines of traditional
source code rather than our establishe "Source Directory" term,
which in the doc set refers to either the unpacked poky tarball
or the cloned poky Git repository.

Reported-by: Paul Eggleton <paul.eggleton@intel.com>
(From yocto-docs rev: f9bfcdebf85481839df01442ee81c4c9e8ee559a)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-17 17:32:52 +01:00
Scott Rifenbark
a1b04a126e documentation: poky-ref-manual - added note about PATH
Added a note explaining why "PATH" is needed when using
SSTATE_MIRRORS if the shared state directory structure on
the mirror is the same as SSTATE_DIR.

(From yocto-docs rev: 94b8a45827d2bf7f16ec530de694ec5e4e6ed164)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-17 17:32:52 +01:00
Scott Rifenbark
96a00c1402 documentation: Release date updated.
Updated the release month in all the manual revision history
tables to say "October 2012" from "Sometime in 2012".

(From yocto-docs rev: 1fc9313fe6c69db3d8cece6d940f78a2f0dc8386)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-17 17:32:52 +01:00
Scott Rifenbark
bdd3323254 documentation: poky-ref-manual - edits to migration chapter.
Paul Eggleton's review comments applied.

(From yocto-docs rev: b7d9a547218f1d79ae5802a41df11911bc9b7e9f)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-17 17:32:51 +01:00
Scott Rifenbark
e32d893c4c documentation: dev-manual - Removed whitespace.
(From yocto-docs rev: 8f6479e8e04a54929e704064ecb44e3fee3cf8b3)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-17 17:32:51 +01:00
Scott Rifenbark
3df40af8d0 documentation: poky-ref-manual - New chapter on migration added.
Created a new chapter dedicated to migration information for
the user updgrading from a previous YP release. Also had to
include the new chapter in the poky-ref-manual.xml manual so
that it will build.

(From yocto-docs rev: df8e02c17bc8157ad4abd1e4954f762ccde8915c)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-17 17:32:51 +01:00
Scott Rifenbark
058a9ff749 documentation: poky-ref-manual - moved SSTATE_DIR.
This entry was situated so that it was not in alphabetical
order.  I moved it.

(From yocto-docs rev: f545414ead63ff58557142acdf416bd5e58d5c45)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-17 17:32:50 +01:00
Scott Rifenbark
5c8546cca0 documentation: poky-ref-manual - New glossary entry SSTATE_MIRRORS.
(From yocto-docs rev: acf9ce9105636b54e6846026edb8d49cd65c0e0b)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-17 17:32:50 +01:00
Andrea Galbusera
5c5b56cffc documentation: kernel-manual - Fixed typo.
(From yocto-docs rev: 0ec3c614bc7fad0cf67ddc2cd802cd0e5b0adf95)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-15 14:45:51 +01:00
Scott Rifenbark
1fc37b75cb documentation: dev-manual - edits to kernel section and compliance
* Edits to get the patching the kernel section more sane.

* A tweak to the opening sentence of the compliance section to
  rid it of the split-infinitives.

(From yocto-docs rev: 8e2ff293e85a602efd98aceb20da5a2ea5f2a34d)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-15 14:45:51 +01:00
Scott Rifenbark
e6bb30d96c documentation: dev-manual - edits to the license compliance section.
Implemented Beth Flanagan's review comments.

(From yocto-docs rev: d480c8525861db4383ce1b656168c01d01c26b2e)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-15 14:45:51 +01:00
Scott Rifenbark
dbd5778d74 documentation: dev-manual - edits to the patching the kernel and model sections.
Made changes to try and clean up the process.

(From yocto-docs rev: 9c4fbcb473dc594647ba8779162379a745f8f8d6)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-15 14:45:50 +01:00
Scott Rifenbark
eed0d8765e documentation: poky-ref-manual, yocto-project-qs - supported distros
Created the new section in the reference manual that lists the
distributions that support YP.

Updated the section in the QS to reference the new section in
the reference manual.

(From yocto-docs rev: ff85945574466b2e6431fbaa0026cdea9d96ac9b)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-15 14:45:50 +01:00
Scott Rifenbark
8dcc289ee4 documentation: poky-ref-manual - Updates to the BPN variable.
(From yocto-docs rev: ae0be8b69e3acfd423d5d062ec32621eb3dce4c5)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-15 14:45:50 +01:00
Scott Rifenbark
4a847c8abd documentation: dev-manual - Added license compliance section.
(From yocto-docs rev: a94b34506152f3494f1acce7b03318d3b5a0a283)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-15 14:45:50 +01:00
Paul Eggleton
28b6628f41 documentation: poky-ref-manual - Updates to the poky structure
* Add meta-yocto, meta-yocto-bsp and meta-hob
* Remove meta-rt - this was merged into OE-Core (meta)
* Remove meta-demoapps - this was dropped

(From yocto-docs rev: c90a8f85f4462caa49c7da2e7ec4541534bee57a)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-15 14:45:49 +01:00
Paul Eggleton
4792499fa5 documentation: poky-ref-manual - wording changes
Some wording changes from "packages" to "recipe" as appropriate
in some of the variable glossary entries.

(From yocto-docs rev: 8f3d72dad9b68f78987a497092d74ff3f7e35b28)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-15 14:45:49 +01:00
Paul Eggleton
2e6a6f0598 documentation: poky-ref-manual - change support to opkg from ipkg
We haven't supported ipkg for some time now - it was replaced by opkg
(whilst still using the ipk package format).

(From yocto-docs rev: 07b3dd9a73be25f31c919ed750ca320c7507eff0)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-15 14:45:49 +01:00
Paul Eggleton
fece3acfb9 documentation: poky-ref-manual - Edits to fix default description
* Use correct/up-to-date names of package systems
* SUMMARY does not default to the value of DESCRIPTION, it's the other
  way around (although the logic may be improved in future so that this
  is the effect).

(From yocto-docs rev: 4ec095f0f45cb3a62a8dfdd1a098b23cbe1dc7b5)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-15 14:45:48 +01:00
Paul Eggleton
a15b641c1c documentation: poky-ref-manual - New backfill variables and section.
Document DISTRO_FEATURES_BACKFILL and MACHINE_FEATURES_BACKFILL. We may
wish to expand upon this in future, but at least this explains what
these variables are for and how to use them.

Also add a link from the DISTRO_FEATURES entry to the section that lists
valid DISTRO_FEATURES items.

(From yocto-docs rev: 018af5c28b44464ae66646780ade910bdcab2bef)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-15 14:45:48 +01:00
Paul Eggleton
f10615345e documentation: poky-ref-manual - DISTRO description extended.
Extend the description of the DISTRO variable so that it mentions that
this points to a .conf file under conf/distro and mentions what happens
if the value is left blank.

(From yocto-docs rev: 50f8f0394d8d849e0a227d6c9ffcdc3cccb7e307)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-15 14:45:48 +01:00
Paul Eggleton
425e00fb99 documentation: poky-ref-manual - New PACKAGECONFIG glossary entry.
Add a description of the PACKAGECONFIG variable to the variable
glossary.

(From yocto-docs rev: 07d08314d3151de7073567a7800156f69fdb549e)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-15 14:45:47 +01:00
Paul Eggleton
4a656cf222 documentation: poky-ref-manual - MACHINE definition extended.
Extend the description of the MACHINE variable so that it mentions that
this points to a .conf file under conf/machine.

(From yocto-docs rev: dd82b176bb059d03faec1abdd406e4cf8f0e5afb)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-15 14:45:47 +01:00
Paul Eggleton
8419bb799e documentation: poky-ref-manual - Variable descriptions edited.
Adjust the descriptions so that it is clearer that these are specific
to a machine and should appear in the machine's .conf file, and are
intended to affect the image contents, not the dependencies of a
specific package. Also change the examples so that they demonstrate more
realistic usage scenarios for these variables.

(From yocto-docs rev: 3c3b8b117b09d78637ae8c4d27f77194cf197ea9)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-15 14:45:47 +01:00
Paul Eggleton
985a13277d documentation: poky-ref-manual - LICENSE_PATH not LICENSE_DIR.
Fixes [YOCTO_#3118]

LICENSE_PATH is the correct variable to use for 1.3 - see:

https://bugzilla.yoctoproject.org/show_bug.cgi?id=3118

(From yocto-docs rev: 96b93175d662696c3c2f25c0d8aa73ab6c5abdd3)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-15 14:45:46 +01:00
Paul Eggleton
b771c50128 documentation: dev-manual - Typo fixed.
(From yocto-docs rev: f64babca3cce710718bbc6b4199ae6ad4002d209)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-15 14:45:46 +01:00
Scott Rifenbark
1a6bf6e4af documentation: Makefile, dev-manual - edits to patching kernel
Made some general edits to the new "Patching the Kernel" section.
Also had to remove a couple of images no longer used in the section
from the Makefile "TARFILES" variable.

(From yocto-docs rev: ac61e22e2f89926fbbda56fbaa4384c3c5156360)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-15 14:45:46 +01:00
Paul Eggleton
1e4028c5d3 local.conf.sample: add PATH to SSTATE_MIRRORS comments
The shared state cache as pointed to by SSTATE_DIR by default now has
two-character subdirectories to prevent there being an issue with too
many files in the same directory; also, native sstate packages will go
into a subdirectory named using the distro ID string. If you copy the
newly structured sstate cache to a mirror location (either local or
remote) and then point to it in SSTATE_MIRRORS, you need to append
"PATH" to the end of the mirror URL so that the path used by bitbake
before the mirror substitution is appended to the path used to access
the mirror.

(From meta-yocto rev: 2724ec2601efeb677df251c46bbcc6a7f255103d)

Signed-off-by: Paul Eggleton <paul.eggleton@linux.intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-15 14:43:48 +01:00
Saul Wold
f851202b2f distro_alias: Update for Internal BOM tracking
(From meta-yocto rev: 468d15a0949311c602b5a2b5e5bc01bed59b137e)

Signed-off-by: Saul Wold <sgw@linux.intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-15 14:43:47 +01:00
Richard Purdie
cc7d4783e7 gitignore: Fix for poky repository
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-15 14:42:59 +01:00
Elizabeth Flanagan
c9de24d3f4 build-appliance-image.bb: Bump SRCREV for 1.3_M5.rc4
Bumping the SRCREV for danny in preparation for 1.3_M5.rc4

Signed-off-by: Elizabeth Flanagan <elizabeth.flanagan@intel.com>
2012-10-10 14:49:57 -07:00
Richard Purdie
58a7160419 gdbm: Resolve host contamination issue
The autoconf macros detect the presence of -ldbm or -lndbm on the host
system and add the library to link against, for now good reason I can
explain.

This patch makes the build behave determinstically whether they're
present or not. Other than the extra linkage, there doesn't appear to be
any other change in behaviour from these options and they look like
dead code.

The extra linkage can cause problems where sstate is used on a machine
where the extra librbary isn't present causing build failures.

(From OE-Core rev: f609bf5525450bfdb8e0864d44c41cce7f9319c9)

Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-10 22:46:52 +01:00
Elizabeth Flanagan
767ced9fa5 build-appliance-image.bb: Bump SRCREV for 1.3_M5.rc4
Bumping the SRCREV for danny in preparation for 1.3_M5.rc4

Signed-off-by: Elizabeth Flanagan <elizabeth.flanagan@intel.com>
2012-10-10 10:53:18 -07:00
Elizabeth Flanagan
5ecc6d0d6f Revert "build-appliance-image.bb: Bumping SRCREV for 1.3_M4"
Wrong build number in the commit log

This reverts commit c030e463ab.
2012-10-10 10:52:48 -07:00
Elizabeth Flanagan
c030e463ab build-appliance-image.bb: Bumping SRCREV for 1.3_M4
In preparation for 1.3_M4, bumping SRCREV for the build appliance

Signed-off-by: Elizabeth Flanagan <elizabeth.flanagan@intel.com>
2012-10-10 10:34:00 -07:00
Richard Purdie
709f570c82 pkgconfig: Drop the RREPLACES for pkgconfig-dev
This line causes pkgconfig-dev to replace pkgconfig so the package with all the files
in is replaced by one with no files. This makes no sense and hence we should just
remove this broken line.

At this point in the release, this is the safest way to fix this even if an empty -dev
package is left available.

[YOCTO #2878]

(From OE-Core rev: 5bed2bb831b379a8fbf2f725435af4b7c934359e)

Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-10 18:30:00 +01:00
Saul Wold
cfbf6fad48 eglibc: force make to use /bin/bash
The eglibc core build still has a number of issues with /bin/dash.
Recently found is both sysdeps/unix/make-syscalls.sh and it's output,
which make calls via SHELL do not play well with /bin/dash. By force
make to use /bin/bash via SHELL setting it works correctly.

Currenly known issues are: make-syscalls.sh line with a bad substitution,
which can be corrected by:
     vdso_symver="$(printf '%s\n' ${vdso_symver} | sed 's/\./_/')"

Following that there is an issue with emiting a '\n' through a second
echo and then to the compiler. There maybe more issues beyond that.

[YOCTO #3080]

(From OE-Core rev: 9d002f7cdc5309c4d850a76e4fd73ff04c980a07)

Signed-off-by: Saul Wold <sgw@linux.intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-10 18:29:52 +01:00
Scott Rifenbark
650d20107d documentation: poky-ref-manual - Formatting fixes for variable names.
(From yocto-docs rev: 71c726194142821eaaf7a222001f2f5047369686)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-10 15:24:15 +01:00
Scott Rifenbark
a8a5765fed documentation: poky-ref-manual - new glossary entry for "T".
Fixes [YOCTO_#3261]

(From yocto-docs rev: 3f6de40fcdd364728a2b62f59940a9ae4019d1d5)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-10 15:24:14 +01:00
Scott Rifenbark
e369448f32 documentation: dev-manual - fixed typo.
(From yocto-docs rev: 902db5c68b1b0670600f06731b95e1e32c687475)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-10 15:24:14 +01:00
Scott Rifenbark
d1fe084c03 documentation: dev-manual - edits to patching kernel section plus others
Removed the temporary text in the new "Patching the Kernel" section
that was copied from the old appendix A.  Fixed the PRINC variable
in the creating a new layer example.

(From yocto-docs rev: 3eba77a81d3460866638a2f2d6b7c27d9dd1a2be)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-10 15:24:14 +01:00
Scott Rifenbark
486441be18 documentation: dev-manual, mega-manual - removed figure
Removed the "kernel-example-repos-generic.png" file as it describes
the bare clone method for kernel modification.  We are removing
that from this manual.

(From yocto-docs rev: c25c4f662c2f8a83fd9b09583646be9dbe01424c)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-10 15:24:14 +01:00
Scott Rifenbark
0eca2b4cb2 documentation: mega-manual - copied in new kernel flow diagram.
Moved the simpler version of the kernel workflow diagram to the
figures folder.

(From yocto-docs rev: c856fe320a0e70701f14312439fec6ccb707f9bd)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-10 15:24:14 +01:00
Scott Rifenbark
7c08b602e6 documentation: dev-manual, bsp-guide, kernel-manual - kernel workflow
The kernel workflow section was re-written to reflect that the
kernel appendix has been removed.  Also, changes to the flow in
general no longer make reference to the bare clone and the copy
of the bare clone as a method used to modify the kernel.

Many links were modified in other manuals as well.

(From yocto-docs rev: 38adbcb00d4305029cfa94e5ef047da41823f021)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-10 15:24:14 +01:00
Scott Rifenbark
970d00de04 documentation: dev-manual - Removed figures no longer needed.
The figure that shows the bare clone and the copy of the bare
clone are no longer needed.  The description for the kernel
workflow has been reduced to discussing only modification of
the temporary source files.  We are no longer talking about
creating a bare clone and copying it as a way to modify the
kernel in this manual.  That topic will be described elsewhere.

(From yocto-docs rev: f6a25e5e3763ea7a1f8a81ce377e3b520143b852)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-10 15:24:14 +01:00
Scott Rifenbark
f058e96728 documentation: poky-ref-manual - variables defined.
Fixes [YOCTO_#3245]

New glossary terms for SPECIAL_PKGSUFFIX, and MLPREFIX.

Also improved the definition of the BPN variable.

(From yocto-docs rev: d9eb38122967a5729f3a6aff1dae00427a22f579)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-10 15:24:14 +01:00
Scott Rifenbark
11fdbf2b27 documenation: dev-manual - re-ordered chapters.
The "Common Tasks" chapter is better suited as the last chapter in
this manual.  So I moved the development workflows up a chapter.

(From yocto-docs rev: 19f0a6411c065388b5bd0083338b164b43baff0e)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-10 15:24:14 +01:00
Scott Rifenbark
bc02fb725b documentation: dev-manual - removed Appendix A.
The kernel example appendix is now gone.

(From yocto-docs rev: d744e76034ff2711a8c40b9bb1982971d28a04b1)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-10 15:24:14 +01:00
Scott Rifenbark
5d4b08853e documentation: dev-manual, bsp-guide - Removing/Moving Appendix A
The kernel example appendix is being removed.  This broke a lot
of links.  For now I have moved the information into a new section
called "Patching the Kernel".  I have preserved the information
by adding the old appendix file as kerne-appendix-orig.xml.

(From yocto-docs rev: 994235a69362dfb0114ef9001ea7f2f2e2fdc5c3)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-10 15:24:14 +01:00
Scott Rifenbark
c29e8cbb2f documentation: dev-manual - Updates to configuring Kernel section
Eliminated the section A.2, which had an example of how to use
menuconfig in the kerenl example appendix.  The information is
now merged into the similar section in Chapter 4 "Common
Tasks."  It was decided that the Appendix A examples in the
manual were too detailed for a general development guide.

(From yocto-docs rev: f88ec421b257657f02cc0f132ec2580c17f07cef)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-10 15:24:13 +01:00
Tom Zanussi
784f93baf3 perl: add archlib_exp variable used to generate ARCHLIB_EXP in config.h
perl.c uses an ARCHLIB_EXP define to generate compile-time code that
adds the archlibexp path to @INC during run-time initialization of a
new perl interpreter.

Because we've changed this value in a temporary way to make it
possible to use ExtUtils::Embed in the target build (the temporary
value in config.sh gets re-stripped out during packaging), the
ARCHLIB_EXP value that gets generated still uses the temporary version
instead of the original expected version (i.e. becauses it's in the
generated config.h, it doesn't get stripped out during packaging like
the others in config.sh).

This creates an unmodified version called archlib_exp that gets used
by a modified config_h.SH to get the correct value into config.h

This patch uses an unmodified version of archlibexp called
archlib_exp, introduced to config.sh, which is used to generate the
correct value of ARCHLIB_EXP into config.h

Fixes [YOCTO #3099].

(From OE-Core rev: cbcfdeb1d55e2e76f199750bda401bad126ae234)

Signed-off-by: Tom Zanussi <tom.zanussi@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-10 15:24:13 +01:00
Martin Jansa
755ca76f8e sstate-cache-management: hide error message when one of possible layer location doesn't exist
* fixes [YOCTO #3116]

(From OE-Core rev: bde88116d9d7e86ca7ecac4cf990689f972b0b1c)

Signed-off-by: Martin Jansa <Martin.Jansa@gmail.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-10 15:24:13 +01:00
Andrei Dinu
1e892fb5a0 bitbake: hob-toolchain: task-core-standalone-sdk-target renamed to packagegroup-core-standalone-sdk-target
This change also applies to task-core-standalone-sdk-target-dbg and resolves
build failures caused by the missing packages.

(Bitbake rev: 4cd0200e96fb282980a945b80af641a6e022e0b4)

Signed-off-by: Andrei Dinu <andrei.adrianx.dinu@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-10 15:24:13 +01:00
Flanagan, Elizabeth
af811fbc0b bzip license: bzip2 not bzip.
The name of the license for bzip2 is wrong causing warnings
to be thrown.

(From OE-Core rev: 566c6101cc7a8d90973eb22478ffc77eac23f81c)

Signed-off-by: Elizabeth Flanagan <elizabeth.flanagan@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-10 15:24:13 +01:00
Richard Purdie
0dc25d42ef gcc-cross-canadian: Fix gettext dependency
There was a problem in commit ad23395cd1 since
gettext-nativesdk was translated to gettext instead of nativesdk-gettext.

This fixes to use the correct dependency.

(From OE-Core rev: a6e325342cb489e05927d6cb2bb0a24fa6c20ef8)

Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-10 15:24:13 +01:00
Cristiana Voicu
5a816edcf9 bitbake: hob/imageconfigurationpage: a 'hob-image' appears listed in the base image combo box
-remove this image from image combo box

[YOCTO #3230]

(Bitbake rev: 90fd57ee3cb2856c10bda1f5af4879d2b7cf2668)

Signed-off-by: Cristiana Voicu <cristiana.voicu@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-10 15:24:13 +01:00
Constantin Musca
f4434bd16e bitbake: hob/hobeventhandler: Describe the runCommand failure exception
[YOCTO #1245]

(Bitbake rev: 17f28f09452f70dfb67fce9a397a99deec84dfe5)

Signed-off-by: Constantin Musca <constantinx.musca@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-10 15:24:13 +01:00
Bruce Ashfield
e83c7d3056 linux-yocto-bsps/3.4: perf: parallel build and tools fixes
korg commit 42dcd1f4e [perf tools: Fix parallel build] fixes parallel
build issues that are being seen in the autobuilder.

We also have a fix from Tom:

[
    perf annotate: replace 'expand' with equivalent sed expression

    We don't have 'expand' in our userspace so we need to accomplish the
    same thing using 'sed', which we do have.
]

So we apply it to all BSP branches and kernel types.

(From meta-yocto rev: 54fc1fd107f907a208b41a66c0a7b9b40cb428c7)

Signed-off-by: Tom Zanussi <tom.zanussi@intel.com>
Signed-off-by: Bruce Ashfield <bruce.ashfield@windriver.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-10 15:24:13 +01:00
Bruce Ashfield
571259cc48 linux-yocto/3.4: perf: parallel build and tools fixes
korg commit 42dcd1f4e [perf tools: Fix parallel build] fixes parallel
build issues that are being seen in the autobuilder.

We also have a fix from Tom:

[
    perf annotate: replace 'expand' with equivalent sed expression

    We don't have 'expand' in our userspace so we need to accomplish the
    same thing using 'sed', which we do have.
]

So we apply it to all BSP branches and kernel types.

(From OE-Core rev: f06e7d38db35c56c71a42264361ec45fb3777a14)

Signed-off-by: Tom Zanussi <tom.zanussi@intel.com>
Signed-off-by: Bruce Ashfield <bruce.ashfield@windriver.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-10 15:24:13 +01:00
Darren Hart
ad41126681 poky-tiny: Update the default kernel to linux-yocto-tiny_3.4
The 3.4 linux-yocto-tiny kernel successfully boots to a prompt for
qemux86.

(From meta-yocto rev: e24ea77ca40e096f294649e3f85c8ec47efcbb87)

Signed-off-by: Darren Hart <dvhart@linux.intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-10 15:24:13 +01:00
Bruce Ashfield
f2533f35e8 linux-yocto-bsps: update hardware reference BSPs to v3.4.11
The hardware reference BSPs are missing the update to 3.4.11
that the qemu* machines received several weeks ago.

Bumping to 3.4.11 specifically addresses the segfaults being
seen with rpm on the beagleboard.

[YOCTO #3186]

(From meta-yocto rev: f2d93f4e79d0c8c0035774cfa7dc4beb197899f4)

Signed-off-by: Bruce Ashfield <bruce.ashfield@windriver.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-10 15:24:13 +01:00
Richard Purdie
dcd1428716 sstate: Also add datadir/sgl to sstate whitelist to avoid openjade warning
(From OE-Core rev: e0ff54db5a5ab171ee1d0dbcf7f267235c21e601)

Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-10 15:24:13 +01:00
Richard Purdie
d81ab9f844 qemu: When applying qemu-mips workaround, check the file exists first
If qemu-mips was disabled as done in some distros, this wrapper would fail.
Therefore check if the file exists before wrapping it.

(From OE-Core rev: 9ec1c06915b10d142bf5646396c4e91bb61a40a5)

Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-10 15:24:12 +01:00
Darren Hart
13bf7c1299 linux-yocto-tiny: Add tiny recipe for the 3.4 linux-yocto kernel
This recipe builds the "tiny" kernel type defined by the linux-yocto
meta-data. Support is defined for the qemux86 machine via
common-pc-tiny.scc in the linux-yocto meta branch. The resulting
kernel is 1.8 MB and boots to a serial console with with qemux86 and
core-image-minimal using the following command:

qemu -kernel tmp/deploy/images/bzImage-qemux86.bin -initrd tmp/deploy/images/core-image-minimal-qemux86.cpio.gz -append "root=/dev/ram0 console=ttyS0" -nographic

(From OE-Core rev: cf25f211ec420e1e8dd48c8e62f60deefe2c6d53)

Signed-off-by: Darren Hart <dvhart@linux.intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-10 15:24:12 +01:00
Saul Wold
6d45c9f72d nfs-export-root: add explict no_subtree-check to suppress warning
exportfs: /etc/exports [1]: Neither 'subtree_check' or 'no_subtree_check' specified for export "*:/".
  Assuming default behaviour ('no_subtree_check').
  NOTE: this default has changed since nfs-utils version 1.0.x

(From OE-Core rev: 1438228d3b54dfdcf8c36154c927c80fcecf688e)

Signed-off-by: Saul Wold <sgw@linux.intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-10 15:24:12 +01:00
Bruce Ashfield
5ae465073f linux-yocto/3.4: tiny: Add qemu KMACHINE to common-pc-tiny.scc
Updating the meta SRCREV to pickup the following change:

  Ensure the qemux86 machine is defined in common-pc-tiny as it is
  for -standard and -rt.

(From OE-Core rev: 1076910ac3cd55a3f87b5ca7a1db1e38c623480a)

Signed-off-by: Darren Hart <dvhart@linux.intel.com>
Signed-off-by: Bruce Ashfield <bruce.ashfield@windriver.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-10 15:24:12 +01:00
Bruce Ashfield
2de77b3c38 linux-yocto/3.4: fix kconfig warnings and unnecessary options
Updating the kernel configuration fragments to fix the following
issues:

  - remove options that are no longer in the 3.4 kernel
  - disable unused, but large kernel modules
  - fix kconfig audit warnings for x86 BSPs
  - make uprobes reusable by multiple fragments

The following meta branch commits are represented by this update:

  3da1172 uprobes: split into enable and patch fragments
  17ec51a meta: cleanup invalid/obselete 3.4 CONFIG options
  b5cee42 meta: disable OCFS2 by default
  efe937e meta: drm: tag DRM options as 'hardware'
  10b5155 meta: emenlow: clean emenlow configuration warnings
  a907b82 meta: add CONFIG_SHMEM to standard kernel config

(From OE-Core rev: a01bb3ec72c375c0f06006769969f63fed3ef566)

Signed-off-by: Bruce Ashfield <bruce.ashfield@windriver.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-10 15:24:12 +01:00
Scott Rifenbark
f6092be1de documentation: dev-manual - mentioned SRC_URI in the kernel example
this statement in the linux-yocto-3.4.bbappend file needs to
have the comment removed so the source can be found.

(From yocto-docs rev: 821162221818f5ce53bb903aeef57c85314f5083)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-10 15:24:12 +01:00
Scott Rifenbark
babe0fa137 documentation: dev-manual - fixed KSRC variable in example
(From yocto-docs rev: 1eb13259c872e3a497b9ec32efac8c5614153a53)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-10 15:24:12 +01:00
Scott Rifenbark
5647682c2f documentation: dev-manual - added OE_INIT_FILE and went to 3.4
In the Kernel example appendix I changed some remaining 3.2
kernel strings to 3.4.  Also I added the OE_INIT_FILE variable
from poky.ent for use instead of the "oe-init-build-env" string.

(From yocto-docs rev: 1d9d8d72d197bdd81756eed7fe1529f341de6089)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-10 15:24:12 +01:00
Scott Rifenbark
77b92b01ce documentation: dev-manual - Created generic figures
Each time the kernel revision is bumped (e.g. 3.2 to 3.4)
Some of the figures would be out of date.  The reason is they
had pathnames that included the release of the kernel.
For previous YP releases I was adding logic to the Makefile
to be sure to catch the right files dependent on the branch
from which the documents were being built.  This scheme is
not scalable so I decided to make the figures generic by
adding a note within the figures explaining the place-holder
"<x.x>" as part of a pathname.  Thus, three new figures were
added to the folders directories of the dev-manual and the
mega-manual.  Correspondingly, the 'denzil' version of the
figures were deleted.

I modified the Makefile so that if the BRANCH is not edison
or denzil then the generic figure set is used. I have to retain
the logic for both edison and denzil to cover the case where
a user clones or sets up an edison or denzil repo and then
builds out the manuals. Basically, it had to be backwards
compatible for releases prior to danny.

(From yocto-docs rev: 8283eed4b0b9ec164b87db99c35231f8731ac443)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-10 15:24:12 +01:00
Scott Rifenbark
0a4f7521bb documentation: dev-manual - Edits to setup part of example
Minor edits to the part of the example that sets up for the
first core-image-minimal build.  Put in the variable to use
for the build environment setup script, updated some changed
output from some of the commands, etc.

(From yocto-docs rev: 0b4b2ddf9a78a9d6d218ed9a6f0acd3e876d9581)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-10 15:24:12 +01:00
Scott Rifenbark
c1261f843e documentation: dev-manual - fixed some links to the source directory term.
(From yocto-docs rev: 807a9f0d216478877b84e6204d88461f623ba3f9)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-10 15:24:12 +01:00
Scott Rifenbark
e3a3bdd81f documentation: Makefile, dev-manual - Updated kernel example repo figure
Danny, the "kernel-example-repo-<release>.png" file changed to
"kernel-example-repo-danny.png".  To correctly make the dev-manual
and the mega-manual some things needed to change:

1. New figure created and added to both the dev-manual and the
   mega-manuals figures directory.

2. The "kernel-example-repo-denzil.png" files from the dev-manual
   and mega-manual figures directory was removed.

3. The Makefile was adjusted so a new BRANCH=danny area now exists
   to set TARFILES for both dev-manual and mega-manual.

(From yocto-docs rev: 8b2ff6b657a1486559799e219baaec9fde2e5c6c)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-10 15:24:12 +01:00
Scott Rifenbark
a8def2777c documentation: dev-manual - Added a note to point to yocto-kernel
I added a note at the beginning of this appendix that references
the yocto-kernel script as a way to quickly manage kernel patches
and configuration.

(From yocto-docs rev: 35cd7f6a9722120e47ae8b422dd86593497ebf1c)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-10 15:24:12 +01:00
Scott Rifenbark
9884bc2d48 documentation: poky-ref-manual, yocto-project-qs - Packages fixed
Fixes [YOCTO_#3180]

Final changes to the packages section.  They were re-organized and
the set is complete and thus fixes this bug.

(From yocto-docs rev: 533b45c9d41330497bbd0da58b812a4738ba64a8)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-10 15:24:11 +01:00
Otavio Salvador
2f1b47e416 oe-buildenv-internal: Add BB_NO_NETWORK to BB_ENV_EXTRAWHITE
This allows for use of bitbake in offline mode, but override it in
command line.

(From OE-Core rev: bcefd015fb163d9c382ae05a86569dbcfd3d736a)

Signed-off-by: Otavio Salvador <otavio@ossystems.com.br>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-10 15:24:11 +01:00
Saul Wold
016d00123a pulseaudio: ensure X11 and consolekit are disabled
When DISTRO_FEATURES does not include X11 ensure that both x11
and gtk are diabled correctly.  ConsoleKit also has x11, so ensure
that any RDEPENDS is also excluded.

The flags for x11 changed at somepoint to use enable/disable, but
this recipe was not updated.

(From OE-Core rev: 0730d3449aa28600488e73de883240ba2bd60aec)

Signed-off-by: Saul Wold <sgw@linux.intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-10 15:24:11 +01:00
Mark Hatle
fdabda6345 package_rpm.bbclass: Fix an issue where complementary installs fail
Also ensure that we always cleanup the temporary install manifest files,
some of them will cause problems if they exist in multiple install
attempts.

Finally verify that the lists remain uniquely sorted otherwise the
complementary install may install the same files numerous times,
triggering a failure.

(From OE-Core rev: 4f2a290cbcc6c21afbb2a6e6148efdef4d135b41)

Signed-off-by: Mark Hatle <mark.hatle@windriver.com>
Signed-off-by: Saul Wold <sgw@linux.intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-10 15:24:11 +01:00
Richard Purdie
99dabeb2e9 sstate: Add extra entries to the sstate duplicate files whitelist
This avoids errors where gcc/binutils get installed to the native sysroot
in the same location for multiple package architectures. Ultimately making
these native recipes with ${PACKAGE_ARCH} appended to PN will resolve this
but hide the warnings until this gets sorted out.

Also hide the python and docbook catalog warnings since they're known about,
nothing to worry about and we'll aim to clean them up properly in the 1.4 cycle.

(From OE-Core rev: 5bae58a5b59c04d8947f4842f19837a914c29b52)

Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-10 15:24:11 +01:00
Richard Purdie
f56a4774a9 sstate: Normalise paths before comparing with the whitelist
Without this, path components like // could break comparisions with the whitelist leading
to warnings being displayed to the user unintentionally.

(From OE-Core rev: d3c46ca56fab2f07bf16b61514f30765543a8747)

Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-10 15:24:11 +01:00
Richard Purdie
4a4cdae234 libdrm: Explicitly disable the cairo dependency
We don't want the cairo dependency. Unfortunately simply checking whether its present
isn't good enough. If its not in DEPENDS, it can disappear half way through building.
We therefore need to explictly disable it.

(From OE-Core rev: 51df11c5747f69b4112121df78fc1e10644d390a)

Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-10 15:24:11 +01:00
Saul Wold
7396cef1b9 poky.conf: fix Poky release info to include release number
(From meta-yocto rev: 4287c2199443b41da3e5637a844f886513d92bc0)

Signed-off-by: Saul Wold <sgw@linux.intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-10 15:22:53 +01:00
Khem Raj
6676fb5e32 toolchain-scripts.bbclass: Export M4
some packages use M4 variable from environment and sometimes
its hardcoded to /usr/bin/m4 if not found in environment. Lets
define it such that it is picked from path

(From OE-Core rev: 06c5593d15f206458b9a5b45ed1229abfee16e95)

Signed-off-by: Khem Raj <raj.khem@gmail.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-10 15:21:41 +01:00
Laurentiu Palcu
be11294d17 cross-canadian.bbclass: add native chrpath dependency
In order for the RPATHs in 32bit toolchain binaries to be relocated
properly, chrpath >=0.14 is needed.

[YOCTO #3161]
[YOCTO #3201]

(From OE-Core rev: 71c71b972100803d33fbb062a237e8a15167387b)

Signed-off-by: Laurentiu Palcu <laurentiu.palcu@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-10 15:21:41 +01:00
Scott Garman
2d93461815 runqemu: allow multiple unfs instances to run simultaneously
A miscalculation in the way the port numbers of mountd and nfsd
are created was causing conflicts when starting multiple instances
of qemu using userspace nfs.

Thanks to Rudolf Streif for proposing this fix!

Fixes [YOCTO #1969]

(From OE-Core rev: 94eef772c283170d19ba92c8de0054cd093fc487)

Signed-off-by: Scott Garman <scott.a.garman@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-10 15:21:41 +01:00
Scott Garman
1e9d77c3b2 runqemu-export-rootfs: improve rpcbind error detection
mountd requires rpcbind or portmap. Check that one of these
services is running before doing anything else, and report
a user-friendly error when they are not found.

(From OE-Core rev: 16d6ec51f4b976c9b86a8b6bf6251089df2d2732)

Signed-off-by: Scott Garman <scott.a.garman@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-10 15:21:41 +01:00
Scott Garman
3634379cea runqemu-export-rootfs: use consistent whitespace
(From OE-Core rev: b05185240669e0ae811a23620913b35ca99493fb)

Signed-off-by: Scott Garman <scott.a.garman@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-10 15:21:41 +01:00
Flanagan, Elizabeth
43c4cdb0df common-licenses: Adding bzip
bzip requires it's own specific license.

(From OE-Core rev: df2b756436b90f8f9ff229ba64d0af30d9d4f923)

Signed-off-by: Elizabeth Flanagan <elizabeth.flanagan@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-10 15:21:41 +01:00
Scott Rifenbark
28c39928d3 documentation: dev-manual - Removed Appendix A.
This appendix is antiquated and needed removed.  The BSP
development example is now in the BSP guide where it talks
about running the yocto-bsp script.

(From yocto-docs rev: 892ff450d79a7564a72f11eb7510d349ca71d47a)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-10 15:21:41 +01:00
Scott Rifenbark
703eadc55f documentation: bsp-guide, dev-manual, kernel-manual - Removed links
Removing the Appendix A (BSP) example had some rippling affects
throughout the doc set.  There were several links into the appendix.
All these links had to either be modified (if possible) or simply
removed since the appendix will be removed.

(From yocto-docs rev: fff35abd87e945de1806eef63a56a956d104bf92)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-10 15:21:40 +01:00
Scott Rifenbark
e7134d50f3 documentation: dev-manual - Updated BSP flow overview.
This section now points into the BSP Guide where it talks
about using the yocto-bsp script to create a BSP.  The prior
method was by hand and described in an appendix (A) of the
YP Development Manual.

FYI - this results in the removal of Appendex A in a future
commit.

(From yocto-docs rev: 5e1c44b1768b79dd1447ea47461b84248bd2111f)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-10 15:21:40 +01:00
Scott Rifenbark
ddef53b962 documentation: poky-ref-manual, yocto-project-qs - Updates to packages
A few edits to the respective sections that talk about required
packages.  Some wording changes for headless and graphics
supported systems.  Also, re-inserted the note about older
CentOS systems.

Reported-by Paul Eggleton <paul.eggleton>
(From yocto-docs rev: 112370758cf41104ff04c4996d4a432e6bd54be1)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-10 15:21:40 +01:00
Scott Rifenbark
c1392638ce documentation: bsp-guide - scrub edits for the BSP Tools section
I did a walk through of the "Using the Yocto Project's BSP Tools"
section.  Updated included altered output based on the current
example commands and scenarios.

Also made changes to the bblayers.conf file as the default
version for this file has changed.

(From yocto-docs rev: d8a2195e37d8f96702026e42bb43daf39852ffcb)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-10 15:21:40 +01:00
Scott Rifenbark
fbd21995ae documentation: dev-manual, poky-ref-manual - updated bblayers.conf
The examples were out of date.  They did not show the
meta-yocto-bsp layer, which is there now by default.

(From yocto-docs rev: ea2e2e8a259bc3e629fb8087229872b9818a696a)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-10 15:21:40 +01:00
Scott Rifenbark
9e21f5b114 documentation: dev-manual - Updated Enabling Your Layer section
This section was out of date.  I copied in the most recent version
of the bblayers.conf file, which sets LCONF_VERSION to "6" now.
Also, added the meta-yocto-bsp layer to the example.

Additionally, I inserted a Note explaining the consequences of
removing the meta-yocto layer.  The note references [YOCTO_#3176]
for more information.

(From yocto-docs rev: 532b72c5c18b2a9a61619164bae6216c91c2ecc9)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-10 15:21:40 +01:00
Scott Rifenbark
b5ad96f86b documentation: dev-manual - updated LCONF_VERSION in the example.
The current setting was changed from "1" to "6".

(From yocto-docs rev: 7f5be4b0b2d1e17add774c7ba3b8803ad770a8fc)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-10 15:21:40 +01:00
Scott Rifenbark
33dcf6960b documentation: dev-manual - Updated bblayers.conf example
Added the meta-yocto-bsp layer to the example listing in the
"Enabling Your Layer" section.

(From yocto-docs rev: 95fb13a1049ccaffb3531c93a28a3c480ea1a243)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-10 15:21:40 +01:00
Scott Rifenbark
5979f64829 documentation: poky-ref-manual - Updated BBLAYERS variable.
Added the meta-yocto-bsp layer to the example.

(From yocto-docs rev: be4ee9d08527b654071b8d4ff54ad978f50a98f5)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-10 15:21:40 +01:00
Scott Rifenbark
b0ac293871 documentation: bsp-guide - Changed Source Directory capitalization.
The term should be initially capitalized.

(From yocto-docs rev: 38a11d512bfe675319fb76da9d7618315af91c47)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-10 15:21:40 +01:00
Scott Rifenbark
6915004b18 documentation: yocto-project-qs, yocto-project-ref - package re-org
Reorganization of the packages section in the YP Quick Start.
These are now ordered still by distro but the listed packages
have been culled down to just the needed ones to run an
image on QEMU with graphical support.

A corresponding section in the reference manual now provides
the comprehensive list of packages for all supported distros.
The section in the reference manual is broken down by
distro and by function.

Finally, four new variables were introduced to track the
essential packages for each of the distros.  The variables
are defined in poky.ent and follow the form
<distro>_HOST_PACKAGES_ESSENTIAL.  This will make it so
we don't have to maintain this list of essential packages
in multiple places.

Reported-by: Paul Eggleton <paul.eggleton@intel.com>
(From yocto-docs rev: 839b441791980db82f4795454e976e606b486d25)

Signed-off-by: Scott Rifenbark <scott.m.rifenbark@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-10 15:21:40 +01:00
Saul Wold
90d45f4264 distro_alias: Update for 1.3 BOM Creation
Fixed Ordering of packagegroup
Added entries for qemu-config split
Added entries for new packages, anotated approved packages

(From meta-yocto rev: 2c50e628aa6735156071f53d617938e610370b6f)

Signed-off-by: Saul Wold <sgw@linux.intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-10 15:21:40 +01:00
Constantin Musca
eb1782f715 bitbake: hob/hobeventhandler: Throw an exception if runCommand fails
- throw a Hob exception if runCommand returns 'Busy' or
'No such command'

[YOCTO #1245]

(Bitbake rev: 5a8e3baa66f845599a616f080a7efce81ecda631)

Signed-off-by: Constantin Musca <constantinx.musca@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-10 15:21:40 +01:00
Paul Eggleton
503023dd69 build-appliance-image: Fix spacing in DESCRIPTION
Fixes [YOCTO #2636]

(From OE-Core rev: 831b88806a3cb0125003aa6d3348716bcfd662a1)

Signed-off-by: Paul Eggleton <paul.eggleton@linux.intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-10 15:21:39 +01:00
Ross Burton
1164f70c34 shutdown-desktop: ensure the postinst script succeeds
When the hostname isn't qemuarm the grep fails so the postinst fails. Stop this
happening by explicitly evaluating true.

[YOCTO #3224]

(From OE-Core rev: 8848ea6793ddaab61c9dad250ec578d68d7d087d)

Signed-off-by: Ross Burton <ross.burton@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-10 15:21:39 +01:00
Ross Burton
31e19a34a5 sato-icon-theme: use gtk-icon-cache helper class
Instead of explicitly updating the icon cache use the helper class that also
forces a loader update at the same time.  This eliminates the possibility of
updating the icon cache without any gdk-pixbuf loaders.

Also check that the Sato icon theme isn't already set to avoid appending to the
file every time the postinst runs.

[YOCTO #2399]

(From OE-Core rev: 9d98dbdae4c05fcf50d546f554a04dc3f0bd66c3)

Signed-off-by: Ross Burton <ross.burton@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-10-10 15:21:39 +01:00
Elizabeth Flanagan
86c9aa8081 build-appliance: Flipping SRCREV
Assigning the SRCREV of build appliance to the most recent version
in the danny branch

Signed-off-by: Elizabeth Flanagan <elizabeth.flanagan@intel.com>
2012-10-03 11:01:51 -07:00
Elizabeth Flanagan
ef5298eebd poky.conf: Flipping for release of Danny (Poky 1.3)
8.0/1.3 release. Flipping poky.conf values

Signed-off-by: Elizabeth Flanagan <elizabeth.flanagan@intel.com>
2012-10-03 10:57:44 -07:00
2626 changed files with 58198 additions and 109437 deletions

8
.gitignore vendored
View File

@@ -6,18 +6,12 @@ pyshtables.py
pstage/
scripts/oe-git-proxy-socks
sources/
meta-*/
meta-*
!meta-skeleton
!meta-hob
hob-image-*.bb
*.swp
*.orig
*.rej
*~
!meta-yocto
!meta-yocto-bsp
bitbake/doc/manual/html/
bitbake/doc/manual/pdf/
bitbake/doc/manual/txt/
bitbake/doc/manual/xhtml/
pull-*/

View File

@@ -1,34 +1,28 @@
Poky Hardware README
====================
This file gives details about using Poky with the reference machines
supported out of the box. A full list of supported reference target machines
can be found by looking in the following directories:
meta/conf/machine/
meta-yocto-bsp/conf/machine/
If you are in doubt about using Poky/OpenEmbedded with your hardware, consult
the documentation for your board/device.
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
looking in the meta/conf/machine/ directory. If in doubt about using Poky with
your hardware, consult the documentation for your board/device.
Support for additional devices is normally added by creating BSP layers - for
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/documentation
http://yoctoproject.org/community/documentation
Support for physical reference hardware has now been split out into a
meta-yocto-bsp layer which can be removed separately from other layers if not
needed.
Support for machines other than QEMU may be moved out to separate BSP layers in
future versions.
QEMU Emulation Targets
======================
To simplify development, the build system supports building images to
work with the QEMU emulator in system emulation mode. Several architectures
are currently supported:
To simplify development Poky supports building images to work with the QEMU
emulator in system emulation mode. Several architectures are currently
supported:
* ARM (qemuarm)
* x86 (qemux86)
@@ -36,33 +30,32 @@ are currently supported:
* PowerPC (qemuppc)
* MIPS (qemumips)
Use of the QEMU images is covered in the Yocto Project Reference Manual.
The appropriate MACHINE variable value corresponding to the target is given
in brackets.
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
=========================
The following boards are supported by the meta-yocto-bsp layer:
The following boards are supported by Poky's core layer:
* Texas Instruments Beagleboard (beagleboard)
* Freescale MPC8315E-RDB (mpc8315e-rdb)
* Ubiquiti Networks RouterStation Pro (routerstationpro)
For more information see the board's section below. The appropriate MACHINE
variable value corresponding to the board is given in brackets.
For more information see the board's section below. The Poky MACHINE setting
corresponding to the board is given in brackets.
Consumer Devices
================
The following consumer devices are supported by the meta-yocto-bsp layer:
The following consumer devices are supported by Poky's core layer:
* Intel Atom based PCs and devices (atom-pc)
For more information see the device's section below. The appropriate MACHINE
variable value corresponding to the device is given in brackets.
For more information see the device's section below. The Poky MACHINE setting
corresponding to the device is given in brackets.
@@ -85,7 +78,7 @@ supports ethernet, wifi, sound, and i915 graphics by default in addition to
common PC input devices, busses, and so on.
Depending on the device, it can boot from a traditional hard-disk, a USB device,
or over the network. Writing generated images to physical media is
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.
@@ -138,7 +131,7 @@ USB Device:
device stops flashing, remove and reinsert the device to allow the
kernel to detect the new partition layout.
c. Copy the contents of the image to the USB-ZIP mode device:
c. Copy the contents of the poky image to the USB-ZIP mode device:
# mkdir /tmp/image
# mkdir /tmp/usbkey
@@ -288,8 +281,8 @@ anything here.
Load the kernel and dtb (device tree blob), and boot the system as follows:
1. Get the kernel (uImage-mpc8315e-rdb.bin) and dtb (uImage-mpc8315e-rdb.dtb)
files from the tmp/deploy directory, and make them available on your TFTP
server.
files from the Poky build tmp/deploy directory, and make them available on
your TFTP server.
2. Connect the board's first serial port to your workstation and then start up
your favourite serial terminal so that you will be able to interact with
@@ -308,9 +301,9 @@ Load the kernel and dtb (device tree blob), and boot the system as follows:
5. Download the kernel and dtb, and boot:
=> tftp 1000000 uImage-mpc8315e-rdb.bin
=> tftp 2000000 uImage-mpc8315e-rdb.dtb
=> bootm 1000000 - 2000000
=> tftp 800000 uImage-mpc8315e-rdb.bin
=> tftp 780000 uImage-mpc8315e-rdb.dtb
=> bootm 800000 - 780000
Ubiquiti Networks RouterStation Pro (routerstationpro)

View File

@@ -39,15 +39,10 @@ import bb.msg
from bb import cooker
from bb import ui
from bb import server
from bb import cookerdata
__version__ = "1.19.0"
__version__ = "1.16.0"
logger = logging.getLogger("BitBake")
# Python multiprocessing requires /dev/shm
if not os.access('/dev/shm', os.W_OK | os.X_OK):
sys.exit("FATAL: /dev/shm does not exist or is not writable")
# Unbuffer stdout to avoid log truncation in the event
# of an unorderly exit as well as to provide timely
# updates to log files for use with tail
@@ -57,6 +52,16 @@ try:
except:
pass
class BBConfiguration(object):
"""
Manages build options and configurations for one run
"""
def __init__(self, options):
for key, val in options.__dict__.items():
setattr(self, key, val)
self.pkgs_to_build = []
def get_ui(config):
if not config.ui:
@@ -70,23 +75,11 @@ def get_ui(config):
# 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)
return getattr(module, interface).main
except AttributeError:
sys.exit("FATAL: Invalid user interface '%s' specified.\n"
"Valid interfaces: depexp, goggle, ncurses, hob, knotty [default]." % interface)
def gather_extra_cache_data():
extra = []
interfaces = ['depexp', 'goggle', 'ncurses', 'hob', 'knotty']
for i in interfaces:
try:
ui = __import__("bb.ui." + i, fromlist = [i])
if hasattr(ui, "extraCaches"):
extra = extra + ui.extraCaches
del ui
except:
pass
return extra
# Display bitbake/OE warnings via the BitBake.Warnings logger, ignoring others"""
warnlog = logging.getLogger("BitBake.Warnings")
@@ -107,208 +100,165 @@ warnings.filterwarnings("ignore", category=ImportWarning)
warnings.filterwarnings("ignore", category=DeprecationWarning, module="<string>$")
warnings.filterwarnings("ignore", message="With-statements now directly support multiple context managers")
class BitBakeConfigParameters(cookerdata.ConfigParameters):
def parseCommandLine(self):
parser = optparse.OptionParser(
version = "BitBake Build Tool Core version %s, %%prog version %s" % (bb.__version__, __version__),
usage = """%prog [options] [package ...]
Executes the specified task (default is 'build') for a given set of BitBake files.
It expects that BBFILES is defined, which is a space separated list of files to
be executed. BBFILES does support wildcards.
Default BBFILES are the .bb files in the current directory.""")
parser.add_option("-b", "--buildfile", help = "execute the task against this .bb file, rather than a package from BBFILES. Does not handle any dependencies.",
action = "store", dest = "buildfile", default = None)
parser.add_option("-k", "--continue", help = "continue as much as possible after an error. While the target that failed, and those that depend on it, cannot be remade, the other dependencies of these targets can be processed all the same.",
action = "store_false", dest = "abort", default = True)
parser.add_option("-a", "--tryaltconfigs", help = "continue with builds by trying to use alternative providers where possible.",
action = "store_true", dest = "tryaltconfigs", default = False)
parser.add_option("-f", "--force", help = "force run of specified cmd, regardless of stamp status",
action = "store_true", dest = "force", default = False)
parser.add_option("-c", "--cmd", help = "Specify task to execute. Note that this only executes the specified task for the providee and the packages it depends on, i.e. 'compile' does not implicitly call stage for the dependencies (IOW: use only if you know what you are doing). Depending on the base.bbclass a listtasks tasks is defined and will show available tasks",
action = "store", dest = "cmd")
parser.add_option("-C", "--clear-stamp", help = "Invalidate the stamp for the specified cmd such as 'compile' and run the default task for the specified target(s)",
action = "store", dest = "invalidate_stamp")
parser.add_option("-r", "--read", help = "read the specified file before bitbake.conf",
action = "append", dest = "prefile", default = [])
parser.add_option("-R", "--postread", help = "read the specified file after bitbake.conf",
action = "append", dest = "postfile", default = [])
parser.add_option("-v", "--verbose", help = "output more chit-chat to the terminal",
action = "store_true", dest = "verbose", default = False)
parser.add_option("-D", "--debug", help = "Increase the debug level. You can specify this more than once.",
action = "count", dest="debug", default = 0)
parser.add_option("-n", "--dry-run", help = "don't execute, just go through the motions",
action = "store_true", dest = "dry_run", default = False)
parser.add_option("-S", "--dump-signatures", help = "don't execute, just dump out the signature construction information",
action = "store_true", dest = "dump_signatures", default = False)
parser.add_option("-p", "--parse-only", help = "quit after parsing the BB files (developers only)",
action = "store_true", dest = "parse_only", default = False)
parser.add_option("-s", "--show-versions", help = "show current and preferred versions of all recipes",
action = "store_true", dest = "show_versions", default = False)
parser.add_option("-e", "--environment", help = "show the global or per-package environment (this is what used to be bbread)",
action = "store_true", dest = "show_environment", default = False)
parser.add_option("-g", "--graphviz", help = "emit the dependency trees of the specified packages in the dot syntax, and the pn-buildlist to show the build list",
action = "store_true", dest = "dot_graph", default = False)
parser.add_option("-I", "--ignore-deps", help = """Assume these dependencies don't exist and are already provided (equivalent to ASSUME_PROVIDED). Useful to make dependency graphs more appealing""",
action = "append", dest = "extra_assume_provided", default = [])
parser.add_option("-l", "--log-domains", help = """Show debug logging for the specified logging domains""",
action = "append", dest = "debug_domains", default = [])
parser.add_option("-P", "--profile", help = "profile the command and print a report",
action = "store_true", dest = "profile", default = False)
parser.add_option("-u", "--ui", help = "userinterface to use",
action = "store", dest = "ui")
parser.add_option("-t", "--servertype", help = "Choose which server to use, process or xmlrpc",
action = "store", dest = "servertype")
parser.add_option("", "--revisions-changed", help = "Set the exit code depending on whether upstream floating revisions have changed or not",
action = "store_true", dest = "revisions_changed", default = False)
parser.add_option("", "--server-only", help = "Run bitbake without UI, the frontend can connect with bitbake server itself",
action = "store_true", dest = "server_only", default = False)
parser.add_option("-B", "--bind", help = "The name/address for the bitbake server to bind to",
action = "store", dest = "bind", default = False)
parser.add_option("", "--no-setscene", help = "Do not run any setscene tasks, forces builds",
action = "store_true", dest = "nosetscene", default = False)
parser.add_option("", "--remote-server", help = "Connect to the specified server",
action = "store", dest = "remote_server", default = False)
options, targets = parser.parse_args(sys.argv)
return options, targets[1:]
def start_server(servermodule, configParams, configuration):
server = servermodule.BitBakeServer()
if configParams.bind:
server.initServer((configParams.bind, 0))
else:
server.initServer()
try:
configuration.setServerRegIdleCallback(server.getServerIdleCB())
cooker = bb.cooker.BBCooker(configuration)
server.addcooker(cooker)
server.saveConnectionDetails()
except Exception as e:
exc_info = sys.exc_info()
while True:
try:
import queue
except ImportError:
import Queue as queue
try:
event = server.event_queue.get(block=False)
except (queue.Empty, IOError):
break
if isinstance(event, logging.LogRecord):
logger.handle(event)
raise exc_info[1], None, exc_info[2]
server.detach()
return server
def main():
parser = optparse.OptionParser(
version = "BitBake Build Tool Core version %s, %%prog version %s" % (bb.__version__, __version__),
usage = """%prog [options] [package ...]
configParams = BitBakeConfigParameters()
configuration = cookerdata.CookerConfiguration()
configuration.setConfigParameters(configParams)
Executes the specified task (default is 'build') for a given set of BitBake files.
It expects that BBFILES is defined, which is a space separated list of files to
be executed. BBFILES does support wildcards.
Default BBFILES are the .bb files in the current directory.""")
ui_module = get_ui(configParams)
parser.add_option("-b", "--buildfile", help = "execute the task against this .bb file, rather than a package from BBFILES. Does not handle any dependencies.",
action = "store", dest = "buildfile", default = None)
# Server type can be xmlrpc or process currently, if nothing is specified,
parser.add_option("-k", "--continue", help = "continue as much as possible after an error. While the target that failed, and those that depend on it, cannot be remade, the other dependencies of these targets can be processed all the same.",
action = "store_false", dest = "abort", default = True)
parser.add_option("-a", "--tryaltconfigs", help = "continue with builds by trying to use alternative providers where possible.",
action = "store_true", dest = "tryaltconfigs", default = False)
parser.add_option("-f", "--force", help = "force run of specified cmd, regardless of stamp status",
action = "store_true", dest = "force", default = False)
parser.add_option("-c", "--cmd", help = "Specify task to execute. Note that this only executes the specified task for the providee and the packages it depends on, i.e. 'compile' does not implicitly call stage for the dependencies (IOW: use only if you know what you are doing). Depending on the base.bbclass a listtasks tasks is defined and will show available tasks",
action = "store", dest = "cmd")
parser.add_option("-C", "--clear-stamp", help = "Invalidate the stamp for the specified cmd such as 'compile' and run the default task for the specified target(s)",
action = "store", dest = "invalidate_stamp")
parser.add_option("-r", "--read", help = "read the specified file before bitbake.conf",
action = "append", dest = "prefile", default = [])
parser.add_option("-R", "--postread", help = "read the specified file after bitbake.conf",
action = "append", dest = "postfile", default = [])
parser.add_option("-v", "--verbose", help = "output more chit-chat to the terminal",
action = "store_true", dest = "verbose", default = False)
parser.add_option("-D", "--debug", help = "Increase the debug level. You can specify this more than once.",
action = "count", dest="debug", default = 0)
parser.add_option("-n", "--dry-run", help = "don't execute, just go through the motions",
action = "store_true", dest = "dry_run", default = False)
parser.add_option("-S", "--dump-signatures", help = "don't execute, just dump out the signature construction information",
action = "store_true", dest = "dump_signatures", default = False)
parser.add_option("-p", "--parse-only", help = "quit after parsing the BB files (developers only)",
action = "store_true", dest = "parse_only", default = False)
parser.add_option("-s", "--show-versions", help = "show current and preferred versions of all recipes",
action = "store_true", dest = "show_versions", default = False)
parser.add_option("-e", "--environment", help = "show the global or per-package environment (this is what used to be bbread)",
action = "store_true", dest = "show_environment", default = False)
parser.add_option("-g", "--graphviz", help = "emit the dependency trees of the specified packages in the dot syntax, and the pn-buildlist to show the build list",
action = "store_true", dest = "dot_graph", default = False)
parser.add_option("-I", "--ignore-deps", help = """Assume these dependencies don't exist and are already provided (equivalent to ASSUME_PROVIDED). Useful to make dependency graphs more appealing""",
action = "append", dest = "extra_assume_provided", default = [])
parser.add_option("-l", "--log-domains", help = """Show debug logging for the specified logging domains""",
action = "append", dest = "debug_domains", default = [])
parser.add_option("-P", "--profile", help = "profile the command and print a report",
action = "store_true", dest = "profile", default = False)
parser.add_option("-u", "--ui", help = "userinterface to use",
action = "store", dest = "ui")
parser.add_option("-t", "--servertype", help = "Choose which server to use, none, process or xmlrpc",
action = "store", dest = "servertype")
parser.add_option("", "--revisions-changed", help = "Set the exit code depending on whether upstream floating revisions have changed or not",
action = "store_true", dest = "revisions_changed", default = False)
parser.add_option("", "--server-only", help = "Run bitbake without UI, the frontend can connect with bitbake server itself",
action = "store_true", dest = "server_only", default = False)
parser.add_option("-B", "--bind", help = "The name/address for the bitbake server to bind to",
action = "store", dest = "bind", default = False)
parser.add_option("", "--no-setscene", help = "Do not run any setscene tasks, forces builds",
action = "store_true", dest = "nosetscene", default = False)
options, args = parser.parse_args(sys.argv)
configuration = BBConfiguration(options)
configuration.pkgs_to_build.extend(args[1:])
ui_main = get_ui(configuration)
# Server type can be xmlrpc, process or none currently, if nothing is specified,
# the default server is process
if configParams.servertype:
server_type = configParams.servertype
if configuration.servertype:
server_type = configuration.servertype
else:
server_type = 'process'
try:
module = __import__("bb.server", fromlist = [server_type])
servermodule = getattr(module, server_type)
server = getattr(module, server_type)
except AttributeError:
sys.exit("FATAL: Invalid server type '%s' specified.\n"
"Valid interfaces: xmlrpc, process [default]." % servertype)
"Valid interfaces: xmlrpc, process [default], none." % servertype)
if configParams.server_only:
if configParams.servertype != "xmlrpc":
if configuration.server_only:
if configuration.servertype != "xmlrpc":
sys.exit("FATAL: If '--server-only' is defined, we must set the servertype as 'xmlrpc'.\n")
if not configParams.bind:
if not configuration.bind:
sys.exit("FATAL: The '--server-only' option requires a name/address to bind to with the -B option.\n")
if configParams.bind and configParams.servertype != "xmlrpc":
if configuration.bind and configuration.servertype != "xmlrpc":
sys.exit("FATAL: If '-B' or '--bind' is defined, we must set the servertype as 'xmlrpc'.\n")
if configParams.remote_server and configParams.servertype != "xmlrpc":
sys.exit("FATAL: If '--remote-server' is defined, we must set the servertype as 'xmlrpc'.\n")
# Save a logfile for cooker into the current working directory. When the
# server is daemonized this logfile will be truncated.
cooker_logfile = os.path.join(os.getcwd(), "cooker.log")
if "BBDEBUG" in os.environ:
level = int(os.environ["BBDEBUG"])
if level > configuration.debug:
configuration.debug = level
bb.msg.init_msgconfig(configParams.verbose, configuration.debug,
bb.msg.init_msgconfig(configuration.verbose, configuration.debug,
configuration.debug_domains)
# Ensure logging messages get sent to the UI as events
handler = bb.event.LogHandler()
logger.addHandler(handler)
# Clear away any spurious environment variables while we stoke up the cooker
cleanedvars = bb.utils.clean_environment()
# Before we start modifying the environment we should take a pristine
# copy for possible later use
initialenv = os.environ.copy()
# Clear away any spurious environment variables. But don't wipe the
# environment totally. This is necessary to ensure the correct operation
# of the UIs (e.g. for DISPLAY, etc.)
bb.utils.clean_environment()
# Collect all the caches we need
if configParams.server_only:
configuration.extra_caches = gather_extra_cache_data()
server = server.BitBakeServer()
if configuration.bind:
server.initServer((configuration.bind, 0))
else:
configuration.extra_caches = getattr(ui_module, "extraCaches", [])
server.initServer()
if not configParams.remote_server:
# we start a server with a given configuration
server = start_server(servermodule, configParams, configuration)
else:
# we start a stub server that is actually a XMLRPClient to
server = servermodule.BitBakeXMLRPCClient()
server.saveConnectionDetails(configParams.remote_server)
idle = server.getServerIdleCB()
cooker = bb.cooker.BBCooker(configuration, idle, initialenv)
cooker.parseCommandLine()
server.addcooker(cooker)
server.saveConnectionDetails()
server.detach(cooker_logfile)
# Should no longer need to ever reference cooker
del cooker
logger.removeHandler(handler)
if not configParams.server_only:
if not configuration.server_only:
# Setup a connection to the server (cooker)
server_connection = server.establishConnection()
# Restore the environment in case the UI needs it
for k in cleanedvars:
os.environ[k] = cleanedvars[k]
try:
return ui_module.main(server_connection.connection, server_connection.events, configParams)
return server.launchUI(ui_main, server_connection.connection, server_connection.events)
finally:
bb.event.ui_queue = []
server_connection.terminate()
@@ -323,6 +273,6 @@ if __name__ == "__main__":
except Exception:
ret = 1
import traceback
traceback.print_exc()
traceback.print_exc(5)
sys.exit(ret)

View File

@@ -85,8 +85,8 @@ options, args = parser.parse_args(sys.argv)
if len(args) == 1:
parser.print_help()
else:
tinfoil = bb.tinfoil.Tinfoil()
if options.taskmode:
tinfoil = bb.tinfoil.Tinfoil()
if len(args) < 3:
logger.error("Please specify a recipe and task name")
sys.exit(1)

View File

@@ -26,7 +26,6 @@ import os
import sys
import fnmatch
from collections import defaultdict
import re
bindir = os.path.dirname(__file__)
topdir = os.path.dirname(bindir)
@@ -73,7 +72,7 @@ class Commands(cmd.Cmd):
else:
sys.stdout.write("usage: bitbake-layers <command> [arguments]\n\n")
sys.stdout.write("Available commands:\n")
procnames = list(set(self.get_names()))
procnames = self.get_names()
for procname in procnames:
if procname[:3] == 'do_':
sys.stdout.write(" %s\n" % procname[3:].replace('_', '-'))
@@ -89,7 +88,7 @@ class Commands(cmd.Cmd):
for layerdir in self.bblayers:
layername = self.get_layer_name(layerdir)
layerpri = 0
for layer, _, regex, pri in self.bbhandler.cooker.recipecache.bbfile_config_priorities:
for layer, _, regex, pri in self.bbhandler.cooker.status.bbfile_config_priorities:
if regex.match(os.path.join(layerdir, 'test')):
layerpri = pri
break
@@ -225,15 +224,15 @@ Options:
def list_recipes(self, title, pnspec, show_overlayed_only, show_same_ver_only, show_filenames, show_multi_provider_only):
pkg_pn = self.bbhandler.cooker.recipecache.pkg_pn
(latest_versions, preferred_versions) = bb.providers.findProviders(self.bbhandler.cooker.configuration.data, self.bbhandler.cooker.recipecache, pkg_pn)
allproviders = bb.providers.allProviders(self.bbhandler.cooker.recipecache)
pkg_pn = self.bbhandler.cooker.status.pkg_pn
(latest_versions, preferred_versions) = bb.providers.findProviders(self.bbhandler.cooker.configuration.data, self.bbhandler.cooker.status, pkg_pn)
allproviders = bb.providers.allProviders(self.bbhandler.cooker.status)
# Ensure we list skipped recipes
# We are largely guessing about PN, PV and the preferred version here,
# but we have no choice since skipped recipes are not fully parsed
skiplist = self.bbhandler.cooker.skiplist.keys()
skiplist.sort( key=lambda fileitem: self.bbhandler.cooker.collection.calc_bbfile_priority(fileitem) )
skiplist.sort( key=lambda fileitem: self.bbhandler.cooker.calc_bbfile_priority(fileitem) )
skiplist.reverse()
for fn in skiplist:
recipe_parts = os.path.splitext(os.path.basename(fn))[0].split('_')
@@ -371,8 +370,8 @@ build results (as the layer priority order has effectively changed).
appended_recipes = []
for layer in layers:
overlayed = []
for f in self.bbhandler.cooker.collection.overlayed.iterkeys():
for of in self.bbhandler.cooker.collection.overlayed[f]:
for f in self.bbhandler.cooker.overlayed.iterkeys():
for of in self.bbhandler.cooker.overlayed[f]:
if of.startswith(layer):
overlayed.append(of)
@@ -396,8 +395,8 @@ build results (as the layer priority order has effectively changed).
logger.warn('Overwriting file %s', fdest)
bb.utils.copyfile(f1full, fdest)
if ext == '.bb':
if f1 in self.bbhandler.cooker.collection.appendlist:
appends = self.bbhandler.cooker.collection.appendlist[f1]
if f1 in self.bbhandler.cooker.appendlist:
appends = self.bbhandler.cooker.appendlist[f1]
if appends:
logger.plain(' Applying appends to %s' % fdest )
for appendname in appends:
@@ -406,9 +405,9 @@ build results (as the layer priority order has effectively changed).
appended_recipes.append(f1)
# Take care of when some layers are excluded and yet we have included bbappends for those recipes
for recipename in self.bbhandler.cooker.collection.appendlist.iterkeys():
for recipename in self.bbhandler.cooker.appendlist.iterkeys():
if recipename not in appended_recipes:
appends = self.bbhandler.cooker.collection.appendlist[recipename]
appends = self.bbhandler.cooker.appendlist[recipename]
first_append = None
for appendname in appends:
layer = layer_path_match(appendname)
@@ -426,7 +425,7 @@ build results (as the layer priority order has effectively changed).
# have come from)
first_regex = None
layerdir = layers[0]
for layername, pattern, regex, _ in self.bbhandler.cooker.recipecache.bbfile_config_priorities:
for layername, pattern, regex, _ in self.bbhandler.cooker.status.bbfile_config_priorities:
if regex.match(os.path.join(layerdir, 'test')):
first_regex = regex
break
@@ -456,28 +455,13 @@ build results (as the layer priority order has effectively changed).
logger.warning("File %s does not match the flattened layer's BBFILES setting, you may need to edit conf/layer.conf or move the file elsewhere" % f1full)
def get_file_layer(self, filename):
for layer, _, regex, _ in self.bbhandler.cooker.recipecache.bbfile_config_priorities:
for layer, _, regex, _ in self.bbhandler.cooker.status.bbfile_config_priorities:
if regex.match(filename):
for layerdir in self.bblayers:
if regex.match(os.path.join(layerdir, 'test')) and re.match(layerdir, filename):
if regex.match(os.path.join(layerdir, 'test')):
return self.get_layer_name(layerdir)
return "?"
def get_file_layerdir(self, filename):
for layer, _, regex, _ in self.bbhandler.cooker.recipecache.bbfile_config_priorities:
if regex.match(filename):
for layerdir in self.bblayers:
if regex.match(os.path.join(layerdir, 'test')) and re.match(layerdir, filename):
return layerdir
return "?"
def remove_layer_prefix(self, f):
"""Remove the layer_dir prefix, e.g., f = /path/to/layer_dir/foo/blah, the
return value will be: layer_dir/foo/blah"""
f_layerdir = self.get_file_layerdir(f)
prefix = os.path.join(os.path.dirname(f_layerdir), '')
return f[len(prefix):] if f.startswith(prefix) else f
def get_layer_name(self, layerdir):
return os.path.basename(layerdir.rstrip(os.sep))
@@ -498,7 +482,7 @@ usage: show-appends
Recipes are listed with the bbappends that apply to them as subitems.
"""
self.bbhandler.prepare()
if not self.bbhandler.cooker.collection.appendlist:
if not self.bbhandler.cooker.appendlist:
logger.plain('No append files found')
return
@@ -550,171 +534,13 @@ Recipes are listed with the bbappends that apply to them as subitems.
continue
basename = os.path.basename(filename)
appends = self.bbhandler.cooker.collection.appendlist.get(basename)
appends = self.bbhandler.cooker.appendlist.get(basename)
if appends:
appended.append((basename, list(appends)))
else:
notappended.append(basename)
return appended, notappended
def do_show_cross_depends(self, args):
"""figure out the dependency between recipes that crosses a layer boundary.
usage: show-cross-depends [-f]
Figure out the dependency between recipes that crosses a layer boundary.
Options:
-f show full file path
NOTE:
The .bbappend file can impact the dependency.
"""
self.bbhandler.prepare()
show_filenames = False
for arg in args.split():
if arg == '-f':
show_filenames = True
else:
sys.stderr.write("show-cross-depends: invalid option %s\n" % arg)
self.do_help('')
return
pkg_fn = self.bbhandler.cooker_data.pkg_fn
bbpath = str(self.bbhandler.config_data.getVar('BBPATH', True))
self.require_re = re.compile(r"require\s+(.+)")
self.include_re = re.compile(r"include\s+(.+)")
self.inherit_re = re.compile(r"inherit\s+(.+)")
# The bb's DEPENDS and RDEPENDS
for f in pkg_fn:
f = bb.cache.Cache.virtualfn2realfn(f)[0]
# Get the layername that the file is in
layername = self.get_file_layer(f)
# The DEPENDS
deps = self.bbhandler.cooker_data.deps[f]
for pn in deps:
if pn in self.bbhandler.cooker_data.pkg_pn:
best = bb.providers.findBestProvider(pn,
self.bbhandler.cooker.configuration.data,
self.bbhandler.cooker_data,
self.bbhandler.cooker_data.pkg_pn)
self.check_cross_depends("DEPENDS", layername, f, best[3], show_filenames)
# The RDPENDS
all_rdeps = self.bbhandler.cooker_data.rundeps[f].values()
# Remove the duplicated or null one.
sorted_rdeps = {}
# The all_rdeps is the list in list, so we need two for loops
for k1 in all_rdeps:
for k2 in k1:
sorted_rdeps[k2] = 1
all_rdeps = sorted_rdeps.keys()
for rdep in all_rdeps:
all_p = bb.providers.getRuntimeProviders(self.bbhandler.cooker_data, rdep)
if all_p:
best = bb.providers.filterProvidersRunTime(all_p, rdep,
self.bbhandler.cooker.configuration.data,
self.bbhandler.cooker_data)[0][0]
self.check_cross_depends("RDEPENDS", layername, f, best, show_filenames)
# The inherit class
cls_re = re.compile('classes/')
if f in self.bbhandler.cooker_data.inherits:
inherits = self.bbhandler.cooker_data.inherits[f]
for cls in inherits:
# The inherits' format is [classes/cls, /path/to/classes/cls]
# ignore the classes/cls.
if not cls_re.match(cls):
inherit_layername = self.get_file_layer(cls)
if inherit_layername != layername:
if not show_filenames:
f_short = self.remove_layer_prefix(f)
cls = self.remove_layer_prefix(cls)
else:
f_short = f
logger.plain("%s inherits %s" % (f_short, cls))
# The 'require/include xxx' in the bb file
pv_re = re.compile(r"\${PV}")
fnfile = open(f, 'r')
line = fnfile.readline()
while line:
m, keyword = self.match_require_include(line)
# Found the 'require/include xxxx'
if m:
needed_file = m.group(1)
# Replace the ${PV} with the real PV
if pv_re.search(needed_file) and f in self.bbhandler.cooker_data.pkg_pepvpr:
pv = self.bbhandler.cooker_data.pkg_pepvpr[f][1]
needed_file = re.sub(r"\${PV}", pv, needed_file)
self.print_cross_files(bbpath, keyword, layername, f, needed_file, show_filenames)
line = fnfile.readline()
fnfile.close()
# The "require/include xxx" in conf/machine/*.conf, .inc and .bbclass
conf_re = re.compile(".*/conf/machine/[^\/]*\.conf$")
inc_re = re.compile(".*\.inc$")
# The "inherit xxx" in .bbclass
bbclass_re = re.compile(".*\.bbclass$")
for layerdir in self.bblayers:
layername = self.get_layer_name(layerdir)
for dirpath, dirnames, filenames in os.walk(layerdir):
for name in filenames:
f = os.path.join(dirpath, name)
s = conf_re.match(f) or inc_re.match(f) or bbclass_re.match(f)
if s:
ffile = open(f, 'r')
line = ffile.readline()
while line:
m, keyword = self.match_require_include(line)
# Only bbclass has the "inherit xxx" here.
bbclass=""
if not m and f.endswith(".bbclass"):
m, keyword = self.match_inherit(line)
bbclass=".bbclass"
# Find a 'require/include xxxx'
if m:
self.print_cross_files(bbpath, keyword, layername, f, m.group(1) + bbclass, show_filenames)
line = ffile.readline()
ffile.close()
def print_cross_files(self, bbpath, keyword, layername, f, needed_filename, show_filenames):
"""Print the depends that crosses a layer boundary"""
needed_file = bb.utils.which(bbpath, needed_filename)
if needed_file:
# Which layer is this file from
needed_layername = self.get_file_layer(needed_file)
if needed_layername != layername:
if not show_filenames:
f = self.remove_layer_prefix(f)
needed_file = self.remove_layer_prefix(needed_file)
logger.plain("%s %s %s" %(f, keyword, needed_file))
def match_inherit(self, line):
"""Match the inherit xxx line"""
return (self.inherit_re.match(line), "inherits")
def match_require_include(self, line):
"""Match the require/include xxx line"""
m = self.require_re.match(line)
keyword = "requires"
if not m:
m = self.include_re.match(line)
keyword = "includes"
return (m, keyword)
def check_cross_depends(self, keyword, layername, f, needed_file, show_filenames):
"""Print the DEPENDS/RDEPENDS file that crosses a layer boundary"""
best_realfn = bb.cache.Cache.virtualfn2realfn(needed_file)[0]
needed_layername = self.get_file_layer(best_realfn)
if needed_layername != layername:
if not show_filenames:
f = self.remove_layer_prefix(f)
best_realfn = self.remove_layer_prefix(best_realfn)
logger.plain("%s %s %s" % (f, keyword, best_realfn))
if __name__ == '__main__':
sys.exit(main(sys.argv[1:]) or 0)

119
bitbake/bin/bitbake-runtask Executable file
View File

@@ -0,0 +1,119 @@
#!/usr/bin/env python
import os
import sys
import warnings
sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(sys.argv[0])), 'lib'))
from bb import fetch2
import logging
logger = logging.getLogger("BitBake")
try:
import cPickle as pickle
except ImportError:
import pickle
bb.msg.note(1, bb.msg.domain.Cache, "Importing cPickle failed. Falling back to a very slow implementation.")
class BBConfiguration(object):
"""
Manages build options and configurations for one run
"""
def __init__(self, **options):
self.data = {}
self.file = []
self.cmd = None
self.dump_signatures = True
self.prefile = []
self.postfile = []
self.parse_only = True
def __getattr__(self, attribute):
try:
return super(BBConfiguration, self).__getattribute__(attribute)
except AttributeError:
return None
_warnings_showwarning = warnings.showwarning
def _showwarning(message, category, filename, lineno, file=None, line=None):
"""Display python warning messages using bb.msg"""
if file is not None:
if _warnings_showwarning is not None:
_warnings_showwarning(message, category, filename, lineno, file, line)
else:
s = warnings.formatwarning(message, category, filename, lineno)
s = s.split("\n")[0]
bb.msg.warn(None, s)
warnings.showwarning = _showwarning
warnings.simplefilter("ignore", DeprecationWarning)
import bb.event
import bb.cooker
buildfile = sys.argv[1]
taskname = sys.argv[2]
if len(sys.argv) >= 4:
dryrun = sys.argv[3]
else:
dryrun = False
if len(sys.argv) >= 5:
hashfile = sys.argv[4]
p = pickle.Unpickler(file(hashfile, "rb"))
hashdata = p.load()
else:
hashdata = None
handler = bb.event.LogHandler()
logger.addHandler(handler)
#An example to make debug log messages show up
#bb.msg.init_msgconfig(True, 3, [])
console = logging.StreamHandler(sys.stdout)
format = bb.msg.BBLogFormatter("%(levelname)s: %(message)s")
bb.msg.addDefaultlogFilter(console)
console.setFormatter(format)
def worker_fire(event, d):
if isinstance(event, logging.LogRecord):
console.handle(event)
bb.event.worker_fire = worker_fire
bb.event.worker_pid = os.getpid()
initialenv = os.environ.copy()
config = BBConfiguration()
def register_idle_function(self, function, data):
pass
cooker = bb.cooker.BBCooker(config, register_idle_function, initialenv)
config_data = cooker.configuration.data
cooker.status = config_data
cooker.handleCollections(config_data.getVar("BBFILE_COLLECTIONS", 1))
fn, cls = bb.cache.Cache.virtualfn2realfn(buildfile)
buildfile = cooker.matchFile(fn)
fn = bb.cache.Cache.realfn2virtual(buildfile, cls)
cooker.buildSetVars()
# Load data into the cache for fn and parse the loaded cache data
the_data = bb.cache.Cache.loadDataFull(fn, cooker.get_file_appends(fn), cooker.configuration.data)
if taskname.endswith("_setscene"):
the_data.setVarFlag(taskname, "quieterrors", "1")
if hashdata:
bb.parse.siggen.set_taskdata(hashdata["hashes"], hashdata["deps"])
for h in hashdata["hashes"]:
the_data.setVar("BBHASH_%s" % h, hashdata["hashes"][h])
for h in hashdata["deps"]:
the_data.setVar("BBHASHDEPS_%s" % h, hashdata["deps"][h])
ret = 0
if dryrun != "True":
ret = bb.build.exec_task(fn, taskname, the_data)
sys.exit(ret)

View File

@@ -28,10 +28,8 @@ import gtk
import optparse
import pygtk
from bb.ui.crumbs.hig import DeployImageDialog, ImageSelectionDialog, CrumbsMessageDialog
from bb.ui.crumbs.hobwidget import HobAltButton, HobButton
from bb.ui.crumbs.hig.crumbsmessagedialog import CrumbsMessageDialog
from bb.ui.crumbs.hig.deployimagedialog import DeployImageDialog
from bb.ui.crumbs.hig.imageselectiondialog import ImageSelectionDialog
# I put all the fs bitbake supported here. Need more test.
DEPLOYABLE_IMAGE_TYPES = ["jffs2", "cramfs", "ext2", "ext3", "btrfs", "squashfs", "ubi", "vmdk"]

View File

@@ -10,8 +10,8 @@ if &compatible || version < 600
finish
endif
" .bb, .bbappend and .bbclass
au BufNewFile,BufRead *.{bb,bbappend,bbclass} set filetype=bitbake
" .bb and .bbclass
au BufNewFile,BufRead *.b{b,bclass} set filetype=bitbake
" .inc
au BufNewFile,BufRead *.inc set filetype=bitbake

View File

@@ -103,24 +103,6 @@ Show debug logging for the specified logging domains
.TP
.B \-P, \-\-profile
profile the command and print a report
.TP
.B \-uUI, \-\-ui=UI
User interface to use. Currently, hob, depexp, goggle or ncurses can be specified as UI.
.TP
.B \-tSERVERTYPE, \-\-servertype=SERVERTYPE
Choose which server to use, none, process or xmlrpc.
.TP
.B \-\-revisions-changed
Set the exit code depending on whether upstream floating revisions have changed or not.
.TP
.B \-\-server-only
Run bitbake without UI, the frontend can connect with bitbake server itself.
.TP
.B \-BBIND, \-\-bind=BIND
The name/address for the bitbake server to bind to.
.TP
.B \-\-no\-setscene
Do not run any setscene tasks, forces builds.
.SH ENVIRONMENT VARIABLES
bitbake uses the following environment variables to control its

View File

@@ -21,7 +21,7 @@
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
__version__ = "1.19.0"
__version__ = "1.16.0"
import sys
if sys.version_info < (2, 6, 0):
@@ -74,6 +74,11 @@ logger.setLevel(logging.DEBUG - 2)
# can result in construction of the various loggers.
import bb.msg
if "BBDEBUG" in os.environ:
level = int(os.environ["BBDEBUG"])
if level:
bb.msg.set_debug_level(level)
from bb import fetch2 as fetch
sys.modules['bb.fetch'] = sys.modules['bb.fetch2']

View File

@@ -29,7 +29,6 @@ import os
import sys
import logging
import shlex
import glob
import bb
import bb.msg
import bb.process
@@ -60,7 +59,7 @@ class FuncFailed(Exception):
def __str__(self):
if self.logfile and os.path.exists(self.logfile):
msg = ("%s (log file is located at %s)" %
msg = ("%s (see %s for further information)" %
(self.msg, self.logfile))
else:
msg = self.msg
@@ -275,8 +274,7 @@ def exec_func_shell(func, d, runfile, cwd=None):
bb.debug(2, "Executing shell function %s" % func)
try:
with open(os.devnull, 'r+') as stdin:
bb.process.run(cmd, shell=False, stdin=stdin, log=logfile)
bb.process.run(cmd, shell=False, stdin=NULL, log=logfile)
except bb.process.CmdError:
logfn = d.getVar('BB_LOGFILE', True)
raise FuncFailed(func, logfn)
@@ -320,11 +318,12 @@ def _exec_task(fn, task, d, quieterr):
# Document the order of the tasks...
logorder = os.path.join(tempdir, 'log.task_order')
try:
with open(logorder, 'a') as logorderfile:
logorderfile.write('{0} ({1}): {2}\n'.format(task, os.getpid(), logbase))
logorderfile = file(logorder, 'a')
except OSError:
logger.exception("Opening log file '%s'", logorder)
pass
logorderfile.write('{0} ({1}): {2}\n'.format(task, os.getpid(), logbase))
logorderfile.close()
# Setup the courtesy link to the logfn
loglink = os.path.join(tempdir, 'log.{0}'.format(task))
@@ -348,10 +347,10 @@ def _exec_task(fn, task, d, quieterr):
self.triggered = True
# Handle logfiles
si = open('/dev/null', 'r')
si = file('/dev/null', 'r')
try:
bb.utils.mkdirhier(os.path.dirname(logfn))
logfile = open(logfn, 'w')
logfile = file(logfn, 'w')
except OSError:
logger.exception("Opening log file '%s'", logfn)
pass
@@ -423,27 +422,13 @@ def _exec_task(fn, task, d, quieterr):
return 0
def exec_task(fn, task, d, profile = False):
def exec_task(fn, task, d):
try:
quieterr = False
if d.getVarFlag(task, "quieterrors") is not None:
quieterr = True
if profile:
profname = "profile-%s.log" % (os.path.basename(fn) + "-" + task)
try:
import cProfile as profile
except:
import profile
prof = profile.Profile()
ret = profile.Profile.runcall(prof, _exec_task, fn, task, d, quieterr)
prof.dump_stats(profname)
bb.utils.process_profilelog(profname)
return ret
else:
return _exec_task(fn, task, d, quieterr)
return _exec_task(fn, task, d, quieterr)
except Exception:
from traceback import format_exc
if not quieterr:
@@ -506,11 +491,9 @@ def stamp_cleanmask_internal(taskname, d, file_name):
extrainfo = d.getVarFlag(taskflagname, 'stamp-extra-info', True) or ""
if not stamp:
return []
return
cleanmask = bb.parse.siggen.stampcleanmask(stamp, file_name, taskname, extrainfo)
return [cleanmask, cleanmask.replace(taskflagname, taskflagname + "_setscene")]
return bb.parse.siggen.stampcleanmask(stamp, file_name, taskname, extrainfo)
def make_stamp(task, d, file_name = None):
"""
@@ -518,22 +501,16 @@ def make_stamp(task, d, file_name = None):
(d can be a data dict or dataCache)
"""
cleanmask = stamp_cleanmask_internal(task, d, file_name)
for mask in cleanmask:
for name in glob.glob(mask):
# Preserve sigdata files in the stamps directory
if "sigdata" in name:
continue
# Preserve taint files in the stamps directory
if name.endswith('.taint'):
continue
os.unlink(name)
if cleanmask:
bb.utils.remove(cleanmask)
stamp = stamp_internal(task, d, file_name)
# Remove the file and recreate to force timestamp
# change on broken NFS filesystems
if stamp:
bb.utils.remove(stamp)
open(stamp, "w").close()
f = open(stamp, "w")
f.close()
# If we're in task context, write out a signature file for each task
# as it completes
@@ -607,10 +584,9 @@ def add_tasks(tasklist, d):
getTask('noexec')
getTask('umask')
task_deps['parents'][task] = []
if 'deps' in flags:
for dep in flags['deps']:
dep = data.expand(dep, d)
task_deps['parents'][task].append(dep)
for dep in flags['deps']:
dep = data.expand(dep, d)
task_deps['parents'][task].append(dep)
# don't assume holding a reference
data.setVar('_task_deps', task_deps, d)

View File

@@ -119,6 +119,7 @@ class CoreRecipeInfo(RecipeInfoCommon):
self.basetaskhashes = self.taskvar('BB_BASEHASH', self.tasks, metadata)
self.hashfilename = self.getvar('BB_HASHFILENAME', metadata)
self.file_depends = metadata.getVar('__depends', False)
self.task_deps = metadata.getVar('_task_deps', False) or {'tasks': [], 'parents': {}}
self.skipped = False
@@ -126,6 +127,7 @@ class CoreRecipeInfo(RecipeInfoCommon):
self.pv = self.getvar('PV', metadata)
self.pr = self.getvar('PR', metadata)
self.defaultpref = self.intvar('DEFAULT_PREFERENCE', metadata)
self.broken = self.getvar('BROKEN', metadata)
self.not_world = self.getvar('EXCLUDE_FROM_WORLD', metadata)
self.stamp = self.getvar('STAMP', metadata)
self.stampclean = self.getvar('STAMPCLEAN', metadata)
@@ -232,7 +234,7 @@ class CoreRecipeInfo(RecipeInfoCommon):
# Collect files we may need for possible world-dep
# calculations
if not self.not_world:
if not self.broken and not self.not_world:
cachedata.possible_world.append(fn)
# create a collection of all targets for sanity checking
@@ -403,12 +405,12 @@ class Cache(object):
"""Parse the specified filename, returning the recipe information"""
infos = []
datastores = cls.load_bbfile(filename, appends, configdata)
depends = []
depends = set()
for variant, data in sorted(datastores.iteritems(),
key=lambda i: i[0],
reverse=True):
virtualfn = cls.realfn2virtual(filename, variant)
depends = depends + (data.getVar("__depends", False) or [])
depends |= (data.getVar("__depends", False) or set())
if depends and not variant:
data.setVar("__depends", depends)
@@ -526,7 +528,7 @@ class Cache(object):
if appends != info_array[0].appends:
logger.debug(2, "Cache: appends for %s changed", fn)
logger.debug(2, "%s to %s" % (str(appends), str(info_array[0].appends)))
bb.note("%s to %s" % (str(appends), str(info_array[0].appends)))
self.remove(fn)
return False
@@ -738,9 +740,8 @@ class MultiProcessCache(object):
logger.debug(1, "Using cache in '%s'", self.cachefile)
try:
with open(self.cachefile, "rb") as f:
p = pickle.Unpickler(f)
data, version = p.load()
p = pickle.Unpickler(file(self.cachefile, "rb"))
data, version = p.load()
except:
return
@@ -780,9 +781,8 @@ class MultiProcessCache(object):
i = i + 1
continue
with open(self.cachefile + "-" + str(i), "wb") as f:
p = pickle.Pickler(f, -1)
p.dump([self.cachedata_extras, self.__class__.CACHE_VERSION])
p = pickle.Pickler(file(self.cachefile + "-" + str(i), "wb"), -1)
p.dump([self.cachedata_extras, self.__class__.CACHE_VERSION])
bb.utils.unlockfile(lf)
bb.utils.unlockfile(glf)
@@ -800,9 +800,8 @@ class MultiProcessCache(object):
glf = bb.utils.lockfile(self.cachefile + ".lock")
try:
with open(self.cachefile, "rb") as f:
p = pickle.Unpickler(f)
data, version = p.load()
p = pickle.Unpickler(file(self.cachefile, "rb"))
data, version = p.load()
except (IOError, EOFError):
data, version = None, None
@@ -812,9 +811,8 @@ class MultiProcessCache(object):
for f in [y for y in os.listdir(os.path.dirname(self.cachefile)) if y.startswith(os.path.basename(self.cachefile) + '-')]:
f = os.path.join(os.path.dirname(self.cachefile), f)
try:
with open(f, "rb") as fd:
p = pickle.Unpickler(fd)
extradata, version = p.load()
p = pickle.Unpickler(file(f, "rb"))
extradata, version = p.load()
except (IOError, EOFError):
extradata, version = self.create_cachedata(), None
@@ -826,9 +824,8 @@ class MultiProcessCache(object):
self.compress_keys(data)
with open(self.cachefile, "wb") as f:
p = pickle.Pickler(f, -1)
p.dump([data, self.__class__.CACHE_VERSION])
p = pickle.Pickler(file(self.cachefile, "wb"), -1)
p.dump([data, self.__class__.CACHE_VERSION])
bb.utils.unlockfile(glf)

View File

@@ -41,10 +41,6 @@ class HobRecipeInfo(RecipeInfoCommon):
self.license = self.getvar('LICENSE', metadata)
self.section = self.getvar('SECTION', metadata)
self.description = self.getvar('DESCRIPTION', metadata)
self.homepage = self.getvar('HOMEPAGE', metadata)
self.bugtracker = self.getvar('BUGTRACKER', metadata)
self.prevision = self.getvar('PR', metadata)
self.files_info = self.getvar('FILES_INFO', metadata)
@classmethod
def init_cacheData(cls, cachedata):
@@ -53,17 +49,9 @@ class HobRecipeInfo(RecipeInfoCommon):
cachedata.license = {}
cachedata.section = {}
cachedata.description = {}
cachedata.homepage = {}
cachedata.bugtracker = {}
cachedata.prevision = {}
cachedata.files_info = {}
def add_cacheData(self, cachedata, fn):
cachedata.summary[fn] = self.summary
cachedata.license[fn] = self.license
cachedata.section[fn] = self.section
cachedata.description[fn] = self.description
cachedata.homepage[fn] = self.homepage
cachedata.bugtracker[fn] = self.bugtracker
cachedata.prevision[fn] = self.prevision
cachedata.files_info[fn] = self.files_info

View File

@@ -35,7 +35,7 @@ def check_indent(codestr):
class CodeParserCache(MultiProcessCache):
cache_file_name = "bb_codeparser.dat"
CACHE_VERSION = 3
CACHE_VERSION = 2
def __init__(self):
MultiProcessCache.__init__(self)
@@ -100,8 +100,7 @@ class BufferedLogger(Logger):
self.buffer = []
class PythonParser():
getvars = ("d.getVar", "bb.data.getVar", "data.getVar", "d.appendVar", "d.prependVar")
containsfuncs = ("bb.utils.contains", "base_contains", "oe.utils.contains")
getvars = ("d.getVar", "bb.data.getVar", "data.getVar")
execfuncs = ("bb.build.exec_func", "bb.build.exec_task")
def warn(self, func, arg):
@@ -120,7 +119,7 @@ class PythonParser():
def visit_Call(self, node):
name = self.called_node_name(node.func)
if name in self.getvars or name in self.containsfuncs:
if name in self.getvars:
if isinstance(node.args[0], ast.Str):
self.var_references.add(node.args[0].s)
else:

View File

@@ -44,9 +44,6 @@ class CommandFailed(CommandExit):
self.error = message
CommandExit.__init__(self, 1)
class CommandError(Exception):
pass
class Command:
"""
A queue of asynchronous commands for bitbake
@@ -60,26 +57,21 @@ class Command:
self.currentAsyncCommand = None
def runCommand(self, commandline):
command = commandline.pop(0)
if hasattr(CommandsSync, command):
# Can run synchronous commands straight away
command_method = getattr(self.cmds_sync, command)
try:
result = command_method(self, commandline)
except CommandError as exc:
return None, exc.args[0]
except Exception:
import traceback
return None, traceback.format_exc()
else:
return result, None
if self.currentAsyncCommand is not None:
return None, "Busy (%s in progress)" % self.currentAsyncCommand[0]
if command not in CommandsAsync.__dict__:
return None, "No such command"
self.currentAsyncCommand = (command, commandline)
self.cooker.configuration.server_register_idlecallback(self.cooker.runCommands, self.cooker)
return True, None
try:
command = commandline.pop(0)
if command in CommandsSync.__dict__:
# Can run synchronous commands straight away
return getattr(CommandsSync, command)(self.cmds_sync, self, commandline)
if self.currentAsyncCommand is not None:
return "Busy (%s in progress)" % self.currentAsyncCommand[0]
if command not in CommandsAsync.__dict__:
return "No such command"
self.currentAsyncCommand = (command, commandline)
self.cooker.server_registration_cb(self.cooker.runCommands, self.cooker)
return True
except:
import traceback
return traceback.format_exc()
def runAsyncCommand(self):
try:
@@ -143,6 +135,12 @@ class CommandsSync:
"""
command.cooker.stop()
def getCmdLineAction(self, command, params):
"""
Get any command parsed from the commandline
"""
return command.cooker.commandlineAction
def getVariable(self, command, params):
"""
Read the value of a variable from configuration.data
@@ -162,26 +160,6 @@ class CommandsSync:
value = str(params[1])
command.cooker.configuration.data.setVar(varname, value)
def setConfig(self, command, params):
"""
Set the value of variable in configuration
"""
varname = params[0]
value = str(params[1])
setattr(command.cooker.configuration, varname, value)
def enableDataTracking(self, command, params):
"""
Enable history tracking for variables
"""
command.cooker.enableDataTracking()
def disableDataTracking(self, command, params):
"""
Disable history tracking for variables
"""
command.cooker.disableDataTracking()
def initCooker(self, command, params):
"""
Init the cooker to initial state with nothing parsed
@@ -201,21 +179,12 @@ class CommandsSync:
"""
return bb.utils.cpu_count()
def matchFile(self, command, params):
fMatch = params[0]
return command.cooker.matchFile(fMatch)
def generateNewImage(self, command, params):
image = params[0]
base_image = params[1]
package_queue = params[2]
return command.cooker.generateNewImage(image, base_image, package_queue)
def setVarFile(self, command, params):
var = params[0]
val = params[1]
default_file = params[2]
command.cooker.saveConfigurationVar(var, val, default_file)
def setConfFilter(self, command, params):
"""
Set the configuration file parsing filter
"""
filterfunc = params[0]
bb.parse.parse_py.ConfHandler.confFilters.append(filterfunc)
class CommandsAsync:
"""
@@ -387,9 +356,7 @@ class CommandsAsync:
"""
prefiles = params[0]
postfiles = params[1]
command.cooker.configuration.prefile = prefiles
command.cooker.configuration.postfile = postfiles
command.cooker.loadConfigurationData()
command.cooker.parseConfigurationFiles(prefiles, postfiles)
command.finishAsyncCommand()
parseConfigurationFiles.needcache = False

View File

@@ -239,690 +239,3 @@ class OrderedDict(dict):
def viewitems(self):
"od.viewitems() -> a set-like object providing a view on od's items"
return ItemsView(self)
# Multiprocessing pool code imported from python 2.7.3. Previous versions of
# python have issues in this code which hang pool usage
#
# Module providing the `Pool` class for managing a process pool
#
# multiprocessing/pool.py
#
# Copyright (c) 2006-2008, R Oudkerk
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# 3. Neither the name of author nor the names of any contributors may be
# used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
import threading
import Queue
import itertools
import collections
import time
import multiprocessing
from multiprocessing import Process, cpu_count, TimeoutError, pool
from multiprocessing.util import Finalize, debug
#
# Constants representing the state of a pool
#
RUN = 0
CLOSE = 1
TERMINATE = 2
#
# Miscellaneous
#
def mapstar(args):
return map(*args)
class MaybeEncodingError(Exception):
"""Wraps possible unpickleable errors, so they can be
safely sent through the socket."""
def __init__(self, exc, value):
self.exc = repr(exc)
self.value = repr(value)
super(MaybeEncodingError, self).__init__(self.exc, self.value)
def __str__(self):
return "Error sending result: '%s'. Reason: '%s'" % (self.value,
self.exc)
def __repr__(self):
return "<MaybeEncodingError: %s>" % str(self)
def worker(inqueue, outqueue, initializer=None, initargs=(), maxtasks=None):
assert maxtasks is None or (type(maxtasks) == int and maxtasks > 0)
put = outqueue.put
get = inqueue.get
if hasattr(inqueue, '_writer'):
inqueue._writer.close()
outqueue._reader.close()
if initializer is not None:
initializer(*initargs)
completed = 0
while maxtasks is None or (maxtasks and completed < maxtasks):
try:
task = get()
except (EOFError, IOError):
debug('worker got EOFError or IOError -- exiting')
break
if task is None:
debug('worker got sentinel -- exiting')
break
job, i, func, args, kwds = task
try:
result = (True, func(*args, **kwds))
except Exception as e:
result = (False, e)
try:
put((job, i, result))
except Exception as e:
wrapped = MaybeEncodingError(e, result[1])
debug("Possible encoding error while sending result: %s" % (
wrapped))
put((job, i, (False, wrapped)))
completed += 1
debug('worker exiting after %d tasks' % completed)
class Pool(object):
'''
Class which supports an async version of the `apply()` builtin
'''
Process = Process
def __init__(self, processes=None, initializer=None, initargs=(),
maxtasksperchild=None):
self._setup_queues()
self._taskqueue = Queue.Queue()
self._cache = {}
self._state = RUN
self._maxtasksperchild = maxtasksperchild
self._initializer = initializer
self._initargs = initargs
if processes is None:
try:
processes = cpu_count()
except NotImplementedError:
processes = 1
if processes < 1:
raise ValueError("Number of processes must be at least 1")
if initializer is not None and not hasattr(initializer, '__call__'):
raise TypeError('initializer must be a callable')
self._processes = processes
self._pool = []
self._repopulate_pool()
self._worker_handler = threading.Thread(
target=Pool._handle_workers,
args=(self, )
)
self._worker_handler.daemon = True
self._worker_handler._state = RUN
self._worker_handler.start()
self._task_handler = threading.Thread(
target=Pool._handle_tasks,
args=(self._taskqueue, self._quick_put, self._outqueue, self._pool)
)
self._task_handler.daemon = True
self._task_handler._state = RUN
self._task_handler.start()
self._result_handler = threading.Thread(
target=Pool._handle_results,
args=(self._outqueue, self._quick_get, self._cache)
)
self._result_handler.daemon = True
self._result_handler._state = RUN
self._result_handler.start()
self._terminate = Finalize(
self, self._terminate_pool,
args=(self._taskqueue, self._inqueue, self._outqueue, self._pool,
self._worker_handler, self._task_handler,
self._result_handler, self._cache),
exitpriority=15
)
def _join_exited_workers(self):
"""Cleanup after any worker processes which have exited due to reaching
their specified lifetime. Returns True if any workers were cleaned up.
"""
cleaned = False
for i in reversed(range(len(self._pool))):
worker = self._pool[i]
if worker.exitcode is not None:
# worker exited
debug('cleaning up worker %d' % i)
worker.join()
cleaned = True
del self._pool[i]
return cleaned
def _repopulate_pool(self):
"""Bring the number of pool processes up to the specified number,
for use after reaping workers which have exited.
"""
for i in range(self._processes - len(self._pool)):
w = self.Process(target=worker,
args=(self._inqueue, self._outqueue,
self._initializer,
self._initargs, self._maxtasksperchild)
)
self._pool.append(w)
w.name = w.name.replace('Process', 'PoolWorker')
w.daemon = True
w.start()
debug('added worker')
def _maintain_pool(self):
"""Clean up any exited workers and start replacements for them.
"""
if self._join_exited_workers():
self._repopulate_pool()
def _setup_queues(self):
from multiprocessing.queues import SimpleQueue
self._inqueue = SimpleQueue()
self._outqueue = SimpleQueue()
self._quick_put = self._inqueue._writer.send
self._quick_get = self._outqueue._reader.recv
def apply(self, func, args=(), kwds={}):
'''
Equivalent of `apply()` builtin
'''
assert self._state == RUN
return self.apply_async(func, args, kwds).get()
def map(self, func, iterable, chunksize=None):
'''
Equivalent of `map()` builtin
'''
assert self._state == RUN
return self.map_async(func, iterable, chunksize).get()
def imap(self, func, iterable, chunksize=1):
'''
Equivalent of `itertools.imap()` -- can be MUCH slower than `Pool.map()`
'''
assert self._state == RUN
if chunksize == 1:
result = IMapIterator(self._cache)
self._taskqueue.put((((result._job, i, func, (x,), {})
for i, x in enumerate(iterable)), result._set_length))
return result
else:
assert chunksize > 1
task_batches = Pool._get_tasks(func, iterable, chunksize)
result = IMapIterator(self._cache)
self._taskqueue.put((((result._job, i, mapstar, (x,), {})
for i, x in enumerate(task_batches)), result._set_length))
return (item for chunk in result for item in chunk)
def imap_unordered(self, func, iterable, chunksize=1):
'''
Like `imap()` method but ordering of results is arbitrary
'''
assert self._state == RUN
if chunksize == 1:
result = IMapUnorderedIterator(self._cache)
self._taskqueue.put((((result._job, i, func, (x,), {})
for i, x in enumerate(iterable)), result._set_length))
return result
else:
assert chunksize > 1
task_batches = Pool._get_tasks(func, iterable, chunksize)
result = IMapUnorderedIterator(self._cache)
self._taskqueue.put((((result._job, i, mapstar, (x,), {})
for i, x in enumerate(task_batches)), result._set_length))
return (item for chunk in result for item in chunk)
def apply_async(self, func, args=(), kwds={}, callback=None):
'''
Asynchronous equivalent of `apply()` builtin
'''
assert self._state == RUN
result = ApplyResult(self._cache, callback)
self._taskqueue.put(([(result._job, None, func, args, kwds)], None))
return result
def map_async(self, func, iterable, chunksize=None, callback=None):
'''
Asynchronous equivalent of `map()` builtin
'''
assert self._state == RUN
if not hasattr(iterable, '__len__'):
iterable = list(iterable)
if chunksize is None:
chunksize, extra = divmod(len(iterable), len(self._pool) * 4)
if extra:
chunksize += 1
if len(iterable) == 0:
chunksize = 0
task_batches = Pool._get_tasks(func, iterable, chunksize)
result = MapResult(self._cache, chunksize, len(iterable), callback)
self._taskqueue.put((((result._job, i, mapstar, (x,), {})
for i, x in enumerate(task_batches)), None))
return result
@staticmethod
def _handle_workers(pool):
thread = threading.current_thread()
# Keep maintaining workers until the cache gets drained, unless the pool
# is terminated.
while thread._state == RUN or (pool._cache and thread._state != TERMINATE):
pool._maintain_pool()
time.sleep(0.1)
# send sentinel to stop workers
pool._taskqueue.put(None)
debug('worker handler exiting')
@staticmethod
def _handle_tasks(taskqueue, put, outqueue, pool):
thread = threading.current_thread()
for taskseq, set_length in iter(taskqueue.get, None):
i = -1
for i, task in enumerate(taskseq):
if thread._state:
debug('task handler found thread._state != RUN')
break
try:
put(task)
except IOError:
debug('could not put task on queue')
break
else:
if set_length:
debug('doing set_length()')
set_length(i+1)
continue
break
else:
debug('task handler got sentinel')
try:
# tell result handler to finish when cache is empty
debug('task handler sending sentinel to result handler')
outqueue.put(None)
# tell workers there is no more work
debug('task handler sending sentinel to workers')
for p in pool:
put(None)
except IOError:
debug('task handler got IOError when sending sentinels')
debug('task handler exiting')
@staticmethod
def _handle_results(outqueue, get, cache):
thread = threading.current_thread()
while 1:
try:
task = get()
except (IOError, EOFError):
debug('result handler got EOFError/IOError -- exiting')
return
if thread._state:
assert thread._state == TERMINATE
debug('result handler found thread._state=TERMINATE')
break
if task is None:
debug('result handler got sentinel')
break
job, i, obj = task
try:
cache[job]._set(i, obj)
except KeyError:
pass
while cache and thread._state != TERMINATE:
try:
task = get()
except (IOError, EOFError):
debug('result handler got EOFError/IOError -- exiting')
return
if task is None:
debug('result handler ignoring extra sentinel')
continue
job, i, obj = task
try:
cache[job]._set(i, obj)
except KeyError:
pass
if hasattr(outqueue, '_reader'):
debug('ensuring that outqueue is not full')
# If we don't make room available in outqueue then
# attempts to add the sentinel (None) to outqueue may
# block. There is guaranteed to be no more than 2 sentinels.
try:
for i in range(10):
if not outqueue._reader.poll():
break
get()
except (IOError, EOFError):
pass
debug('result handler exiting: len(cache)=%s, thread._state=%s',
len(cache), thread._state)
@staticmethod
def _get_tasks(func, it, size):
it = iter(it)
while 1:
x = tuple(itertools.islice(it, size))
if not x:
return
yield (func, x)
def __reduce__(self):
raise NotImplementedError(
'pool objects cannot be passed between processes or pickled'
)
def close(self):
debug('closing pool')
if self._state == RUN:
self._state = CLOSE
self._worker_handler._state = CLOSE
def terminate(self):
debug('terminating pool')
self._state = TERMINATE
self._worker_handler._state = TERMINATE
self._terminate()
def join(self):
debug('joining pool')
assert self._state in (CLOSE, TERMINATE)
self._worker_handler.join()
self._task_handler.join()
self._result_handler.join()
for p in self._pool:
p.join()
@staticmethod
def _help_stuff_finish(inqueue, task_handler, size):
# task_handler may be blocked trying to put items on inqueue
debug('removing tasks from inqueue until task handler finished')
inqueue._rlock.acquire()
while task_handler.is_alive() and inqueue._reader.poll():
inqueue._reader.recv()
time.sleep(0)
@classmethod
def _terminate_pool(cls, taskqueue, inqueue, outqueue, pool,
worker_handler, task_handler, result_handler, cache):
# this is guaranteed to only be called once
debug('finalizing pool')
worker_handler._state = TERMINATE
task_handler._state = TERMINATE
debug('helping task handler/workers to finish')
cls._help_stuff_finish(inqueue, task_handler, len(pool))
assert result_handler.is_alive() or len(cache) == 0
result_handler._state = TERMINATE
outqueue.put(None) # sentinel
# We must wait for the worker handler to exit before terminating
# workers because we don't want workers to be restarted behind our back.
debug('joining worker handler')
if threading.current_thread() is not worker_handler:
worker_handler.join(1e100)
# Terminate workers which haven't already finished.
if pool and hasattr(pool[0], 'terminate'):
debug('terminating workers')
for p in pool:
if p.exitcode is None:
p.terminate()
debug('joining task handler')
if threading.current_thread() is not task_handler:
task_handler.join(1e100)
debug('joining result handler')
if threading.current_thread() is not result_handler:
result_handler.join(1e100)
if pool and hasattr(pool[0], 'terminate'):
debug('joining pool workers')
for p in pool:
if p.is_alive():
# worker has not yet exited
debug('cleaning up worker %d' % p.pid)
p.join()
class ApplyResult(object):
def __init__(self, cache, callback):
self._cond = threading.Condition(threading.Lock())
self._job = multiprocessing.pool.job_counter.next()
self._cache = cache
self._ready = False
self._callback = callback
cache[self._job] = self
def ready(self):
return self._ready
def successful(self):
assert self._ready
return self._success
def wait(self, timeout=None):
self._cond.acquire()
try:
if not self._ready:
self._cond.wait(timeout)
finally:
self._cond.release()
def get(self, timeout=None):
self.wait(timeout)
if not self._ready:
raise TimeoutError
if self._success:
return self._value
else:
raise self._value
def _set(self, i, obj):
self._success, self._value = obj
if self._callback and self._success:
self._callback(self._value)
self._cond.acquire()
try:
self._ready = True
self._cond.notify()
finally:
self._cond.release()
del self._cache[self._job]
#
# Class whose instances are returned by `Pool.map_async()`
#
class MapResult(ApplyResult):
def __init__(self, cache, chunksize, length, callback):
ApplyResult.__init__(self, cache, callback)
self._success = True
self._value = [None] * length
self._chunksize = chunksize
if chunksize <= 0:
self._number_left = 0
self._ready = True
del cache[self._job]
else:
self._number_left = length//chunksize + bool(length % chunksize)
def _set(self, i, success_result):
success, result = success_result
if success:
self._value[i*self._chunksize:(i+1)*self._chunksize] = result
self._number_left -= 1
if self._number_left == 0:
if self._callback:
self._callback(self._value)
del self._cache[self._job]
self._cond.acquire()
try:
self._ready = True
self._cond.notify()
finally:
self._cond.release()
else:
self._success = False
self._value = result
del self._cache[self._job]
self._cond.acquire()
try:
self._ready = True
self._cond.notify()
finally:
self._cond.release()
#
# Class whose instances are returned by `Pool.imap()`
#
class IMapIterator(object):
def __init__(self, cache):
self._cond = threading.Condition(threading.Lock())
self._job = multiprocessing.pool.job_counter.next()
self._cache = cache
self._items = collections.deque()
self._index = 0
self._length = None
self._unsorted = {}
cache[self._job] = self
def __iter__(self):
return self
def next(self, timeout=None):
self._cond.acquire()
try:
try:
item = self._items.popleft()
except IndexError:
if self._index == self._length:
raise StopIteration
self._cond.wait(timeout)
try:
item = self._items.popleft()
except IndexError:
if self._index == self._length:
raise StopIteration
raise TimeoutError
finally:
self._cond.release()
success, value = item
if success:
return value
raise value
__next__ = next # XXX
def _set(self, i, obj):
self._cond.acquire()
try:
if self._index == i:
self._items.append(obj)
self._index += 1
while self._index in self._unsorted:
obj = self._unsorted.pop(self._index)
self._items.append(obj)
self._index += 1
self._cond.notify()
else:
self._unsorted[i] = obj
if self._index == self._length:
del self._cache[self._job]
finally:
self._cond.release()
def _set_length(self, length):
self._cond.acquire()
try:
self._length = length
if self._index == self._length:
self._cond.notify()
del self._cache[self._job]
finally:
self._cond.release()
#
# Class whose instances are returned by `Pool.imap_unordered()`
#
class IMapUnorderedIterator(IMapIterator):
def _set(self, i, obj):
self._cond.acquire()
try:
self._items.append(obj)
self._index += 1
self._cond.notify()
if self._index == self._length:
del self._cache[self._job]
finally:
self._cond.release()

File diff suppressed because it is too large Load Diff

View File

@@ -1,272 +0,0 @@
#!/usr/bin/env python
# ex:ts=4:sw=4:sts=4:et
# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
#
# Copyright (C) 2003, 2004 Chris Larson
# Copyright (C) 2003, 2004 Phil Blundell
# Copyright (C) 2003 - 2005 Michael 'Mickey' Lauer
# Copyright (C) 2005 Holger Hans Peter Freyther
# Copyright (C) 2005 ROAD GmbH
# Copyright (C) 2006 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, sys
from functools import wraps
import logging
from bb import data
logger = logging.getLogger("BitBake")
parselog = logging.getLogger("BitBake.Parsing")
class ConfigParameters(object):
def __init__(self):
self.options, targets = self.parseCommandLine()
self.environment = self.parseEnvironment()
self.options.pkgs_to_build = targets or []
self.options.tracking = False
if hasattr(self.options, "show_environment") and self.options.show_environment:
self.options.tracking = True
for key, val in self.options.__dict__.items():
setattr(self, key, val)
def parseCommandLine(self):
raise Exception("Caller must implement commandline option parsing")
def parseEnvironment(self):
return os.environ.copy()
def updateFromServer(self, server):
if not self.options.cmd:
defaulttask, error = server.runCommand(["getVariable", "BB_DEFAULT_TASK"])
if error:
raise Exception("Unable to get the value of BB_DEFAULT_TASK from the server: %s" % error)
self.options.cmd = defaulttask or "build"
_, error = server.runCommand(["setConfig", "cmd", self.options.cmd])
if error:
raise Exception("Unable to set configuration option 'cmd' on the server: %s" % error)
if not self.options.pkgs_to_build:
bbpkgs, error = server.runCommand(["getVariable", "BBPKGS"])
if error:
raise Exception("Unable to get the value of BBPKGS from the server: %s" % error)
if bbpkgs:
self.options.pkgs_to_build.extend(bbpkgs.split())
def parseActions(self):
# Parse any commandline into actions
action = {'action':None, 'msg':None}
if self.options.show_environment:
if 'world' in self.options.pkgs_to_build:
action['msg'] = "'world' is not a valid target for --environment."
elif 'universe' in self.options.pkgs_to_build:
action['msg'] = "'universe' is not a valid target for --environment."
elif len(self.options.pkgs_to_build) > 1:
action['msg'] = "Only one target can be used with the --environment option."
elif self.options.buildfile and len(self.options.pkgs_to_build) > 0:
action['msg'] = "No target should be used with the --environment and --buildfile options."
elif len(self.options.pkgs_to_build) > 0:
action['action'] = ["showEnvironmentTarget", self.options.pkgs_to_build]
else:
action['action'] = ["showEnvironment", self.options.buildfile]
elif self.options.buildfile is not None:
action['action'] = ["buildFile", self.options.buildfile, self.options.cmd]
elif self.options.revisions_changed:
action['action'] = ["compareRevisions"]
elif self.options.show_versions:
action['action'] = ["showVersions"]
elif self.options.parse_only:
action['action'] = ["parseFiles"]
elif self.options.dot_graph:
if self.options.pkgs_to_build:
action['action'] = ["generateDotGraph", self.options.pkgs_to_build, self.options.cmd]
else:
action['msg'] = "Please specify a package name for dependency graph generation."
else:
if self.options.pkgs_to_build:
action['action'] = ["buildTargets", self.options.pkgs_to_build, self.options.cmd]
else:
#action['msg'] = "Nothing to do. Use 'bitbake world' to build everything, or run 'bitbake --help' for usage information."
action = None
self.options.initialaction = action
return action
class CookerConfiguration(object):
"""
Manages build options and configurations for one run
"""
def __init__(self):
self.debug_domains = []
self.extra_assume_provided = []
self.prefile = []
self.postfile = []
self.debug = 0
self.cmd = None
self.abort = True
self.force = False
self.profile = False
self.nosetscene = False
self.invalidate_stamp = False
self.dump_signatures = False
self.dry_run = False
self.tracking = False
self.extra_caches = []
self.env = {}
def setConfigParameters(self, parameters):
for key in self.__dict__.keys():
if key in parameters.options.__dict__:
setattr(self, key, parameters.options.__dict__[key])
self.env = parameters.environment.copy()
self.tracking = parameters.tracking
def setServerRegIdleCallback(self, srcb):
self.server_register_idlecallback = srcb
def catch_parse_error(func):
"""Exception handling bits for our parsing"""
@wraps(func)
def wrapped(fn, *args):
try:
return func(fn, *args)
except (IOError, bb.parse.ParseError, bb.data_smart.ExpansionError) as exc:
parselog.critical("Unable to parse %s: %s" % (fn, exc))
sys.exit(1)
return wrapped
@catch_parse_error
def parse_config_file(fn, data, include=True):
return bb.parse.handle(fn, data, include)
@catch_parse_error
def _inherit(bbclass, data):
bb.parse.BBHandler.inherit(bbclass, "configuration INHERITs", 0, data)
return data
def findConfigFile(configfile):
path = os.getcwd()
while path != "/":
confpath = os.path.join(path, "conf", configfile)
if os.path.exists(confpath):
return confpath
path, _ = os.path.split(path)
return None
class CookerDataBuilder(object):
def __init__(self, cookercfg, worker = False):
self.prefiles = cookercfg.prefile
self.postfiles = cookercfg.postfile
self.tracking = cookercfg.tracking
bb.utils.set_context(bb.utils.clean_context())
bb.event.set_class_handlers(bb.event.clean_class_handlers())
self.data = bb.data.init()
if self.tracking:
self.data.enableTracking()
# Keep a datastore of the initial environment variables and their
# values from when BitBake was launched to enable child processes
# to use environment variables which have been cleaned from the
# BitBake processes env
self.savedenv = bb.data.init()
for k in cookercfg.env:
self.savedenv.setVar(k, cookercfg.env[k])
filtered_keys = bb.utils.approved_variables()
bb.data.inheritFromOS(self.data, self.savedenv, filtered_keys)
self.data.setVar("BB_ORIGENV", self.savedenv)
if worker:
self.data.setVar("BB_WORKERCONTEXT", "1")
def parseBaseConfiguration(self):
try:
self.parseConfigurationFiles(self.prefiles, self.postfiles)
except SyntaxError:
sys.exit(1)
except Exception:
logger.exception("Error parsing configuration files")
sys.exit(1)
def _findLayerConf(self):
return findConfigFile("bblayers.conf")
def parseConfigurationFiles(self, prefiles, postfiles):
data = self.data
bb.parse.init_parser(data)
# Parse files for loading *before* bitbake.conf and any includes
for f in prefiles:
data = parse_config_file(f, data)
layerconf = self._findLayerConf()
if layerconf:
parselog.debug(2, "Found bblayers.conf (%s)", layerconf)
data = parse_config_file(layerconf, data)
layers = (data.getVar('BBLAYERS', True) or "").split()
data = bb.data.createCopy(data)
for layer in layers:
parselog.debug(2, "Adding layer %s", layer)
data.setVar('LAYERDIR', layer)
data = parse_config_file(os.path.join(layer, "conf", "layer.conf"), data)
data.expandVarref('LAYERDIR')
data.delVar('LAYERDIR')
if not data.getVar("BBPATH", True):
raise SystemExit("The BBPATH variable is not set")
data = parse_config_file(os.path.join("conf", "bitbake.conf"), data)
# Parse files for loading *after* bitbake.conf and any includes
for p in postfiles:
data = parse_config_file(p, data)
# Handle any INHERITs and inherit the base class
bbclasses = ["base"] + (data.getVar('INHERIT', True) or "").split()
for bbclass in bbclasses:
data = _inherit(bbclass, data)
# Nomally we only register event handlers at the end of parsing .bb files
# We register any handlers we've found so far here...
for var in data.getVar('__BBHANDLERS') or []:
bb.event.register(var, data.getVar(var))
if data.getVar("BB_WORKERCONTEXT", False) is None:
bb.fetch.fetcher_init(data)
bb.codeparser.parser_cache_init(data)
bb.event.fire(bb.event.ConfigParsed(), data)
if data.getVar("BB_INVALIDCONF") is True:
data.setVar("BB_INVALIDCONF", False)
self.parseConfigurationFiles(self.prefiles, self.postfiles)
return
bb.parse.init_parser(data)
data.setVar('BBINCLUDED',bb.parse.get_file_depends(data))
self.data = data
self.data_hash = data.get_hash()

View File

@@ -158,12 +158,7 @@ def expandKeys(alterdata, readdata = None):
for key in todolist:
ekey = todolist[key]
newval = alterdata.getVar(ekey, 0)
if newval:
val = alterdata.getVar(key, 0)
if val is not None and newval is not None:
bb.warn("Variable key %s (%s) replaces original key %s (%s)." % (key, val, ekey, newval))
alterdata.renameVar(key, ekey)
renameVar(key, ekey, alterdata)
def inheritFromOS(d, savedenv, permitted):
"""Inherit variables from the initial environment."""
@@ -171,9 +166,9 @@ def inheritFromOS(d, savedenv, permitted):
for s in savedenv.keys():
if s in permitted:
try:
d.setVar(s, getVar(s, savedenv, True), op = 'from env')
setVar(s, getVar(s, savedenv, True), d)
if s in exportlist:
d.setVarFlag(s, "export", True, op = 'auto env export')
setVarFlag(s, "export", True, d)
except TypeError:
pass
@@ -199,7 +194,8 @@ def emit_var(var, o=sys.__stdout__, d = init(), all=False):
return 0
if all:
d.varhistory.emit(var, oval, val, o)
commentVal = re.sub('\n', '\n#', str(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:
return 0
@@ -264,7 +260,6 @@ def emit_func(func, o=sys.__stdout__, d = init()):
emit_var(func, o, d, False) and o.write('\n')
newdeps = bb.codeparser.ShellParser(func, logger).parse_shell(d.getVar(func, True))
newdeps |= set((d.getVarFlag(func, "vardeps", True) or "").split())
seen = set()
while newdeps:
deps = newdeps
@@ -274,12 +269,11 @@ def emit_func(func, o=sys.__stdout__, d = init()):
if d.getVarFlag(dep, "func"):
emit_var(dep, o, d, False) and o.write('\n')
newdeps |= bb.codeparser.ShellParser(dep, logger).parse_shell(d.getVar(dep, True))
newdeps |= set((d.getVarFlag(dep, "vardeps", True) or "").split())
newdeps -= seen
def update_data(d):
"""Performs final steps upon the datastore, including application of overrides"""
d.finalize(parent = True)
d.finalize()
def build_dependencies(key, keys, shelldeps, vardepvals, d):
deps = set()
@@ -363,8 +357,6 @@ def generate_dependencies(d):
def inherits_class(klass, d):
val = getVar('__inherit_cache', d) or []
needle = os.path.join('classes', '%s.bbclass' % klass)
for v in val:
if v.endswith(needle):
return True
if os.path.join('classes', '%s.bbclass' % klass) in val:
return True
return False

View File

@@ -28,7 +28,7 @@ BitBake build tools.
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
# Based on functions from the base bb module, Copyright 2003 Holger Schurig
import copy, re, sys, traceback
import copy, re
from collections import MutableMapping
import logging
import hashlib
@@ -43,42 +43,6 @@ __setvar_regexp__ = re.compile('(?P<base>.*?)(?P<keyword>_append|_prepend)(_(?P<
__expand_var_regexp__ = re.compile(r"\${[^{}]+}")
__expand_python_regexp__ = re.compile(r"\${@.+?}")
def infer_caller_details(loginfo, parent = False, varval = True):
"""Save the caller the trouble of specifying everything."""
# Save effort.
if 'ignore' in loginfo and loginfo['ignore']:
return
# If nothing was provided, mark this as possibly unneeded.
if not loginfo:
loginfo['ignore'] = True
return
# Infer caller's likely values for variable (var) and value (value),
# to reduce clutter in the rest of the code.
if varval and ('variable' not in loginfo or 'detail' not in loginfo):
try:
raise Exception
except Exception:
tb = sys.exc_info()[2]
if parent:
above = tb.tb_frame.f_back.f_back
else:
above = tb.tb_frame.f_back
lcls = above.f_locals.items()
for k, v in lcls:
if k == 'value' and 'detail' not in loginfo:
loginfo['detail'] = v
if k == 'var' and 'variable' not in loginfo:
loginfo['variable'] = v
# Infer file/line/function from traceback
if 'file' not in loginfo:
depth = 3
if parent:
depth = 4
file, line, func, text = traceback.extract_stack(limit = depth)[0]
loginfo['file'] = file
loginfo['line'] = line
if func not in loginfo:
loginfo['func'] = func
class VariableParse:
def __init__(self, varname, d, val = None):
@@ -150,157 +114,16 @@ class ExpansionError(Exception):
def __str__(self):
return self.msg
class IncludeHistory(object):
def __init__(self, parent = None, filename = '[TOP LEVEL]'):
self.parent = parent
self.filename = filename
self.children = []
self.current = self
def copy(self):
new = IncludeHistory(self.parent, self.filename)
for c in self.children:
new.children.append(c)
return new
def include(self, filename):
newfile = IncludeHistory(self.current, filename)
self.current.children.append(newfile)
self.current = newfile
return self
def __enter__(self):
pass
def __exit__(self, a, b, c):
if self.current.parent:
self.current = self.current.parent
else:
bb.warn("Include log: Tried to finish '%s' at top level." % filename)
return False
def emit(self, o, level = 0):
"""Emit an include history file, and its children."""
if level:
spaces = " " * (level - 1)
o.write("# %s%s" % (spaces, self.filename))
if len(self.children) > 0:
o.write(" includes:")
else:
o.write("#\n# INCLUDE HISTORY:\n#")
level = level + 1
for child in self.children:
o.write("\n")
child.emit(o, level)
class VariableHistory(object):
def __init__(self, dataroot):
self.dataroot = dataroot
self.variables = COWDictBase.copy()
def copy(self):
new = VariableHistory(self.dataroot)
new.variables = self.variables.copy()
return new
def record(self, *kwonly, **loginfo):
if not self.dataroot._tracking:
return
if len(kwonly) > 0:
raise TypeError
infer_caller_details(loginfo, parent = True)
if 'ignore' in loginfo and loginfo['ignore']:
return
if 'op' not in loginfo or not loginfo['op']:
loginfo['op'] = 'set'
if 'detail' in loginfo:
loginfo['detail'] = str(loginfo['detail'])
if 'variable' not in loginfo or 'file' not in loginfo:
raise ValueError("record() missing variable or file.")
var = loginfo['variable']
if var not in self.variables:
self.variables[var] = []
self.variables[var].append(loginfo.copy())
def variable(self, var):
if var in self.variables:
return self.variables[var]
else:
return []
def emit(self, var, oval, val, o):
history = self.variable(var)
commentVal = re.sub('\n', '\n#', str(oval))
if history:
if len(history) == 1:
o.write("#\n# $%s\n" % var)
else:
o.write("#\n# $%s [%d operations]\n" % (var, len(history)))
for event in history:
# o.write("# %s\n" % str(event))
if 'func' in event:
# If we have a function listed, this is internal
# code, not an operation in a config file, and the
# full path is distracting.
event['file'] = re.sub('.*/', '', event['file'])
display_func = ' [%s]' % event['func']
else:
display_func = ''
if 'flag' in event:
flag = '[%s] ' % (event['flag'])
else:
flag = ''
o.write("# %s %s:%s%s\n# %s\"%s\"\n" % (event['op'], event['file'], event['line'], display_func, flag, re.sub('\n', '\n# ', event['detail'])))
if len(history) > 1:
o.write("# computed:\n")
o.write('# "%s"\n' % (commentVal))
else:
o.write("#\n# $%s\n# [no history recorded]\n#\n" % var)
o.write('# "%s"\n' % (commentVal))
def get_variable_files(self, var):
"""Get the files where operations are made on a variable"""
var_history = self.variable(var)
files = []
for event in var_history:
files.append(event['file'])
return files
def get_variable_lines(self, var, f):
"""Get the line where a operation is made on a variable in file f"""
var_history = self.variable(var)
lines = []
for event in var_history:
if f== event['file']:
line = event['line']
lines.append(line)
return lines
def del_var_history(self, var):
if var in self.variables:
self.variables[var] = []
class DataSmart(MutableMapping):
def __init__(self, special = COWDictBase.copy(), seen = COWDictBase.copy() ):
self.dict = {}
self.inchistory = IncludeHistory()
self.varhistory = VariableHistory(self)
self._tracking = False
# cookie monster tribute
self._special_values = special
self._seen_overrides = seen
self.expand_cache = {}
def enableTracking(self):
self._tracking = True
def disableTracking(self):
self._tracking = False
def expandWithRefs(self, s, varname):
if not isinstance(s, basestring): # sanity check
@@ -320,8 +143,6 @@ class DataSmart(MutableMapping):
break
except ExpansionError:
raise
except bb.parse.SkipPackage:
raise
except Exception as exc:
raise ExpansionError(varname, s, exc)
@@ -336,14 +157,10 @@ class DataSmart(MutableMapping):
return self.expandWithRefs(s, varname).value
def finalize(self, parent = False):
def finalize(self):
"""Performs final steps upon the datastore, including application of overrides"""
overrides = (self.getVar("OVERRIDES", True) or "").split(":") or []
finalize_caller = {
'op': 'finalize',
}
infer_caller_details(finalize_caller, parent = parent, varval = False)
#
# Well let us see what breaks here. We used to iterate
@@ -360,9 +177,6 @@ class DataSmart(MutableMapping):
# Then we will handle _append and _prepend
#
# We only want to report finalization once per variable overridden.
finalizes_reported = {}
for o in overrides:
# calculate '_'+override
l = len(o) + 1
@@ -375,19 +189,7 @@ class DataSmart(MutableMapping):
for var in vars:
name = var[:-l]
try:
# Report only once, even if multiple changes.
if name not in finalizes_reported:
finalizes_reported[name] = True
finalize_caller['variable'] = name
finalize_caller['detail'] = 'was: ' + str(self.getVar(name, False))
self.varhistory.record(**finalize_caller)
# Copy history of the override over.
for event in self.varhistory.variable(var):
loginfo = event.copy()
loginfo['variable'] = name
loginfo['op'] = 'override[%s]:%s' % (o, loginfo['op'])
self.varhistory.record(**loginfo)
self.setVar(name, self.getVar(var, False), op = 'finalize', file = 'override[%s]' % o, line = '')
self.setVar(name, self.getVar(var, False))
self.delVar(var)
except Exception:
logger.info("Untracked delVar")
@@ -418,9 +220,9 @@ class DataSmart(MutableMapping):
# We save overrides that may be applied at some later stage
if keep:
self.setVarFlag(append, op, keep, ignore=True)
self.setVarFlag(append, op, keep)
else:
self.delVarFlag(append, op, ignore=True)
self.delVarFlag(append, op)
def initVar(self, var):
self.expand_cache = {}
@@ -448,11 +250,7 @@ class DataSmart(MutableMapping):
else:
self.initVar(var)
def setVar(self, var, value, **loginfo):
#print("var=" + str(var) + " val=" + str(value))
if 'op' not in loginfo:
loginfo['op'] = "set"
def setVar(self, var, value):
self.expand_cache = {}
match = __setvar_regexp__.match(var)
if match and match.group("keyword") in __setvar_keyword__:
@@ -461,22 +259,15 @@ class DataSmart(MutableMapping):
override = match.group('add')
l = self.getVarFlag(base, keyword) or []
l.append([value, override])
self.setVarFlag(base, keyword, l, ignore=True)
# And cause that to be recorded:
loginfo['detail'] = value
loginfo['variable'] = base
if override:
loginfo['op'] = '%s[%s]' % (keyword, override)
else:
loginfo['op'] = keyword
self.varhistory.record(**loginfo)
self.setVarFlag(base, keyword, l)
# todo make sure keyword is not __doc__ or __module__
# pay the cookie monster
try:
self._special_values[keyword].add(base)
self._special_values[keyword].add( base )
except KeyError:
self._special_values[keyword] = set()
self._special_values[keyword].add(base)
self._special_values[keyword].add( base )
return
@@ -493,7 +284,6 @@ class DataSmart(MutableMapping):
# setting var
self.dict[var]["_content"] = value
self.varhistory.record(**loginfo)
def getVar(self, var, expand=False, noweakdefault=False):
value = self.getVarFlag(var, "_content", False, noweakdefault)
@@ -503,17 +293,13 @@ class DataSmart(MutableMapping):
return self.expand(value, var)
return value
def renameVar(self, key, newkey, **loginfo):
def renameVar(self, key, newkey):
"""
Rename the variable key to newkey
"""
val = self.getVar(key, 0)
if val is not None:
loginfo['variable'] = newkey
loginfo['op'] = 'rename from %s' % key
loginfo['detail'] = val
self.varhistory.record(**loginfo)
self.setVar(newkey, val, ignore=True)
self.setVar(newkey, val)
for i in ('_append', '_prepend'):
src = self.getVarFlag(key, i)
@@ -522,34 +308,23 @@ class DataSmart(MutableMapping):
dest = self.getVarFlag(newkey, i) or []
dest.extend(src)
self.setVarFlag(newkey, i, dest, ignore=True)
self.setVarFlag(newkey, i, dest)
if i in self._special_values and key in self._special_values[i]:
self._special_values[i].remove(key)
self._special_values[i].add(newkey)
loginfo['variable'] = key
loginfo['op'] = 'rename (to)'
loginfo['detail'] = newkey
self.varhistory.record(**loginfo)
self.delVar(key, ignore=True)
self.delVar(key)
def appendVar(self, var, value, **loginfo):
loginfo['op'] = 'append'
self.varhistory.record(**loginfo)
newvalue = (self.getVar(var, False) or "") + value
self.setVar(var, newvalue, ignore=True)
def appendVar(self, key, value):
value = (self.getVar(key, False) or "") + value
self.setVar(key, value)
def prependVar(self, var, value, **loginfo):
loginfo['op'] = 'prepend'
self.varhistory.record(**loginfo)
newvalue = value + (self.getVar(var, False) or "")
self.setVar(var, newvalue, ignore=True)
def prependVar(self, key, value):
value = value + (self.getVar(key, False) or "")
self.setVar(key, value)
def delVar(self, var, **loginfo):
loginfo['detail'] = ""
loginfo['op'] = 'del'
self.varhistory.record(**loginfo)
def delVar(self, var):
self.expand_cache = {}
self.dict[var] = {}
if '_' in var:
@@ -557,14 +332,10 @@ class DataSmart(MutableMapping):
if override and override in self._seen_overrides and var in self._seen_overrides[override]:
self._seen_overrides[override].remove(var)
def setVarFlag(self, var, flag, value, **loginfo):
if 'op' not in loginfo:
loginfo['op'] = "set"
loginfo['flag'] = flag
self.varhistory.record(**loginfo)
def setVarFlag(self, var, flag, flagvalue):
if not var in self.dict:
self._makeShadowCopy(var)
self.dict[var][flag] = value
self.dict[var][flag] = flagvalue
def getVarFlag(self, var, flag, expand=False, noweakdefault=False):
local_var = self._findVar(var)
@@ -578,7 +349,7 @@ class DataSmart(MutableMapping):
value = self.expand(value, None)
return value
def delVarFlag(self, var, flag, **loginfo):
def delVarFlag(self, var, flag):
local_var = self._findVar(var)
if not local_var:
return
@@ -586,38 +357,23 @@ class DataSmart(MutableMapping):
self._makeShadowCopy(var)
if var in self.dict and flag in self.dict[var]:
loginfo['detail'] = ""
loginfo['op'] = 'delFlag'
loginfo['flag'] = flag
self.varhistory.record(**loginfo)
del self.dict[var][flag]
def appendVarFlag(self, var, flag, value, **loginfo):
loginfo['op'] = 'append'
loginfo['flag'] = flag
self.varhistory.record(**loginfo)
newvalue = (self.getVarFlag(var, flag, False) or "") + value
self.setVarFlag(var, flag, newvalue, ignore=True)
def appendVarFlag(self, key, flag, value):
value = (self.getVarFlag(key, flag, False) or "") + value
self.setVarFlag(key, flag, value)
def prependVarFlag(self, var, flag, value, **loginfo):
loginfo['op'] = 'prepend'
loginfo['flag'] = flag
self.varhistory.record(**loginfo)
newvalue = value + (self.getVarFlag(var, flag, False) or "")
self.setVarFlag(var, flag, newvalue, ignore=True)
def prependVarFlag(self, key, flag, value):
value = value + (self.getVarFlag(key, flag, False) or "")
self.setVarFlag(key, flag, value)
def setVarFlags(self, var, flags, **loginfo):
infer_caller_details(loginfo)
def setVarFlags(self, var, flags):
if not var in self.dict:
self._makeShadowCopy(var)
for i in flags:
if i == "_content":
continue
loginfo['flag'] = i
loginfo['detail'] = flags[i]
self.varhistory.record(**loginfo)
self.dict[var][i] = flags[i]
def getVarFlags(self, var):
@@ -635,16 +391,13 @@ class DataSmart(MutableMapping):
return flags
def delVarFlags(self, var, **loginfo):
def delVarFlags(self, var):
if not var in self.dict:
self._makeShadowCopy(var)
if var in self.dict:
content = None
loginfo['op'] = 'delete flags'
self.varhistory.record(**loginfo)
# try to save the content
if "_content" in self.dict[var]:
content = self.dict[var]["_content"]
@@ -661,11 +414,6 @@ class DataSmart(MutableMapping):
# we really want this to be a DataSmart...
data = DataSmart(seen=self._seen_overrides.copy(), special=self._special_values.copy())
data.dict["_data"] = self.dict
data.varhistory = self.varhistory.copy()
data.varhistory.datasmart = data
data.inchistory = self.inchistory.copy()
data._tracking = self._tracking
return data
@@ -726,27 +474,13 @@ class DataSmart(MutableMapping):
def get_hash(self):
data = {}
d = self.createCopy()
bb.data.expandKeys(d)
bb.data.update_data(d)
config_whitelist = set((d.getVar("BB_HASHCONFIG_WHITELIST", True) or "").split())
keys = set(key for key in iter(d) if not key.startswith("__"))
config_whitelist = set((self.getVar("BB_HASHCONFIG_WHITELIST", True) or "").split())
keys = set(key for key in iter(self) if not key.startswith("__"))
for key in keys:
if key in config_whitelist:
continue
value = d.getVar(key, False) or ""
value = self.getVar(key, False) or ""
data.update({key:value})
for key in ["__BBTASKS", "__BBANONFUNCS", "__BBHANDLERS"]:
bb_list = d.getVar(key, False) or []
bb_list.sort()
data.update({key:str(bb_list)})
if key == "__BBANONFUNCS":
for i in bb_list:
value = d.getVar(i, True) or ""
data.update({i:value})
data_str = str([(k, data[k]) for k in sorted(data.keys())])
return hashlib.md5(data_str).hexdigest()

View File

@@ -47,23 +47,21 @@ class Event(object):
def __init__(self):
self.pid = worker_pid
NotHandled = 0
Handled = 1
Registered = 10
AlreadyRegistered = 14
def get_class_handlers():
return _handlers
def set_class_handlers(h):
_handlers = h
def clean_class_handlers():
return bb.compat.OrderedDict()
# Internal
_handlers = clean_class_handlers()
_handlers = bb.compat.OrderedDict()
_ui_handlers = {}
_ui_handler_seq = 0
# For compatibility
bb.utils._context["NotHandled"] = NotHandled
bb.utils._context["Handled"] = Handled
def execute_handler(name, handler, event, d):
event.data = d
try:
@@ -82,6 +80,10 @@ def execute_handler(name, handler, event, d):
finally:
del event.data
if ret is not None:
warnings.warn("Using Handled/NotHandled in event handlers is deprecated",
DeprecationWarning, stacklevel = 2)
def fire_class_handlers(event, d):
if isinstance(event, logging.LogRecord):
return
@@ -564,19 +566,3 @@ class SanityCheckFailed(Event):
Event.__init__(self)
self._msg = msg
self._network_error = network_error
class NetworkTest(Event):
"""
Event to start network test
"""
class NetworkTestPassed(Event):
"""
Event to indicate network test has passed
"""
class NetworkTestFailed(Event):
"""
Event to indicate network test has failed
"""

View File

@@ -28,20 +28,11 @@ BitBake build tools.
from __future__ import absolute_import
from __future__ import print_function
import os, re
import signal
import glob
import logging
import urllib
import urlparse
if 'git' not in urlparse.uses_netloc:
urlparse.uses_netloc.append('git')
from urlparse import urlparse
import operator
import bb.persist_data, bb.utils
import bb.checksum
from bb import data
import bb.process
import subprocess
__version__ = "2"
_checksum_cache = bb.checksum.FileChecksumCache()
@@ -78,9 +69,6 @@ class FetchError(BBFetchException):
class ChecksumError(FetchError):
"""Exception when mismatched checksum encountered"""
def __init__(self, message, url = None, checksum = None):
self.checksum = checksum
FetchError.__init__(self, message, url)
class NoChecksumError(FetchError):
"""Exception when no checksum is specified, but BB_STRICT_CHECKSUM is set"""
@@ -131,199 +119,6 @@ class NonLocalMethod(Exception):
def __init__(self):
Exception.__init__(self)
class URI(object):
"""
A class representing a generic URI, with methods for
accessing the URI components, and stringifies to the
URI.
It is constructed by calling it with a URI, or setting
the attributes manually:
uri = URI("http://example.com/")
uri = URI()
uri.scheme = 'http'
uri.hostname = 'example.com'
uri.path = '/'
It has the following attributes:
* scheme (read/write)
* userinfo (authentication information) (read/write)
* username (read/write)
* password (read/write)
Note, password is deprecated as of RFC 3986.
* hostname (read/write)
* port (read/write)
* hostport (read only)
"hostname:port", if both are set, otherwise just "hostname"
* path (read/write)
* path_quoted (read/write)
A URI quoted version of path
* params (dict) (read/write)
* relative (bool) (read only)
True if this is a "relative URI", (e.g. file:foo.diff)
It stringifies to the URI itself.
Some notes about relative URIs: while it's specified that
a URI beginning with <scheme>:// should either be directly
followed by a hostname or a /, the old URI handling of the
fetch2 library did not comform to this. Therefore, this URI
class has some kludges to make sure that URIs are parsed in
a way comforming to bitbake's current usage. This URI class
supports the following:
file:relative/path.diff (IETF compliant)
git:relative/path.git (IETF compliant)
git:///absolute/path.git (IETF compliant)
file:///absolute/path.diff (IETF compliant)
file://relative/path.diff (not IETF compliant)
But it does not support the following:
file://hostname/absolute/path.diff (would be IETF compliant)
Note that the last case only applies to a list of
"whitelisted" schemes (currently only file://), that requires
its URIs to not have a network location.
"""
_relative_schemes = ['file', 'git']
_netloc_forbidden = ['file']
def __init__(self, uri=None):
self.scheme = ''
self.userinfo = ''
self.hostname = ''
self.port = None
self._path = ''
self.params = {}
self.relative = False
if not uri:
return
urlp = urlparse(uri)
self.scheme = urlp.scheme
# Convert URI to be relative
if urlp.scheme in self._netloc_forbidden:
uri = re.sub("(?<=:)//(?!/)", "", uri, 1)
urlp = urlparse(uri)
# Identify if the URI is relative or not
if urlp.scheme in self._relative_schemes and \
re.compile("^\w+:(?!//)").match(uri):
self.relative = True
if not self.relative:
self.hostname = urlp.hostname or ''
self.port = urlp.port
self.userinfo += urlp.username or ''
if urlp.password:
self.userinfo += ':%s' % urlp.password
# Do support params even for URI schemes that Python's
# urlparse doesn't support params for.
path = ''
param_str = ''
if not urlp.params:
path, param_str = (list(urlp.path.split(";", 1)) + [None])[:2]
else:
path = urlp.path
param_str = urlp.params
self.path = urllib.unquote(path)
if param_str:
self.params = self._param_dict(param_str)
def __str__(self):
userinfo = self.userinfo
if userinfo:
userinfo += '@'
return "%s:%s%s%s%s%s" % (
self.scheme,
'' if self.relative else '//',
userinfo,
self.hostport,
self.path_quoted,
self._param_str)
@property
def _param_str(self):
ret = ''
for key, val in self.params.items():
ret += ";%s=%s" % (key, val)
return ret
def _param_dict(self, param_str):
parm = {}
for keyval in param_str.split(";"):
key, val = keyval.split("=", 1)
parm[key] = val
return parm
@property
def hostport(self):
if not self.port:
return self.hostname
return "%s:%d" % (self.hostname, self.port)
@property
def path_quoted(self):
return urllib.quote(self.path)
@path_quoted.setter
def path_quoted(self, path):
self.path = urllib.unquote(path)
@property
def path(self):
return self._path
@path.setter
def path(self, path):
self._path = path
if re.compile("^/").match(path):
self.relative = False
else:
self.relative = True
@property
def username(self):
if self.userinfo:
return (self.userinfo.split(":", 1))[0]
return ''
@username.setter
def username(self, username):
self.userinfo = username
if self.password:
self.userinfo += ":%s" % self.password
@property
def password(self):
if self.userinfo and ":" in self.userinfo:
return (self.userinfo.split(":", 1))[1]
return ''
@password.setter
def password(self, password):
self.userinfo = "%s:%s" % (self.username, password)
def decodeurl(url):
"""Decodes an URL into the tokens (scheme, network location, path,
user, password, parameters).
@@ -418,8 +213,6 @@ def uri_replace(ud, uri_find, uri_replace, replacements, d):
return None
# Overwrite any specified replacement parameters
for k in uri_replace_decoded[loc]:
for l in replacements:
uri_replace_decoded[loc][k] = uri_replace_decoded[loc][k].replace(l, replacements[l])
result_decoded[loc][k] = uri_replace_decoded[loc][k]
elif (re.match(regexp, uri_decoded[loc])):
if not uri_replace_decoded[loc]:
@@ -568,7 +361,7 @@ def verify_checksum(u, ud, d):
msg = msg + '\nIf this change is expected (e.g. you have upgraded to a new version without updating the checksums) then you can use these lines within the recipe:\nSRC_URI[%s] = "%s"\nSRC_URI[%s] = "%s"\nOtherwise you should retry the download and/or check with upstream to determine if the file has become corrupted or otherwise unexpectedly modified.\n' % (ud.md5_name, md5data, ud.sha256_name, sha256data)
if len(msg):
raise ChecksumError('Checksum mismatch!%s' % msg, u, md5data)
raise ChecksumError('Checksum mismatch!%s' % msg, u)
def update_stamp(u, ud, d):
@@ -588,6 +381,7 @@ def update_stamp(u, ud, d):
open(ud.donestamp, 'w').close()
def subprocess_setup():
import signal
# Python installs a SIGPIPE handler by default. This is usually not what
# non-Python subprocesses expect.
# SIGPIPE errors are known issues with gzip/bash
@@ -619,12 +413,7 @@ def get_srcrev(d):
raise FetchError("SRCREV was used yet no valid SCM was found in SRC_URI")
if len(scms) == 1 and len(urldata[scms[0]].names) == 1:
autoinc, rev = urldata[scms[0]].method.sortable_revision(scms[0], urldata[scms[0]], d, urldata[scms[0]].names[0])
if len(rev) > 10:
rev = rev[:10]
if autoinc:
return "AUTOINC+" + rev
return rev
return urldata[scms[0]].method.sortable_revision(scms[0], urldata[scms[0]], d, urldata[scms[0]].names[0])
#
# Mutiple SCMs are in SRC_URI so we resort to SRCREV_FORMAT
@@ -633,16 +422,10 @@ def get_srcrev(d):
if not format:
raise FetchError("The SRCREV_FORMAT variable must be set when multiple SCMs are used.")
seenautoinc = False
for scm in scms:
ud = urldata[scm]
for name in ud.names:
autoinc, rev = ud.method.sortable_revision(scm, ud, d, name)
if len(rev) > 10:
rev = rev[:10]
if autoinc and not seenautoinc:
rev = "AUTOINC+" + rev
seenautoinc = True
rev = ud.method.sortable_revision(scm, ud, d, name)
format = format.replace(name, rev)
return format
@@ -659,20 +442,18 @@ def runfetchcmd(cmd, d, quiet = False, cleanup = []):
Optionally remove the files/directories listed in cleanup upon failure
"""
import bb.process
import subprocess
# Need to export PATH as binary could be in metadata paths
# rather than host provided
# Also include some other variables.
# FIXME: Should really include all export varaiables?
exportvars = ['HOME', 'PATH',
'HTTP_PROXY', 'http_proxy',
'HTTPS_PROXY', 'https_proxy',
'FTP_PROXY', 'ftp_proxy',
'FTPS_PROXY', 'ftps_proxy',
'NO_PROXY', 'no_proxy',
'ALL_PROXY', 'all_proxy',
'GIT_PROXY_COMMAND',
'SSH_AUTH_SOCK', 'SSH_AGENT_PID',
'SOCKS5_USER', 'SOCKS5_PASSWD']
exportvars = ['PATH', 'GIT_PROXY_COMMAND', 'GIT_PROXY_HOST',
'GIT_PROXY_PORT', 'GIT_CONFIG', 'http_proxy', 'ftp_proxy',
'https_proxy', 'no_proxy', 'ALL_PROXY', 'all_proxy',
'SSH_AUTH_SOCK', 'SSH_AGENT_PID', 'HOME',
'GIT_PROXY_IGNORE', 'SOCKS5_USER', 'SOCKS5_PASSWD']
for var in exportvars:
val = d.getVar(var, True)
@@ -759,19 +540,6 @@ def build_mirroruris(origud, mirrors, ld):
return uris, uds
def rename_bad_checksum(ud, suffix):
"""
Renames files to have suffix from parameter
"""
if ud.localpath is None:
return
new_localpath = "%s_bad-checksum_%s" % (ud.localpath, suffix)
bb.warn("Renaming %s to %s" % (ud.localpath, new_localpath))
bb.utils.movefile(ud.localpath, new_localpath)
def try_mirror_url(newuri, origud, ud, ld, check = False):
# Return of None or a value means we're finished
# False means try another url
@@ -800,7 +568,6 @@ def try_mirror_url(newuri, origud, ud, ld, check = False):
dldir = ld.getVar("DL_DIR", True)
if origud.mirrortarball and os.path.basename(ud.localpath) == os.path.basename(origud.mirrortarball) \
and os.path.basename(ud.localpath) != os.path.basename(origud.localpath):
bb.utils.mkdirhier(os.path.dirname(ud.donestamp))
open(ud.donestamp, 'w').close()
dest = os.path.join(dldir, os.path.basename(ud.localpath))
if not os.path.exists(dest):
@@ -823,7 +590,6 @@ def try_mirror_url(newuri, origud, ud, ld, check = False):
if isinstance(e, ChecksumError):
logger.warn("Mirror checksum failure for url %s (original url: %s)\nCleaning and trying again." % (newuri, origud.url))
logger.warn(str(e))
rename_bad_checksum(ud, e.checksum)
elif isinstance(e, NoChecksumError):
raise
else:
@@ -875,14 +641,11 @@ def srcrev_internal_helper(ud, d, name):
if not rev:
rev = d.getVar("SRCREV_%s" % name, True)
if not rev:
rev = d.getVar("SRCREV_pn-%s" % pn, True)
rev = d.getVar("SRCREV_pn-%s" % pn, True)
if not rev:
rev = d.getVar("SRCREV", True)
if rev == "INVALID":
var = "SRCREV_pn-%s" % pn
if name != '':
var = "SRCREV_%s_pn-%s" % (name, pn)
raise FetchError("Please set %s to a valid value" % var, ud.url)
raise FetchError("Please set SRCREV to a valid value", ud.url)
if rev == "AUTOINC":
rev = ud.method.latest_revision(ud.url, ud, d, name)
@@ -929,6 +692,7 @@ def get_file_checksums(filelist, pn):
try:
checksum = _checksum_cache.get_checksum(f)
except OSError as e:
import traceback
bb.warn("Unable to get checksum for %s SRC_URI entry %s: %s" % (pn, os.path.basename(f), e))
return None
return checksum
@@ -938,6 +702,7 @@ def get_file_checksums(filelist, pn):
checksum = None
if '*' in pth:
# Handle globs
import glob
for f in glob.glob(pth):
checksum = checksum_file(f)
if checksum:
@@ -956,7 +721,7 @@ def get_file_checksums(filelist, pn):
if checksum:
checksums.append((pth, checksum))
checksums.sort(key=operator.itemgetter(1))
checksums.sort()
return checksums
@@ -972,7 +737,6 @@ class FetchData(object):
self.lockfile = None
self.mirrortarball = None
self.basename = None
self.basepath = None
(self.type, self.host, self.path, self.user, self.pswd, self.parm) = decodeurl(data.expand(url, d))
self.date = self.getSRCDate(d)
self.url = url
@@ -1029,14 +793,8 @@ class FetchData(object):
elif self.localfile:
self.localpath = self.method.localpath(self.url, self, d)
dldir = d.getVar("DL_DIR", True)
# Note: .done and .lock files should always be in DL_DIR whereas localpath may not be.
if self.localpath and self.localpath.startswith(dldir):
basepath = self.localpath
elif self.localpath:
basepath = dldir + os.sep + os.path.basename(self.localpath)
else:
basepath = dldir + os.sep + (self.basepath or self.basename)
# Note: These files should always be in DL_DIR whereas localpath may not be.
basepath = d.expand("${DL_DIR}/%s" % os.path.basename(self.localpath or self.basename))
self.donestamp = basepath + '.done'
self.lockfile = basepath + '.lock'
@@ -1147,6 +905,7 @@ class FetchMethod(object):
raise NoMethodError(url)
def unpack(self, urldata, rootdir, data):
import subprocess
iterate = False
file = urldata.localpath
@@ -1204,18 +963,15 @@ class FetchMethod(object):
dest = os.path.join(rootdir, os.path.basename(file))
if (file != dest) and not (os.path.exists(dest) and os.path.samefile(file, dest)):
if os.path.isdir(file):
# If for example we're asked to copy file://foo/bar, we need to unpack the result into foo/bar
basepath = getattr(urldata, "basepath", None)
filesdir = os.path.realpath(data.getVar("FILESDIR", True))
destdir = "."
if basepath and basepath.endswith("/"):
basepath = basepath.rstrip("/")
elif basepath:
basepath = os.path.dirname(basepath)
if basepath and basepath.find("/") != -1:
destdir = basepath[:basepath.rfind('/')]
if file[0:len(filesdir)] == filesdir:
destdir = file[len(filesdir):file.rfind('/')]
destdir = destdir.strip('/')
if destdir != "." and not os.access("%s/%s" % (rootdir, destdir), os.F_OK):
os.makedirs("%s/%s" % (rootdir, destdir))
if len(destdir) < 1:
destdir = "."
elif not os.access("%s/%s" % (rootdir, destdir), os.F_OK):
os.makedirs("%s/%s" % (rootdir, destdir))
cmd = 'cp -pPR %s %s/%s/' % (file, rootdir, destdir)
#cmd = 'tar -cf - -C "%d" -ps . | tar -xf - -C "%s/%s/"' % (file, rootdir, destdir)
else:
@@ -1277,6 +1033,23 @@ class FetchMethod(object):
logger.info("URL %s could not be checked for status since no method exists.", url)
return True
def localcount_internal_helper(ud, d, name):
"""
Return:
a) a locked localcount if specified
b) None otherwise
"""
localcount = None
if name != '':
pn = d.getVar("PN", True)
localcount = d.getVar("LOCALCOUNT_" + name, True)
if not localcount:
localcount = d.getVar("LOCALCOUNT", True)
return localcount
localcount_internal_helper = staticmethod(localcount_internal_helper)
def latest_revision(self, url, ud, d, name):
"""
Look in the cache for the latest revision, if not present ask the SCM.
@@ -1293,8 +1066,42 @@ class FetchMethod(object):
return rev
def sortable_revision(self, url, ud, d, name):
"""
"""
if hasattr(self, "_sortable_revision"):
return self._sortable_revision(url, ud, d)
localcounts = bb.persist_data.persist('BB_URI_LOCALCOUNT', d)
key = self.generate_revision_key(url, ud, d, name)
latest_rev = self._build_revision(url, ud, d, name)
return True, str(latest_rev)
last_rev = localcounts.get(key + '_rev')
uselocalcount = d.getVar("BB_LOCALCOUNT_OVERRIDE", True) or False
count = None
if uselocalcount:
count = FetchMethod.localcount_internal_helper(ud, d, name)
if count is None:
count = localcounts.get(key + '_count') or "0"
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 generate_revision_key(self, url, ud, d, name):
key = self._revision_key(url, ud, d, name)
@@ -1399,7 +1206,6 @@ class Fetch(object):
if isinstance(e, ChecksumError):
logger.warn("Checksum failure encountered with download of %s - will attempt other sources if available" % u)
logger.debug(1, str(e))
rename_bad_checksum(ud, e.checksum)
elif isinstance(e, NoChecksumError):
raise
else:
@@ -1509,13 +1315,11 @@ class Fetch(object):
from . import cvs
from . import git
from . import gitsm
from . import local
from . import svn
from . import wget
from . import svk
from . import ssh
from . import sftp
from . import perforce
from . import bzr
from . import hg
@@ -1526,11 +1330,9 @@ methods.append(local.Local())
methods.append(wget.Wget())
methods.append(svn.Svn())
methods.append(git.Git())
methods.append(gitsm.GitSM())
methods.append(cvs.Cvs())
methods.append(svk.Svk())
methods.append(ssh.SSH())
methods.append(sftp.SFTP())
methods.append(perforce.Perforce())
methods.append(bzr.Bzr())
methods.append(hg.Hg())

View File

@@ -132,12 +132,12 @@ class Bzr(FetchMethod):
return output.strip()
def sortable_revision(self, url, ud, d, name):
def _sortable_revision(self, url, ud, d):
"""
Return a sortable revision number which in our case is the revision number
"""
return False, self._build_revision(url, ud, d)
return self._build_revision(url, ud, d)
def _build_revision(self, url, ud, d):
return ud.revision

View File

@@ -11,8 +11,8 @@ Supported SRC_URI options are:
- branch
The git branch to retrieve from. The default is "master"
This option also supports multiple branch fetching, with branches
separated by commas. In multiple branches case, the name option
this option also support multiple branches fetching, branches
are seperated by comma. in multiple branches case, the name option
must have the same number of names to match the branches, which is
used to specify the SRC_REV for the branch
e.g:
@@ -25,13 +25,13 @@ Supported SRC_URI options are:
- protocol
The method to use to access the repository. Common options are "git",
"http", "https", "file", "ssh" and "rsync". The default is "git".
"http", "file" and "rsync". The default is "git"
- rebaseable
rebaseable indicates that the upstream git repo may rebase in the future,
and current revision may disappear from upstream repo. This option will
remind fetcher to preserve local cache carefully for future use.
The default value is "0", set rebaseable=1 for rebaseable git repo.
reminder fetcher to preserve local cache carefully for future use.
The default value is "0", set rebaseable=1 for rebaseable git repo
- nocheckout
Don't checkout source code when unpacking. set this option for the recipe
@@ -71,8 +71,11 @@ from bb.fetch2 import logger
class Git(FetchMethod):
"""Class to fetch a module or modules from git repositories"""
def init(self, d):
pass
#
# Only enable _sortable revision if the key is set
#
if d.getVar("BB_GIT_CLONE_FOR_SRCREV", 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.
@@ -217,10 +220,6 @@ class Git(FetchMethod):
def build_mirror_data(self, url, ud, d):
# Generate a mirror tarball if needed
if ud.write_tarballs and (ud.repochanged or not os.path.exists(ud.fullmirror)):
# it's possible that this symlink points to read-only filesystem with PREMIRROR
if os.path.islink(ud.fullmirror):
os.unlink(ud.fullmirror)
os.chdir(ud.clonedir)
logger.info("Creating tarball of git repository")
runfetchcmd("tar -czf %s %s" % (ud.fullmirror, os.path.join(".") ), d)
@@ -238,7 +237,7 @@ class Git(FetchMethod):
def_destsuffix = "git/"
destsuffix = ud.parm.get("destsuffix", def_destsuffix)
destdir = ud.destdir = os.path.join(destdir, destsuffix)
destdir = os.path.join(destdir, destsuffix)
if os.path.exists(destdir):
bb.utils.prunedir(destdir)
@@ -317,6 +316,38 @@ class Git(FetchMethod):
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):
logger.debug(1, "GIT repository for %s does not exist in %s. \
Downloading.", url, ud.clonedir)
self.download(None, ud, d)
if not os.path.exists(ud.clonedir):
logger.error("GIT repository for %s does not exist in %s after \
download. 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
def checkstatus(self, uri, ud, d):
fetchcmd = "%s ls-remote %s" % (ud.basecmd, uri)
try:

View File

@@ -1,78 +0,0 @@
# ex:ts=4:sw=4:sts=4:et
# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
"""
BitBake 'Fetch' git submodules implementation
"""
# Copyright (C) 2013 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.git import Git
from bb.fetch2 import runfetchcmd
from bb.fetch2 import logger
class GitSM(Git):
def supports(self, url, ud, d):
"""
Check to see if a given url can be fetched with git.
"""
return ud.type in ['gitsm']
def uses_submodules(self, ud, d):
for name in ud.names:
try:
runfetchcmd("%s show %s:.gitmodules" % (ud.basecmd, ud.revisions[name]), d, quiet=True)
return True
except bb.fetch.FetchError:
pass
return False
def update_submodules(self, u, ud, d):
# We have to convert bare -> full repo, do the submodule bit, then convert back
tmpclonedir = ud.clonedir + ".tmp"
gitdir = tmpclonedir + os.sep + ".git"
bb.utils.remove(tmpclonedir, True)
os.mkdir(tmpclonedir)
os.rename(ud.clonedir, gitdir)
runfetchcmd("sed " + gitdir + "/config -i -e 's/bare.*=.*true/bare = false/'", d)
os.chdir(tmpclonedir)
runfetchcmd("git reset --hard", d)
runfetchcmd("git submodule init", d)
runfetchcmd("git submodule update", d)
runfetchcmd("sed " + gitdir + "/config -i -e 's/bare.*=.*false/bare = true/'", d)
os.rename(gitdir, ud.clonedir,)
bb.utils.remove(tmpclonedir, True)
def download(self, loc, ud, d):
Git.download(self, loc, ud, d)
os.chdir(ud.clonedir)
submodules = self.uses_submodules(ud, d)
if submodules:
self.update_submodules(loc, ud, d)
def unpack(self, ud, destdir, d):
Git.unpack(self, ud, destdir, d)
os.chdir(ud.destdir)
submodules = self.uses_submodules(ud, d)
if submodules:
runfetchcmd("cp -r " + ud.clonedir + "/modules " + ud.destdir + "/.git/", d)
runfetchcmd("git submodule init", d)
runfetchcmd("git submodule update", d)

View File

@@ -98,12 +98,7 @@ class Hg(FetchMethod):
return "%s identify -i %s://%s/%s" % (basecmd, proto, hgroot, ud.module)
options = [];
# Don't specify revision for the fetch; clone the entire repo.
# This avoids an issue if the specified revision is a tag, because
# the tag actually exists in the specified revision + 1, so it won't
# be available when used in any successive commands.
if ud.revision and command != "fetch":
if ud.revision:
options.append("-r %s" % ud.revision)
if command == "fetch":

View File

@@ -44,7 +44,6 @@ class Local(FetchMethod):
# We don't set localfile as for this fetcher the file is already local!
ud.decodedurl = urllib.unquote(ud.url.split("://")[1].split(";")[0])
ud.basename = os.path.basename(ud.decodedurl)
ud.basepath = ud.decodedurl
return
def localpath(self, url, urldata, d):
@@ -63,12 +62,7 @@ class Local(FetchMethod):
if filesdir:
logger.debug(2, "Searching for %s in path: %s" % (path, filesdir))
newpath = os.path.join(filesdir, path)
if (not newpath or not os.path.exists(newpath)) and path.find("*") != -1:
# For expressions using '*', best we can do is take the first directory in FILESPATH that exists
newpath = bb.utils.which(filespath, ".")
logger.debug(2, "Searching for %s in path: %s" % (path, newpath))
return newpath
if not os.path.exists(newpath):
if not os.path.exists(newpath) and path.find("*") == -1:
dldirfile = os.path.join(d.getVar("DL_DIR", True), path)
logger.debug(2, "Defaulting to %s for %s" % (dldirfile, path))
bb.utils.mkdirhier(os.path.dirname(dldirfile))

View File

@@ -170,7 +170,7 @@ class Perforce(FetchMethod):
logger.info("Fetch " + loc)
logger.info("%s%s files %s", p4cmd, p4opt, depot)
p4file, errors = bb.process.run("%s%s files %s" % (p4cmd, p4opt, depot))
p4file = [f.rstrip() for f in p4file.splitlines()]
p4file = p4file.strip()
if not p4file:
raise FetchError("Fetch: unable to get the P4 files from %s" % depot, loc)

View File

@@ -1,129 +0,0 @@
# ex:ts=4:sw=4:sts=4:et
# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
"""
BitBake SFTP Fetch implementation
Class for fetching files via SFTP. It tries to adhere to the (now
expired) IETF Internet Draft for "Uniform Resource Identifier (URI)
Scheme for Secure File Transfer Protocol (SFTP) and Secure Shell
(SSH)" (SECSH URI).
It uses SFTP (as to adhere to the SECSH URI specification). It only
supports key based authentication, not password. This class, unlike
the SSH fetcher, does not support fetching a directory tree from the
remote.
http://tools.ietf.org/html/draft-ietf-secsh-scp-sftp-ssh-uri-04
https://www.iana.org/assignments/uri-schemes/prov/sftp
https://tools.ietf.org/html/draft-ietf-secsh-filexfer-13
Please note that '/' is used as host path seperator, and not ":"
as you may be used to from the scp/sftp commands. You can use a
~ (tilde) to specify a path relative to your home directory.
(The /~user/ syntax, for specyfing a path relative to another
user's home directory is not supported.) Note that the tilde must
still follow the host path seperator ("/"). See exampels below.
Example SRC_URIs:
SRC_URI = "sftp://host.example.com/dir/path.file.txt"
A path relative to your home directory.
SRC_URI = "sftp://host.example.com/~/dir/path.file.txt"
You can also specify a username (specyfing password in the
URI is not supported, use SSH keys to authenticate):
SRC_URI = "sftp://user@host.example.com/dir/path.file.txt"
"""
# Copyright (C) 2013, Olof Johansson <olof.johansson@axis.com>
#
# Based in part on bb.fetch2.wget:
# 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 urllib
import commands
from bb import data
from bb.fetch2 import URI
from bb.fetch2 import FetchMethod
from bb.fetch2 import runfetchcmd
class SFTP(FetchMethod):
"""Class to fetch urls via 'sftp'"""
def supports(self, url, ud, d):
"""
Check to see if a given url can be fetched with sftp.
"""
return ud.type in ['sftp']
def recommends_checksum(self, urldata):
return True
def urldata_init(self, ud, d):
if 'protocol' in ud.parm and ud.parm['protocol'] == 'git':
raise bb.fetch2.ParameterError(
"Invalid protocol - if you wish to fetch from a " +
"git repository using ssh, you need to use the " +
"git:// prefix with protocol=ssh", ud.url)
if 'downloadfilename' in ud.parm:
ud.basename = ud.parm['downloadfilename']
else:
ud.basename = os.path.basename(ud.path)
ud.localfile = data.expand(urllib.unquote(ud.basename), d)
def download(self, uri, ud, d):
"""Fetch urls"""
urlo = URI(uri)
basecmd = 'sftp -oPasswordAuthentication=no'
port = ''
if urlo.port:
port = '-P %d' % urlo.port
urlo.port = None
dldir = data.getVar('DL_DIR', d, True)
lpath = os.path.join(dldir, ud.localfile)
user = ''
if urlo.userinfo:
user = urlo.userinfo + '@'
path = urlo.path
# Supoprt URIs relative to the user's home directory, with
# the tilde syntax. (E.g. <sftp://example.com/~/foo.diff>).
if path[:3] == '/~/':
path = path[3:]
remote = '%s%s:%s' % (user, urlo.hostname, path)
cmd = '%s %s %s %s' % (basecmd, port, commands.mkarg(remote),
commands.mkarg(lpath))
bb.fetch2.check_network_access(d, cmd, uri)
runfetchcmd(cmd, d)
return True

View File

@@ -10,12 +10,6 @@ IETF secsh internet draft:
Currently does not support the sftp parameters, as this uses scp
Also does not support the 'fingerprint' connection parameter.
Please note that '/' is used as host, path separator not ':' as you may
be used to, also '~' can be used to specify user HOME, but again after '/'
Example SRC_URI:
SRC_URI = "ssh://user@host.example.com/dir/path/file.txt"
SRC_URI = "ssh://user@host.example.com/~/file.txt"
'''
# Copyright (C) 2006 OpenedHand Ltd.
@@ -78,19 +72,15 @@ class SSH(FetchMethod):
def supports_checksum(self, urldata):
return False
def urldata_init(self, urldata, d):
if 'protocol' in urldata.parm and urldata.parm['protocol'] == 'git':
raise bb.fetch2.ParameterError(
"Invalid protocol - if you wish to fetch from a git " +
"repository using ssh, you need to use " +
"git:// prefix with protocol=ssh", urldata.url)
def localpath(self, url, urldata, d):
m = __pattern__.match(urldata.url)
path = m.group('path')
host = m.group('host')
urldata.localpath = os.path.join(d.getVar('DL_DIR', True), os.path.basename(path))
lpath = os.path.join(data.getVar('DL_DIR', d, True), host, os.path.basename(path))
return lpath
def download(self, url, urldata, d):
dldir = d.getVar('DL_DIR', True)
dldir = data.getVar('DL_DIR', d, True)
m = __pattern__.match(url)
path = m.group('path')
@@ -99,10 +89,16 @@ class SSH(FetchMethod):
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:
portarg = '-P %s' % port
port = '-P %s' % port
else:
portarg = ''
port = ''
if user:
fr = user
@@ -116,9 +112,9 @@ class SSH(FetchMethod):
import commands
cmd = 'scp -B -r %s %s %s/' % (
portarg,
port,
commands.mkarg(fr),
commands.mkarg(dldir)
commands.mkarg(ldir)
)
bb.fetch2.check_network_access(d, cmd, urldata.url)

View File

@@ -81,8 +81,6 @@ class Svn(FetchMethod):
options = []
options.append("--no-auth-cache")
if ud.user:
options.append("--username %s" % ud.user)
@@ -178,12 +176,12 @@ class Svn(FetchMethod):
return revision
def sortable_revision(self, url, ud, d, name):
def _sortable_revision(self, url, ud, d):
"""
Return a sortable revision number which in our case is the revision number
"""
return False, self._build_revision(url, ud, d)
return self._build_revision(url, ud, d)
def _build_revision(self, url, ud, d):
return ud.revision

View File

@@ -32,6 +32,8 @@ 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
@@ -63,20 +65,21 @@ class Wget(FetchMethod):
basecmd = d.getVar("FETCHCMD_wget", True) or "/usr/bin/env wget -t 2 -T 30 -nv --passive-ftp --no-check-certificate"
if not checkonly and 'downloadfilename' in ud.parm:
dldir = d.getVar("DL_DIR", True)
bb.utils.mkdirhier(os.path.dirname(dldir + os.sep + ud.localfile))
basecmd += " -O " + dldir + os.sep + ud.localfile
if 'downloadfilename' in ud.parm:
basecmd += " -O ${DL_DIR}/" + ud.localfile
if checkonly:
fetchcmd = d.getVar("CHECKCOMMAND_wget", True) or d.expand(basecmd + " --spider '${URI}'")
fetchcmd = d.getVar("CHECKCOMMAND_wget", True) or d.expand(basecmd + " -c -P ${DL_DIR} '${URI}'")
elif os.path.exists(ud.localpath):
# file exists, but we didnt complete it.. trying again..
fetchcmd = d.getVar("RESUMECOMMAND_wget", True) or d.expand(basecmd + " -c -P ${DL_DIR} '${URI}'")
fetchcmd = d.getVar("RESUMECOMMAND_wget", True) or d.expand(basecmd + " --spider -P ${DL_DIR} '${URI}'")
else:
fetchcmd = d.getVar("FETCHCOMMAND_wget", True) or d.expand(basecmd + " -P ${DL_DIR} '${URI}'")
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)

View File

@@ -17,7 +17,24 @@
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
"""
What is a method pool?
BitBake has a global method scope where .bb, .inc and .bbclass
files can install methods. These methods are parsed from strings.
To avoid recompiling and executing these string we introduce
a method pool to do this task.
This pool will be used to compile and execute the functions. It
will be smart enough to
"""
from bb.utils import better_compile, better_exec
from bb import error
# A dict of function names we have seen
_parsed_fns = { }
def insert_method(modulename, code, fn):
"""
@@ -27,3 +44,28 @@ def insert_method(modulename, code, fn):
comp = better_compile(code, modulename, fn )
better_exec(comp, None, code, fn)
# now some instrumentation
code = comp.co_names
for name in code:
if name in ['None', 'False']:
continue
elif name in _parsed_fns and not _parsed_fns[name] == modulename:
error("The function %s defined in %s was already declared in %s. BitBake has a global python function namespace so shared functions should be declared in a common include file rather than being duplicated, or if the functions are different, please use different function names." % (name, modulename, _parsed_fns[name]))
else:
_parsed_fns[name] = modulename
# A dict of modules the parser has finished with
_parsed_methods = {}
def parsed_module(modulename):
"""
Has module been parsed?
"""
return modulename in _parsed_methods
def set_parsed_module(modulename):
"""
Set module as parsed
"""
_parsed_methods[modulename] = True

View File

@@ -107,7 +107,7 @@ def getDiskData(BBDirs, configuration):
printErr("Invalid disk space value in BB_DISKMON_DIRS: %s" % pathSpaceInodeRe.group(3))
return None
else:
# None means that it is not specified
# 0 means that it is not specified
minSpace = None
minInode = pathSpaceInodeRe.group(4)
@@ -117,7 +117,7 @@ def getDiskData(BBDirs, configuration):
printErr("Invalid inode value in BB_DISKMON_DIRS: %s" % pathSpaceInodeRe.group(4))
return None
else:
# None means that it is not specified
# 0 means that it is not specified
minInode = None
if minSpace is None and minInode is None:
@@ -127,9 +127,8 @@ def getDiskData(BBDirs, configuration):
# DL_DIR may not exist at the very beginning
if not os.path.exists(path):
bb.utils.mkdirhier(path)
dev = getMountedDev(path)
# Use path/action as the key
devDict[os.path.join(path, action)] = [dev, minSpace, minInode]
mountedDev = getMountedDev(path)
devDict[mountedDev] = action, path, minSpace, minInode
return devDict
@@ -193,10 +192,10 @@ class diskMonitor:
# This is for STOPTASKS and ABORT, to avoid print the message repeatly
# during waiting the tasks to finish
self.checked = {}
for k in self.devDict:
self.preFreeS[k] = 0
self.preFreeI[k] = 0
self.checked[k] = False
for dev in self.devDict:
self.preFreeS[dev] = 0
self.preFreeI[dev] = 0
self.checked[dev] = False
if self.spaceInterval is None and self.inodeInterval is None:
self.enableMonitor = False
@@ -205,61 +204,46 @@ class diskMonitor:
""" Take action for the monitor """
if self.enableMonitor:
for k in self.devDict:
path = os.path.dirname(k)
action = os.path.basename(k)
dev = self.devDict[k][0]
minSpace = self.devDict[k][1]
minInode = self.devDict[k][2]
st = os.statvfs(path)
for dev in self.devDict:
st = os.statvfs(self.devDict[dev][1])
# The free space, float point number
freeSpace = st.f_bavail * st.f_frsize
if minSpace and freeSpace < minSpace:
if self.devDict[dev][2] and freeSpace < self.devDict[dev][2]:
# Always show warning, the self.checked would always be False if the action is WARN
if self.preFreeS[k] == 0 or self.preFreeS[k] - freeSpace > self.spaceInterval and not self.checked[k]:
logger.warn("The free space of %s (%s) is running low (%.3fGB left)" % \
(path, dev, freeSpace / 1024 / 1024 / 1024.0))
self.preFreeS[k] = freeSpace
if self.preFreeS[dev] == 0 or self.preFreeS[dev] - freeSpace > self.spaceInterval and not self.checked[dev]:
logger.warn("The free space of %s is running low (%.3fGB left)" % (dev, freeSpace / 1024 / 1024 / 1024.0))
self.preFreeS[dev] = freeSpace
if action == "STOPTASKS" and not self.checked[k]:
if self.devDict[dev][0] == "STOPTASKS" and not self.checked[dev]:
logger.error("No new tasks can be excuted since the disk space monitor action is \"STOPTASKS\"!")
self.checked[k] = True
self.checked[dev] = True
rq.finish_runqueue(False)
bb.event.fire(bb.event.DiskFull(dev, 'disk', freeSpace, path), self.configuration)
elif action == "ABORT" and not self.checked[k]:
bb.event.fire(bb.event.DiskFull(dev, 'disk', freeSpace, self.devDict[dev][1]), self.configuration)
elif self.devDict[dev][0] == "ABORT" and not self.checked[dev]:
logger.error("Immediately abort since the disk space monitor action is \"ABORT\"!")
self.checked[k] = True
self.checked[dev] = True
rq.finish_runqueue(True)
bb.event.fire(bb.event.DiskFull(dev, 'disk', freeSpace, path), self.configuration)
bb.event.fire(bb.event.DiskFull(dev, 'disk', freeSpace, self.devDict[dev][1]), self.configuration)
# The free inodes, float point number
freeInode = st.f_favail
if minInode and freeInode < minInode:
# Some fs formats' (e.g., btrfs) statvfs.f_files (inodes) is
# zero, this is a feature of the fs, we disable the inode
# checking for such a fs.
if st.f_files == 0:
logger.warn("Inode check for %s is unavaliable, will remove it from disk monitor" % path)
self.devDict[k][2] = None
continue
if self.devDict[dev][3] and freeInode < self.devDict[dev][3]:
# Always show warning, the self.checked would always be False if the action is WARN
if self.preFreeI[k] == 0 or self.preFreeI[k] - freeInode > self.inodeInterval and not self.checked[k]:
logger.warn("The free inode of %s (%s) is running low (%.3fK left)" % \
(path, dev, freeInode / 1024.0))
self.preFreeI[k] = freeInode
if self.preFreeI[dev] == 0 or self.preFreeI[dev] - freeInode > self.inodeInterval and not self.checked[dev]:
logger.warn("The free inode of %s is running low (%.3fK left)" % (dev, freeInode / 1024.0))
self.preFreeI[dev] = freeInode
if action == "STOPTASKS" and not self.checked[k]:
if self.devDict[dev][0] == "STOPTASKS" and not self.checked[dev]:
logger.error("No new tasks can be excuted since the disk space monitor action is \"STOPTASKS\"!")
self.checked[k] = True
self.checked[dev] = True
rq.finish_runqueue(False)
bb.event.fire(bb.event.DiskFull(dev, 'inode', freeInode, path), self.configuration)
elif action == "ABORT" and not self.checked[k]:
bb.event.fire(bb.event.DiskFull(dev, 'inode', freeSpace, self.devDict[dev][1]), self.configuration)
elif self.devDict[dev][0] == "ABORT" and not self.checked[dev]:
logger.error("Immediately abort since the disk space monitor action is \"ABORT\"!")
self.checked[k] = True
self.checked[dev] = True
rq.finish_runqueue(True)
bb.event.fire(bb.event.DiskFull(dev, 'inode', freeInode, path), self.configuration)
bb.event.fire(bb.event.DiskFull(dev, 'inode', freeSpace, self.devDict[dev][1]), self.configuration)
return

View File

@@ -23,7 +23,6 @@ Message handling infrastructure for bitbake
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
import sys
import copy
import logging
import collections
from itertools import groupby
@@ -56,25 +55,6 @@ class BBLogFormatter(logging.Formatter):
CRITICAL: 'ERROR',
}
color_enabled = False
BASECOLOR, BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = range(29,38)
COLORS = {
DEBUG3 : CYAN,
DEBUG2 : CYAN,
DEBUG : CYAN,
VERBOSE : BASECOLOR,
NOTE : BASECOLOR,
PLAIN : BASECOLOR,
WARNING : YELLOW,
ERROR : RED,
CRITICAL: RED,
}
BLD = '\033[1;%dm'
STD = '\033[%dm'
RST = '\033[0m'
def getLevelName(self, levelno):
try:
return self.levelnames[levelno]
@@ -87,8 +67,6 @@ class BBLogFormatter(logging.Formatter):
if record.levelno == self.PLAIN:
msg = record.getMessage()
else:
if self.color_enabled:
record = self.colorize(record)
msg = logging.Formatter.format(self, record)
if hasattr(record, 'bb_exc_info'):
@@ -97,17 +75,6 @@ class BBLogFormatter(logging.Formatter):
msg += '\n' + ''.join(formatted)
return msg
def colorize(self, record):
color = self.COLORS[record.levelno]
if self.color_enabled and color is not None:
record = copy.copy(record)
record.levelname = "".join([self.BLD % color, record.levelname, self.RST])
record.msg = "".join([self.STD % color, record.msg, self.RST])
return record
def enable_color(self):
self.color_enabled = True
class BBLogFilter(object):
def __init__(self, handler, level, debug_domains):
self.stdlevel = level

View File

@@ -73,7 +73,8 @@ def update_mtime(f):
def mark_dependency(d, f):
if f.startswith('./'):
f = "%s/%s" % (os.getcwd(), f[2:])
deps = (d.getVar('__depends') or []) + [(f, cached_mtime(f))]
deps = d.getVar('__depends') or set()
deps.update([(f, cached_mtime(f))])
d.setVar('__depends', deps)
def supports(fn, data):
@@ -87,8 +88,7 @@ def handle(fn, data, include = 0):
"""Call the handler that is appropriate for this file"""
for h in handlers:
if h['supports'](fn, data):
with data.inchistory.include(fn):
return h['handle'](fn, data, include)
return h['handle'](fn, data, include)
raise ParseError("not a BitBake file", fn)
def init(fn, data):
@@ -134,8 +134,8 @@ def vars_from_file(mypkg, d):
def get_file_depends(d):
'''Return the dependent files'''
dep_files = []
depends = d.getVar('__base_depends', True) or []
depends = depends + (d.getVar('__depends', True) or [])
depends = d.getVar('__depends', True) or set()
depends = depends.union(d.getVar('__base_depends', True) or set())
for (fn, _) in depends:
dep_files.append(os.path.abspath(fn))
return " ".join(dep_files)

View File

@@ -68,7 +68,7 @@ class ExportNode(AstNode):
self.var = var
def eval(self, data):
data.setVarFlag(self.var, "export", 1, op = 'exported')
data.setVarFlag(self.var, "export", 1)
class DataNode(AstNode):
"""
@@ -90,53 +90,33 @@ class DataNode(AstNode):
def eval(self, data):
groupd = self.groupd
key = groupd["var"]
loginfo = {
'variable': key,
'file': self.filename,
'line': self.lineno,
}
if "exp" in groupd and groupd["exp"] != None:
data.setVarFlag(key, "export", 1, op = 'exported', **loginfo)
op = "set"
data.setVarFlag(key, "export", 1)
if "ques" in groupd and groupd["ques"] != None:
val = self.getFunc(key, data)
op = "set?"
if val == None:
val = groupd["value"]
elif "colon" in groupd and groupd["colon"] != None:
e = data.createCopy()
bb.data.update_data(e)
op = "immediate"
val = e.expand(groupd["value"], key + "[:=]")
elif "append" in groupd and groupd["append"] != None:
op = "append"
val = "%s %s" % ((self.getFunc(key, data) or ""), groupd["value"])
elif "prepend" in groupd and groupd["prepend"] != None:
op = "prepend"
val = "%s %s" % (groupd["value"], (self.getFunc(key, data) or ""))
elif "postdot" in groupd and groupd["postdot"] != None:
op = "postdot"
val = "%s%s" % ((self.getFunc(key, data) or ""), groupd["value"])
elif "predot" in groupd and groupd["predot"] != None:
op = "predot"
val = "%s%s" % (groupd["value"], (self.getFunc(key, data) or ""))
else:
val = groupd["value"]
flag = None
if 'flag' in groupd and groupd['flag'] != None:
flag = groupd['flag']
data.setVarFlag(key, groupd['flag'], val)
elif groupd["lazyques"]:
flag = "defaultval"
loginfo['op'] = op
loginfo['detail'] = groupd["value"]
if flag:
data.setVarFlag(key, flag, val, **loginfo)
data.setVarFlag(key, "defaultval", val)
else:
data.setVar(key, val, **loginfo)
data.setVar(key, val)
class MethodNode(AstNode):
def __init__(self, filename, lineno, func_name, body):
@@ -148,8 +128,9 @@ class MethodNode(AstNode):
text = '\n'.join(self.body)
if self.func_name == "__anonymous":
funcname = ("__anon_%s_%s" % (self.lineno, self.filename.translate(string.maketrans('/.+-', '____'))))
text = "def %s(d):\n" % (funcname) + text
bb.methodpool.insert_method(funcname, text, self.filename)
if not funcname in bb.methodpool._parsed_fns:
text = "def %s(d):\n" % (funcname) + text
bb.methodpool.insert_method(funcname, text, self.filename)
anonfuncs = data.getVar('__BBANONFUNCS') or []
anonfuncs.append(funcname)
data.setVar('__BBANONFUNCS', anonfuncs)
@@ -170,7 +151,8 @@ class PythonMethodNode(AstNode):
# 'this' file. This means we will not parse methods from
# bb classes twice
text = '\n'.join(self.body)
bb.methodpool.insert_method(self.modulename, text, self.filename)
if not bb.methodpool.parsed_module(self.modulename):
bb.methodpool.insert_method(self.modulename, text, self.filename)
data.setVarFlag(self.function, "func", 1)
data.setVarFlag(self.function, "python", 1)
data.setVar(self.function, text)
@@ -197,35 +179,44 @@ class MethodFlagsNode(AstNode):
data.delVarFlag(self.key, "fakeroot")
class ExportFuncsNode(AstNode):
def __init__(self, filename, lineno, fns, classname):
def __init__(self, filename, lineno, fns, classes):
AstNode.__init__(self, filename, lineno)
self.n = fns.split()
self.classname = classname
self.classes = classes
def eval(self, data):
for f in self.n:
allvars = []
allvars.append(f)
allvars.append(self.classes[-1] + "_" + f)
for func in self.n:
calledfunc = self.classname + "_" + func
vars = [[ allvars[0], allvars[1] ]]
if len(self.classes) > 1 and self.classes[-2] is not None:
allvars.append(self.classes[-2] + "_" + f)
vars = []
vars.append([allvars[2], allvars[1]])
vars.append([allvars[0], allvars[2]])
if data.getVar(func) and not data.getVarFlag(func, 'export_func'):
continue
for (var, calledvar) in vars:
if data.getVar(var) and not data.getVarFlag(var, 'export_func'):
continue
if data.getVar(func):
data.setVarFlag(func, 'python', None)
data.setVarFlag(func, 'func', None)
if data.getVar(var):
data.setVarFlag(var, 'python', None)
data.setVarFlag(var, 'func', None)
for flag in [ "func", "python" ]:
if data.getVarFlag(calledfunc, flag):
data.setVarFlag(func, flag, data.getVarFlag(calledfunc, flag))
for flag in [ "dirs" ]:
if data.getVarFlag(func, flag):
data.setVarFlag(calledfunc, flag, data.getVarFlag(func, flag))
for flag in [ "func", "python" ]:
if data.getVarFlag(calledvar, flag):
data.setVarFlag(var, flag, data.getVarFlag(calledvar, flag))
for flag in [ "dirs" ]:
if data.getVarFlag(var, flag):
data.setVarFlag(calledvar, flag, data.getVarFlag(var, flag))
if data.getVarFlag(calledfunc, "python"):
data.setVar(func, " bb.build.exec_func('" + calledfunc + "', d)\n")
else:
data.setVar(func, " " + calledfunc + "\n")
data.setVarFlag(func, 'export_func', '1')
if data.getVarFlag(calledvar, "python"):
data.setVar(var, " bb.build.exec_func('" + calledvar + "', d)\n")
else:
data.setVar(var, " " + calledvar + "\n")
data.setVarFlag(var, 'export_func', '1')
class AddTaskNode(AstNode):
def __init__(self, filename, lineno, func, before, after):
@@ -297,8 +288,8 @@ def handlePythonMethod(statements, filename, lineno, funcname, modulename, body)
def handleMethodFlags(statements, filename, lineno, key, m):
statements.append(MethodFlagsNode(filename, lineno, key, m))
def handleExportFuncs(statements, filename, lineno, m, classname):
statements.append(ExportFuncsNode(filename, lineno, m.group(1), classname))
def handleExportFuncs(statements, filename, lineno, m, classes):
statements.append(ExportFuncsNode(filename, lineno, m.group(1), classes))
def handleAddTask(statements, filename, lineno, m):
func = m.group("func")

View File

@@ -51,6 +51,7 @@ __infunc__ = ""
__inpython__ = False
__body__ = []
__classname__ = ""
classes = [ None, ]
cached_statements = {}
@@ -74,17 +75,10 @@ def inherit(files, fn, lineno, d):
if not os.path.isabs(file) and not file.endswith(".bbclass"):
file = os.path.join('classes', '%s.bbclass' % file)
if not os.path.isabs(file):
dname = os.path.dirname(fn)
bbpath = "%s:%s" % (dname, d.getVar("BBPATH", True))
abs_fn = bb.utils.which(bbpath, file)
if abs_fn:
file = abs_fn
if not file in __inherit_cache:
logger.log(logging.DEBUG -1, "BB %s:%d: inheriting %s", fn, lineno, file)
__inherit_cache.append( file )
d.setVar('__inherit_cache', __inherit_cache)
data.setVar('__inherit_cache', __inherit_cache, d)
include(fn, file, lineno, d, "inherit")
__inherit_cache = d.getVar('__inherit_cache') or []
@@ -104,7 +98,6 @@ def get_statements(filename, absolute_filename, base_name):
if not s: break
s = s.rstrip()
feeder(lineno, s, filename, base_name, statements)
file.close()
if __inpython__:
# add a blank line to close out any python definition
feeder(IN_PYTHON_EOF, "", filename, base_name, statements)
@@ -114,7 +107,7 @@ def get_statements(filename, absolute_filename, base_name):
return statements
def handle(fn, d, include):
global __func_start_regexp__, __inherit_regexp__, __export_func_regexp__, __addtask_regexp__, __addhandler_regexp__, __infunc__, __body__, __residue__, __classname__
global __func_start_regexp__, __inherit_regexp__, __export_func_regexp__, __addtask_regexp__, __addhandler_regexp__, __infunc__, __body__, __residue__
__body__ = []
__infunc__ = ""
__classname__ = ""
@@ -132,10 +125,11 @@ def handle(fn, d, include):
if ext == ".bbclass":
__classname__ = root
classes.append(__classname__)
__inherit_cache = d.getVar('__inherit_cache') or []
if not fn in __inherit_cache:
__inherit_cache.append(fn)
d.setVar('__inherit_cache', __inherit_cache)
data.setVar('__inherit_cache', __inherit_cache, d)
if include != 0:
oldfile = d.getVar('FILE')
@@ -152,25 +146,27 @@ def handle(fn, d, include):
# DONE WITH PARSING... time to evaluate
if ext != ".bbclass":
d.setVar('FILE', abs_fn)
data.setVar('FILE', abs_fn, d)
try:
statements.eval(d)
except bb.parse.SkipPackage:
bb.data.setVar("__SKIPPED", True, d)
statements.eval(d)
if ext == ".bbclass":
classes.remove(__classname__)
else:
if include == 0:
return { "" : d }
if ext != ".bbclass" and include == 0:
return ast.multi_finalize(fn, d)
return ast.multi_finalize(fn, d)
if oldfile:
d.setVar("FILE", oldfile)
# we have parsed the bb class now
if ext == ".bbclass" or ext == ".inc":
bb.methodpool.set_parsed_module(base_name)
return d
def feeder(lineno, s, fn, root, statements):
global __func_start_regexp__, __inherit_regexp__, __export_func_regexp__, __addtask_regexp__, __addhandler_regexp__, __def_regexp__, __python_func_regexp__, __inpython__, __infunc__, __body__, bb, __residue__, __classname__
global __func_start_regexp__, __inherit_regexp__, __export_func_regexp__, __addtask_regexp__, __addhandler_regexp__, __def_regexp__, __python_func_regexp__, __inpython__, __infunc__, __body__, classes, bb, __residue__
if __infunc__:
if s == '}':
__body__.append('')
@@ -197,10 +193,7 @@ def feeder(lineno, s, fn, root, statements):
if s and s[0] == '#':
if len(__residue__) != 0 and __residue__[0][0] != "#":
bb.fatal("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 len(__residue__) != 0 and __residue__[0][0] == "#" and (not s or s[0] != "#"):
bb.fatal("There is a confusing multiline, partially commented expression on line %s of file %s (%s).\nPlease clarify whether this is all a comment or should be parsed." % (lineno, fn, s))
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 and s[-1] == '\\':
__residue__.append(s[:-1])
@@ -232,7 +225,7 @@ def feeder(lineno, s, fn, root, statements):
m = __export_func_regexp__.match(s)
if m:
ast.handleExportFuncs(statements, fn, lineno, m, __classname__)
ast.handleExportFuncs(statements, fn, lineno, m, classes)
return
m = __addtask_regexp__.match(s)

View File

@@ -29,30 +29,7 @@ import logging
import bb.utils
from bb.parse import ParseError, resolve_file, ast, logger
__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)
$
""", re.X)
__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)$")
__include_regexp__ = re.compile( r"include\s+(.+)" )
__require_regexp__ = re.compile( r"require\s+(.+)" )
__export_regexp__ = re.compile( r"export\s+([a-zA-Z0-9\-_+.${}/]+)$" )
@@ -121,22 +98,15 @@ def handle(fn, data, include):
while True:
lineno = lineno + 1
s = f.readline()
if not s:
break
if not s: break
w = s.strip()
# skip empty lines
if not w:
continue
if not w: continue # skip empty lines
s = s.rstrip()
if s[0] == '#': continue # skip comments
while s[-1] == '\\':
s2 = f.readline().strip()
lineno = lineno + 1
if (not s2 or s2 and s2[0] != "#") and s[0] == "#" :
bb.fatal("There is a confusing multiline, partially commented expression on line %s of file %s (%s).\nPlease clarify whether this is all a comment or should be parsed." % (lineno, fn, s))
s = s[:-1] + s2
# skip comments
if s[0] == '#':
continue
feeder(lineno, s, fn, statements)
# DONE WITH PARSING... time to evaluate
@@ -145,8 +115,6 @@ def handle(fn, data, include):
if oldfile:
data.setVar('FILE', oldfile)
f.close()
for f in confFilters:
f(fn, data)

View File

@@ -125,11 +125,6 @@ class SQLTable(collections.MutableMapping):
return len(self) < len(other)
def get_by_pattern(self, pattern):
data = self._execute("SELECT * FROM %s WHERE key LIKE ?;" %
self.table, [pattern])
return [row[1] for row in data]
def values(self):
return list(self.itervalues())

View File

@@ -85,7 +85,7 @@ def _logged_communicate(pipe, log, input):
rlist = rin
try:
r,w,e = select.select (rlist, [], [])
except OSError as e:
except OSError, e:
if e.errno != errno.EINTR:
raise
@@ -102,10 +102,6 @@ def _logged_communicate(pipe, log, input):
log.write(data)
finally:
log.flush()
if pipe.stdout is not None:
pipe.stdout.close()
if pipe.stderr is not None:
pipe.stderr.close()
return ''.join(outdata), ''.join(errdata)
def run(cmd, input=None, log=None, **options):

View File

@@ -92,9 +92,9 @@ def sortPriorities(pn, dataCache, pkg_pn = None):
priorities[priority][preference] = []
priorities[priority][preference].append(f)
tmp_pn = []
for pri in sorted(priorities):
for pri in sorted(priorities, lambda a, b: a - b):
tmp_pref = []
for pref in sorted(priorities[pri]):
for pref in sorted(priorities[pri], lambda a, b: b - a):
tmp_pref.extend(priorities[pri][pref])
tmp_pn = [tmp_pref] + tmp_pn

View File

@@ -292,7 +292,7 @@ class WordLexer:
elif sep=='${':
parsefunc = self._parse_parameter
else:
raise NotImplementedError(sep)
raise NotImplementedError()
pos, closed = parsefunc(buf, result, eof)
return pos, closed

View File

@@ -472,7 +472,7 @@ class RunQueueData:
if depdata is not None:
taskid = taskData.gettask_id_fromfnid(depdata, idependtask)
if taskid is None:
bb.msg.fatal("RunQueue", "Task %s in %s depends upon non-existent task %s in %s" % (taskData.tasks_name[task], fn, idependtask, taskData.fn_index[depdata]))
bb.msg.fatal("RunQueue", "Task %s in %s depends upon non-existent task %s in %s" % (taskData.tasks_name[task], fn, idependtask, dep))
depends.add(taskid)
irdepends = taskData.tasks_irdepends[task]
for (depid, idependtask) in irdepends:
@@ -482,7 +482,7 @@ class RunQueueData:
if depdata is not None:
taskid = taskData.gettask_id_fromfnid(depdata, idependtask)
if taskid is None:
bb.msg.fatal("RunQueue", "Task %s in %s rdepends upon non-existent task %s in %s" % (taskData.tasks_name[task], fn, idependtask, taskData.fn_index[depdata]))
bb.msg.fatal("RunQueue", "Task %s in %s rdepends upon non-existent task %s in %s" % (taskData.tasks_name[task], fn, idependtask, dep))
depends.add(taskid)
# Resolve recursive 'recrdeptask' dependencies (Part A)
@@ -785,7 +785,6 @@ class RunQueue:
self.stamppolicy = cfgData.getVar("BB_STAMP_POLICY", True) or "perfile"
self.hashvalidate = cfgData.getVar("BB_HASHCHECK_FUNCTION", True) or None
self.setsceneverify = cfgData.getVar("BB_SETSCENE_VERIFY_FUNCTION", True) or None
self.depvalidate = cfgData.getVar("BB_SETSCENE_DEPVALID", True) or None
self.state = runQueuePrepare
@@ -957,7 +956,7 @@ class RunQueue:
for task in range(len(self.rqdata.runq_fnid)):
if self.rqdata.runq_fnid[task] not in done:
fn = self.rqdata.taskData.fn_index[self.rqdata.runq_fnid[task]]
the_data = bb.cache.Cache.loadDataFull(fn, self.cooker.collection.get_file_appends(fn), self.cooker.configuration.data)
the_data = bb.cache.Cache.loadDataFull(fn, self.cooker.get_file_appends(fn), self.cooker.configuration.data)
done.add(self.rqdata.runq_fnid[task])
bb.parse.siggen.dump_sigs(self.rqdata.dataCache)
@@ -1123,7 +1122,7 @@ class RunQueueExecute:
bb.parse.siggen.set_taskdata(self.rqdata.hashes, self.rqdata.hash_deps)
ret = 0
try:
the_data = bb.cache.Cache.loadDataFull(fn, self.cooker.collection.get_file_appends(fn), self.cooker.configuration.data)
the_data = bb.cache.Cache.loadDataFull(fn, self.cooker.get_file_appends(fn), self.cooker.configuration.data)
the_data.setVar('BB_TASKHASH', self.rqdata.runq_hash[task])
for h in self.rqdata.hashes:
the_data.setVar("BBHASH_%s" % h, self.rqdata.hashes[h])
@@ -1139,7 +1138,6 @@ class RunQueueExecute:
for e in fakeenv:
os.environ[e] = fakeenv[e]
the_data.setVar(e, fakeenv[e])
the_data.setVarFlag(e, 'export', "1")
if quieterrors:
the_data.setVarFlag(taskname, "quieterrors", "1")
@@ -1150,8 +1148,7 @@ class RunQueueExecute:
os._exit(1)
try:
if not self.cooker.configuration.dry_run:
profile = self.cooker.configuration.profile
ret = bb.build.exec_task(fn, taskname, the_data, profile)
ret = bb.build.exec_task(fn, taskname, the_data)
os._exit(ret)
except:
os._exit(1)
@@ -1164,26 +1161,6 @@ class RunQueueExecute:
return pid, pipein, pipeout
def check_dependencies(self, task, taskdeps, setscene = False):
if not self.rq.depvalidate:
return False
taskdata = {}
taskdeps.add(task)
for dep in taskdeps:
if setscene:
depid = self.rqdata.runq_setscene[dep]
else:
depid = dep
fn = self.rqdata.taskData.fn_index[self.rqdata.runq_fnid[depid]]
pn = self.rqdata.dataCache.pkg_fn[fn]
taskname = self.rqdata.runq_task[depid]
taskdata[dep] = [pn, taskname, fn]
call = self.rq.depvalidate + "(task, taskdata, notneeded, d)"
locs = { "task" : task, "taskdata" : taskdata, "notneeded" : self.scenequeue_notneeded, "d" : self.cooker.configuration.data }
valid = bb.utils.better_eval(call, locs)
return valid
class RunQueueExecuteDummy(RunQueueExecute):
def __init__(self, rq):
self.rq = rq
@@ -1221,8 +1198,16 @@ class RunQueueExecuteTasks(RunQueueExecute):
logger.debug(1, 'Considering %s (%s): %s' % (task, self.rqdata.get_user_idstring(task), str(self.rqdata.runq_revdeps[task])))
if len(self.rqdata.runq_revdeps[task]) > 0 and self.rqdata.runq_revdeps[task].issubset(self.rq.scenequeue_covered) and task not in self.rq.scenequeue_notcovered:
found = True
self.rq.scenequeue_covered.add(task)
ok = True
for revdep in self.rqdata.runq_revdeps[task]:
if self.rqdata.runq_fnid[task] != self.rqdata.runq_fnid[revdep]:
logger.debug(1, 'Found "bad" dep %s (%s) for %s (%s)' % (revdep, self.rqdata.get_user_idstring(revdep), task, self.rqdata.get_user_idstring(task)))
ok = False
break
if ok:
found = True
self.rq.scenequeue_covered.add(task)
logger.debug(1, 'Skip list (pre setsceneverify) %s', sorted(self.rq.scenequeue_covered))
@@ -1423,7 +1408,6 @@ class RunQueueExecuteScenequeue(RunQueueExecute):
self.scenequeue_covered = set()
self.scenequeue_notcovered = set()
self.scenequeue_notneeded = set()
# If we don't have any setscene functions, skip this step
if len(self.rqdata.runq_setscene) == 0:
@@ -1433,6 +1417,7 @@ class RunQueueExecuteScenequeue(RunQueueExecute):
self.stats = RunQueueStats(len(self.rqdata.runq_setscene))
endpoints = {}
sq_revdeps = []
sq_revdeps_new = []
sq_revdeps_squash = []
@@ -1447,15 +1432,12 @@ class RunQueueExecuteScenequeue(RunQueueExecute):
self.runq_complete.append(0)
self.runq_buildable.append(0)
# First process the chains up to the first setscene task.
endpoints = {}
for task in xrange(len(self.rqdata.runq_fnid)):
sq_revdeps.append(copy.copy(self.rqdata.runq_revdeps[task]))
sq_revdeps_new.append(set())
if (len(self.rqdata.runq_revdeps[task]) == 0) and task not in self.rqdata.runq_setscene:
endpoints[task] = set()
# Secondly process the chains between setscene tasks.
for task in self.rqdata.runq_setscene:
for dep in self.rqdata.runq_depends[task]:
if dep not in endpoints:
@@ -1471,8 +1453,6 @@ class RunQueueExecuteScenequeue(RunQueueExecute):
if sq_revdeps_new[point]:
tasks |= sq_revdeps_new[point]
sq_revdeps_new[point] = set()
if point in self.rqdata.runq_setscene:
sq_revdeps_new[point] = tasks
for dep in self.rqdata.runq_depends[point]:
if point in sq_revdeps[dep]:
sq_revdeps[dep].remove(point)
@@ -1485,42 +1465,6 @@ class RunQueueExecuteScenequeue(RunQueueExecute):
process_endpoints(endpoints)
# Build a list of setscene tasks which as "unskippable"
# These are direct endpoints referenced by the build
endpoints2 = {}
sq_revdeps2 = []
sq_revdeps_new2 = []
def process_endpoints2(endpoints):
newendpoints = {}
for point, task in endpoints.items():
tasks = set([point])
if task:
tasks |= task
if sq_revdeps_new2[point]:
tasks |= sq_revdeps_new2[point]
sq_revdeps_new2[point] = set()
if point in self.rqdata.runq_setscene:
sq_revdeps_new2[point] = tasks
for dep in self.rqdata.runq_depends[point]:
if point in sq_revdeps2[dep]:
sq_revdeps2[dep].remove(point)
if tasks:
sq_revdeps_new2[dep] |= tasks
if (len(sq_revdeps2[dep]) == 0 or len(sq_revdeps_new2[dep]) != 0) and dep not in self.rqdata.runq_setscene:
newendpoints[dep] = tasks
if len(newendpoints) != 0:
process_endpoints2(newendpoints)
for task in xrange(len(self.rqdata.runq_fnid)):
sq_revdeps2.append(copy.copy(self.rqdata.runq_revdeps[task]))
sq_revdeps_new2.append(set())
if (len(self.rqdata.runq_revdeps[task]) == 0) and task not in self.rqdata.runq_setscene:
endpoints2[task] = set()
process_endpoints2(endpoints2)
self.unskippable = []
for task in self.rqdata.runq_setscene:
if sq_revdeps_new2[task]:
self.unskippable.append(self.rqdata.runq_setscene.index(task))
for task in xrange(len(self.rqdata.runq_fnid)):
if task in self.rqdata.runq_setscene:
deps = set()
@@ -1681,13 +1625,6 @@ class RunQueueExecuteScenequeue(RunQueueExecute):
# Find the next setscene to run
for nexttask in xrange(self.stats.total):
if self.runq_buildable[nexttask] == 1 and self.runq_running[nexttask] != 1:
if nexttask in self.unskippable:
logger.debug(2, "Setscene task %s is unskippable" % self.rqdata.get_user_idstring(self.rqdata.runq_setscene[nexttask]))
if nexttask not in self.unskippable and len(self.sq_revdeps[nexttask]) > 0 and self.sq_revdeps[nexttask].issubset(self.scenequeue_covered) and self.check_dependencies(nexttask, self.sq_revdeps[nexttask], True):
logger.debug(2, "Skipping setscene for task %s" % self.rqdata.get_user_idstring(self.rqdata.runq_setscene[nexttask]))
self.task_skip(nexttask)
self.scenequeue_notneeded.add(nexttask)
return True
task = nexttask
break
if task is not None:

View File

@@ -0,0 +1,203 @@
#
# BitBake 'dummy' Passthrough Server
#
# Copyright (C) 2006 - 2007 Michael 'Mickey' Lauer
# Copyright (C) 2006 - 2008 Richard Purdie
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
"""
This module implements a passthrough server for BitBake.
Use register_idle_function() to add a function which the server
calls from within idle_commands when no requests are pending. Make sure
that those functions are non-blocking or else you will introduce latency
in the server's main loop.
"""
import time
import bb
import signal
DEBUG = False
import inspect, select
class BitBakeServerCommands():
def __init__(self, server):
self.server = server
def runCommand(self, command):
"""
Run a cooker command on the server
"""
#print "Running Command %s" % command
return self.cooker.command.runCommand(command)
def terminateServer(self):
"""
Trigger the server to quit
"""
self.server.server_exit()
#print "Server (cooker) exitting"
return
def ping(self):
"""
Dummy method which can be used to check the server is still alive
"""
return True
eventQueue = []
class BBUIEventQueue:
class event:
def __init__(self, parent):
self.parent = parent
@staticmethod
def send(event):
bb.server.none.eventQueue.append(event)
@staticmethod
def quit():
return
def __init__(self, BBServer):
self.eventQueue = bb.server.none.eventQueue
self.BBServer = BBServer
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):
if len(self.eventQueue) == 0:
self.BBServer.idle_commands(0)
return self.__popEvent()
def waitEvent(self, delay):
event = self.__popEvent()
if event:
return event
self.BBServer.idle_commands(delay)
return self.__popEvent()
def queue_event(self, event):
self.eventQueue.append(event)
def system_quit( self ):
bb.event.unregister_UIHhandler(self.EventHandle)
# Dummy signal handler to ensure we break out of sleep upon SIGCHLD
def chldhandler(signum, stackframe):
pass
class BitBakeNoneServer():
# remove this when you're done with debugging
# allow_reuse_address = True
def __init__(self):
self._idlefuns = {}
self.commands = BitBakeServerCommands(self)
def addcooker(self, cooker):
self.cooker = cooker
self.commands.cooker = cooker
def register_idle_function(self, function, data):
"""Register a function to be called while the server is idle"""
assert hasattr(function, '__call__')
self._idlefuns[function] = data
def idle_commands(self, delay):
#print "Idle queue length %s" % len(self._idlefuns)
#print "Idle timeout, running idle functions"
#if len(self._idlefuns) == 0:
nextsleep = delay
for function, data in self._idlefuns.items():
try:
retval = function(self, data, False)
#print "Idle function returned %s" % (retval)
if retval is False:
del self._idlefuns[function]
elif retval is True:
nextsleep = None
elif nextsleep is None:
continue
elif retval < nextsleep:
nextsleep = retval
except SystemExit:
raise
except:
import traceback
traceback.print_exc()
self.commands.runCommand(["stateShutdown"])
pass
if nextsleep is not None:
#print "Sleeping for %s (%s)" % (nextsleep, delay)
signal.signal(signal.SIGCHLD, chldhandler)
time.sleep(nextsleep)
signal.signal(signal.SIGCHLD, signal.SIG_DFL)
def server_exit(self):
# Tell idle functions we're exiting
for function, data in self._idlefuns.items():
try:
retval = function(self, data, True)
except:
pass
class BitBakeServerConnection():
def __init__(self, server):
self.server = server.server
self.connection = self.server.commands
self.events = bb.server.none.BBUIEventQueue(self.server)
for event in bb.event.ui_queue:
self.events.queue_event(event)
def terminate(self):
try:
self.events.system_quit()
except:
pass
try:
self.connection.terminateServer()
except:
pass
class BitBakeServer(object):
def initServer(self):
self.server = BitBakeNoneServer()
def addcooker(self, cooker):
self.cooker = cooker
self.server.addcooker(cooker)
def getServerIdleCB(self):
return self.server.register_idle_function
def saveConnectionDetails(self):
return
def detach(self, cooker_logfile):
self.logfile = cooker_logfile
def establishConnection(self):
self.connection = BitBakeServerConnection(self)
return self.connection
def launchUI(self, uifunc, *args):
return bb.cooker.server_main(self.cooker, uifunc, *args)

View File

@@ -45,10 +45,10 @@ class ServerCommunicator():
while True:
# don't let the user ctrl-c while we're waiting for a response
try:
if self.connection.poll(20):
if self.connection.poll(.5):
return self.connection.recv()
else:
bb.fatal("Timeout while attempting to communicate with bitbake server")
return None
except KeyboardInterrupt:
pass
@@ -256,7 +256,7 @@ class BitBakeServer(object):
def saveConnectionDetails(self):
return
def detach(self):
def detach(self, cooker_logfile):
self.server.start()
return
@@ -264,3 +264,7 @@ class BitBakeServer(object):
self.connection = BitBakeServerConnection(self)
signal.signal(signal.SIGTERM, lambda i, s: self.connection.terminate(force=True))
return self.connection
def launchUI(self, uifunc, *args):
return bb.cooker.server_main(self.cooker, uifunc, *args)

View File

@@ -35,14 +35,6 @@ import bb
import xmlrpclib, sys
from bb import daemonize
from bb.ui import uievent
import hashlib, time
import socket
import os, signal
import threading
try:
import cPickle as pickle
except ImportError:
import pickle
DEBUG = False
@@ -62,104 +54,82 @@ if sys.hexversion < 0x020600F0:
# 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
#
# To implement a simple form of client control, we use a special transport
# that adds a HTTP header field ("Bitbake-token") to ensure that a server
# can communicate with only a client at a given time (the client must use
# the same token).
##
if (2, 7, 0) <= sys.version_info < (2, 7, 2):
class BBTransport(xmlrpclib.Transport):
def __init__(self):
self.connection_token = None
xmlrpclib.Transport.__init__(self)
def request(self, host, handler, request_body, verbose=0):
h = self.make_connection(host)
if verbose:
h.set_debuglevel(1)
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)
if self.connection_token:
h.putheader("Bitbake-token", self.connection_token)
self.send_content(h, request_body)
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()
errcode, errmsg, headers = h.getreply()
if errcode != 200:
raise ProtocolError(
host + handler,
errcode, errmsg,
headers
)
if errcode != 200:
raise ProtocolError(
host + handler,
errcode, errmsg,
headers
)
self.verbose = verbose
self.verbose = verbose
try:
sock = h._conn.sock
except AttributeError:
sock = None
try:
sock = h._conn.sock
except AttributeError:
sock = None
return self._parse_response(h.getfile(), sock)
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 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()
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)
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()
file.close()
p.close()
return u.close()
def set_connection_token(self, token):
self.connection_token = token
else:
class BBTransport(xmlrpclib.Transport):
def __init__(self):
self.connection_token = None
xmlrpclib.Transport.__init__(self)
def set_connection_token(self, token):
self.connection_token = token
def send_content(self, h, body):
if self.connection_token:
h.putheader("Bitbake-token", self.connection_token)
xmlrpclib.Transport.send_content(self, h, body)
return u.close()
def _create_server(host, port):
t = BBTransport()
s = xmlrpclib.Server("http://%s:%d/" % (host, port), transport=t, allow_none=True)
return s, t
# 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():
def __init__(self, server):
self.server = server
self.has_client = False
def registerEventHandler(self, host, port):
"""
Register a remote UI Event Handler
"""
s, t = _create_server(host, port)
s = _create_server(host, port)
return bb.event.register_UIHhandler(s)
@@ -183,145 +153,11 @@ class BitBakeServerCommands():
print("Server (cooker) exiting")
return
def addClient(self):
if self.has_client:
return None
token = hashlib.md5(str(time.time())).hexdigest()
self.server.set_connection_token(token)
self.has_client = True
return token
def removeClient(self):
if self.has_client:
self.server.set_connection_token(None)
self.has_client = False
# This request handler checks if the request has a "Bitbake-token" header
# field (this comes from the client side) and compares it with its internal
# "Bitbake-token" field (this comes from the server). If the two are not
# equal, it is assumed that a client is trying to connect to the server
# while another client is connected to the server. In this case, a 503 error
# ("service unavailable") is returned to the client.
class BitBakeXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
def __init__(self, request, client_address, server):
self.connection_token = server.connection_token
SimpleXMLRPCRequestHandler.__init__(self, request, client_address, server)
def do_POST(self):
try:
remote_token = self.headers["Bitbake-token"]
except:
remote_token = None
if remote_token != self.connection_token:
self.report_503()
else:
SimpleXMLRPCRequestHandler.do_POST(self)
def report_503(self):
self.send_response(503)
response = 'No more client allowed'
self.send_header("Content-type", "text/plain")
self.send_header("Content-length", str(len(response)))
self.end_headers()
self.wfile.write(response)
class BitBakeUIEventServer(threading.Thread):
class EventAdapter():
def ping(self):
"""
Adapter to wrap our event queue since the caller (bb.event) expects to
call a send() method, but our actual queue only has put()
Dummy method which can be used to check the server is still alive
"""
def __init__(self, notify):
self.queue = []
self.notify = notify
self.qlock = threading.Lock()
def send(self, event):
self.qlock.acquire()
self.queue.append(event)
self.qlock.release()
self.notify.set()
def get(self):
self.qlock.acquire()
if len(self.queue) == 0:
self.qlock.release()
return None
e = self.queue.pop(0)
if len(self.queue) == 0:
self.notify.clear()
self.qlock.release()
return e
def __init__(self, connection):
self.connection = connection
self.notify = threading.Event()
self.event = BitBakeUIEventServer.EventAdapter(self.notify)
self.quit = False
threading.Thread.__init__(self)
def terminateServer(self):
self.quit = True
def run(self):
while not self.quit:
self.notify.wait(0.1)
evt = self.event.get()
if evt:
self.connection.event.sendpickle(pickle.dumps(evt))
class BitBakeXMLRPCEventServerController(SimpleXMLRPCServer):
def __init__(self, interface):
SimpleXMLRPCServer.__init__(self, interface, logRequests=False, allow_none=True)
self.register_function(self.registerEventHandler, "registerEventHandler")
self.register_function(self.unregisterEventHandler, "unregisterEventHandler")
self.register_function(self.terminateServer, "terminateServer")
#self.register_function(self.runCommand, "runCommand")
self.quit = False
self.clients = {}
self.client_ui_ids = {}
def registerEventHandler(self, host, port):
"""
Register a remote UI Event Handler
"""
print "registering handler %s:%s" % (host,port)
connection = xmlrpclib.ServerProxy("http://%s:%d/" % (host, port), allow_none=True)
client_hash = "%s:%d" % (host, port)
if self.clients.has_key(client_hash):
return None
client_ui_server = BitBakeUIEventServer(connection)
self.client_ui_ids[client_hash] = bb.event.register_UIHhandler(client_ui_server)
client_ui_server.start()
self.clients[client_hash] = client_ui_server
return client_hash
def unregisterEventHandler(self, client_hash):
"""
Unregister a remote UI Event Handler
"""
print "unregistering handler %s:%s" % (host,port)
client_thread = self.clients[client_hash]
if client_thread:
bb.event.unregister_UIHhandler(self.clients_ui_ids[client_hash])
client_thread.terminateServer()
client_thread.join()
return True
else:
return False
def terminateServer(self):
self.quit = True
def runCommand(self, cmd):
return None
def serve_forever(self, main_server):
self.main_server = main_server
while not self.quit:
self.handle_request()
self.server_close()
return True
class BitBakeXMLRPCServer(SimpleXMLRPCServer):
# remove this when you're done with debugging
@@ -332,15 +168,13 @@ class BitBakeXMLRPCServer(SimpleXMLRPCServer):
Constructor
"""
SimpleXMLRPCServer.__init__(self, interface,
requestHandler=BitBakeXMLRPCRequestHandler,
requestHandler=SimpleXMLRPCRequestHandler,
logRequests=False, allow_none=True)
self._idlefuns = {}
self.host, self.port = self.socket.getsockname()
self.connection_token = None
#self.register_introspection_functions()
self.commands = BitBakeServerCommands(self)
self.autoregister_all_functions(self.commands, "")
self.interface = interface
def addcooker(self, cooker):
self.cooker = cooker
@@ -362,16 +196,8 @@ class BitBakeXMLRPCServer(SimpleXMLRPCServer):
self._idlefuns[function] = data
def serve_forever(self):
# Create and run the event server controller in a separate thread
evt_server_ctrl = BitBakeXMLRPCEventServerController((self.host, self.port + 2))
self.event_controller_thread = threading.Thread(target = evt_server_ctrl.serve_forever, args = (self,))
self.event_controller_thread.start()
# Start the actual XMLRPC server
bb.cooker.server_main(self.cooker, self._serve_forever)
def removeClient(self):
self.commands.removeClient()
def _serve_forever(self):
"""
Serve Requests. Overloaded to honor a quit command
@@ -411,15 +237,10 @@ class BitBakeXMLRPCServer(SimpleXMLRPCServer):
retval = function(self, data, True)
except:
pass
# Terminate the event server
self.event_controller_thread.terminateServer()
self.event_controller_thread.join()
self.server_close()
return
def set_connection_token(self, token):
self.connection_token = token
class BitbakeServerInfo():
def __init__(self, host, port):
self.host = host
@@ -427,22 +248,10 @@ class BitbakeServerInfo():
class BitBakeServerConnection():
def __init__(self, serverinfo, clientinfo=("localhost", 0)):
self.connection, self.transport = _create_server(serverinfo.host, serverinfo.port)
self.clientinfo = clientinfo
self.serverinfo = serverinfo
def connect(self):
token = self.connection.addClient()
if token is None:
return None
self.transport.set_connection_token(token)
self.events = uievent.BBUIEventQueue(self.connection, self.clientinfo)
self.connection = _create_server(serverinfo.host, serverinfo.port)
self.events = uievent.BBUIEventQueue(self.connection, clientinfo)
for event in bb.event.ui_queue:
self.events.queue_event(event)
return self
def removeClient(self):
self.connection.removeClient()
def terminate(self):
# Don't wait for server indefinitely
@@ -468,51 +277,19 @@ class BitBakeServer(object):
def getServerIdleCB(self):
return self.server.register_idle_function
def saveConnectionDetails(self):
def saveConnectionDetails(self):
self.serverinfo = BitbakeServerInfo(self.server.host, self.server.port)
def detach(self):
daemonize.createDaemon(self.server.serve_forever, "bitbake-cookerdaemon.log")
def detach(self, cooker_logfile):
daemonize.createDaemon(self.server.serve_forever, cooker_logfile)
del self.cooker
del self.server
def establishConnection(self):
self.connection = BitBakeServerConnection(self.serverinfo)
return self.connection.connect()
return self.connection
def set_connection_token(self, token):
self.connection.transport.set_connection_token(token)
def launchUI(self, uifunc, *args):
return uifunc(*args)
def endSession(self):
self.connection.terminate()
class BitBakeXMLRPCClient(object):
def __init__(self):
pass
def saveConnectionDetails(self, remote):
self.remote = remote
def establishConnection(self):
# The format of "remote" must be "server:port"
try:
[host, port] = self.remote.split(":")
port = int(port)
except:
return None
# We need our IP for the server connection. We get the IP
# by trying to connect with the server
try:
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect((host, port))
ip = s.getsockname()[0]
s.close()
except:
return None
self.serverinfo = BitbakeServerInfo(host, port)
self.connection = BitBakeServerConnection(self.serverinfo, (ip, 0))
return self.connection.connect()
def endSession(self):
self.connection.removeClient()

View File

@@ -24,7 +24,7 @@ def init(d):
break
else:
logger.error("Invalid signature generator '%s', using default 'noop'\n"
"Available generators: %s", desired,
"Available generators: %s",
', '.join(obj.name for obj in siggens))
return SignatureGenerator(d)
@@ -49,7 +49,7 @@ class SignatureGenerator(object):
return ("%s.%s.%s" % (stampbase, taskname, extrainfo)).rstrip('.')
def stampcleanmask(self, stampbase, file_name, taskname, extrainfo):
return ("%s.%s.%s" % (stampbase, taskname, extrainfo)).rstrip('.')
return ("%s.%s*.%s" % (stampbase, taskname, extrainfo)).rstrip('.')
def dump_sigtask(self, fn, task, stampbase, runtime):
return
@@ -98,7 +98,6 @@ class SignatureGeneratorBasic(SignatureGenerator):
bb.error("Task %s from %s seems to be empty?!" % (task, fn))
data = ''
gendeps[task] -= self.basewhitelist
newdeps = gendeps[task]
seen = set()
while newdeps:
@@ -108,12 +107,12 @@ class SignatureGeneratorBasic(SignatureGenerator):
for dep in nextdeps:
if dep in self.basewhitelist:
continue
gendeps[dep] -= self.basewhitelist
newdeps |= gendeps[dep]
newdeps -= seen
alldeps = sorted(seen)
for dep in alldeps:
alldeps = seen - self.basewhitelist
for dep in sorted(alldeps):
data = data + dep
if dep in lookupcache:
var = lookupcache[dep]
@@ -127,7 +126,7 @@ class SignatureGeneratorBasic(SignatureGenerator):
if var:
data = data + str(var)
self.basehash[fn + "." + task] = hashlib.md5(data).hexdigest()
taskdeps[task] = alldeps
taskdeps[task] = sorted(alldeps)
self.taskdeps[fn] = taskdeps
self.gendeps[fn] = gendeps
@@ -249,7 +248,7 @@ class SignatureGeneratorBasic(SignatureGenerator):
os.fsync(fd)
os.chmod(tmpfile, 0664)
os.rename(tmpfile, sigfile)
except (OSError, IOError) as err:
except (OSError, IOError), err:
try:
os.unlink(tmpfile)
except OSError:
@@ -277,6 +276,7 @@ class SignatureGeneratorBasicHash(SignatureGeneratorBasic):
k = fn + "." + taskname
if clean:
h = "*"
taskname = taskname + "*"
elif k in self.taskhash:
h = self.taskhash[k]
else:
@@ -331,12 +331,12 @@ def compare_sigfiles(a, b, recursecb = None):
return changed, added, removed
if 'basewhitelist' in a_data and a_data['basewhitelist'] != b_data['basewhitelist']:
output.append("basewhitelist changed from '%s' to '%s'" % (a_data['basewhitelist'], b_data['basewhitelist']))
output.append("basewhitelist changed from %s to %s" % (a_data['basewhitelist'], b_data['basewhitelist']))
if a_data['basewhitelist'] and b_data['basewhitelist']:
output.append("changed items: %s" % a_data['basewhitelist'].symmetric_difference(b_data['basewhitelist']))
if 'taskwhitelist' in a_data and a_data['taskwhitelist'] != b_data['taskwhitelist']:
output.append("taskwhitelist changed from '%s' to '%s'" % (a_data['taskwhitelist'], b_data['taskwhitelist']))
output.append("taskwhitelist changed from %s to %s" % (a_data['taskwhitelist'], b_data['taskwhitelist']))
if a_data['taskwhitelist'] and b_data['taskwhitelist']:
output.append("changed items: %s" % a_data['taskwhitelist'].symmetric_difference(b_data['taskwhitelist']))
@@ -349,7 +349,7 @@ def compare_sigfiles(a, b, recursecb = None):
changed, added, removed = dict_diff(a_data['gendeps'], b_data['gendeps'], a_data['basewhitelist'] & b_data['basewhitelist'])
if changed:
for dep in changed:
output.append("List of dependencies for variable %s changed from '%s' to '%s'" % (dep, a_data['gendeps'][dep], b_data['gendeps'][dep]))
output.append("List of dependencies for variable %s changed from %s to %s" % (dep, a_data['gendeps'][dep], b_data['gendeps'][dep]))
if a_data['gendeps'][dep] and b_data['gendeps'][dep]:
output.append("changed items: %s" % a_data['gendeps'][dep].symmetric_difference(b_data['gendeps'][dep]))
if added:
@@ -363,7 +363,7 @@ def compare_sigfiles(a, b, recursecb = None):
changed, added, removed = dict_diff(a_data['varvals'], b_data['varvals'])
if changed:
for dep in changed:
output.append("Variable %s value changed from '%s' to '%s'" % (dep, a_data['varvals'][dep], b_data['varvals'][dep]))
output.append("Variable %s value changed from %s to %s" % (dep, a_data['varvals'][dep], b_data['varvals'][dep]))
changed, added, removed = dict_diff(a_data['file_checksum_values'], b_data['file_checksum_values'])
if changed:

View File

@@ -1,5 +1,3 @@
# ex:ts=4:sw=4:sts=4:et
# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
#
# BitBake Test for codeparser.py
#
@@ -26,9 +24,6 @@ import bb
logger = logging.getLogger('BitBake.TestCodeParser')
# bb.data references bb.parse but can't directly import due to circular dependencies.
# Hack around it for now :(
import bb.parse
import bb.data
class ReferenceTest(unittest.TestCase):

View File

@@ -1,5 +1,3 @@
# ex:ts=4:sw=4:sts=4:et
# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
#
# BitBake Tests for Copy-on-Write (cow.py)
#

View File

@@ -1,5 +1,3 @@
# ex:ts=4:sw=4:sts=4:et
# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
#
# BitBake Tests for the Data Store (data.py/data_smart.py)
#

View File

@@ -1,5 +1,3 @@
# ex:ts=4:sw=4:sts=4:et
# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
#
# BitBake Tests for the Fetcher (fetch2/)
#
@@ -23,252 +21,11 @@ import unittest
import tempfile
import subprocess
import os
from bb.fetch2 import URI
import bb
class URITest(unittest.TestCase):
test_uris = {
"http://www.google.com/index.html" : {
'uri': 'http://www.google.com/index.html',
'scheme': 'http',
'hostname': 'www.google.com',
'port': None,
'hostport': 'www.google.com',
'path': '/index.html',
'userinfo': '',
'username': '',
'password': '',
'params': {},
'relative': False
},
"http://www.google.com/index.html;param1=value1" : {
'uri': 'http://www.google.com/index.html;param1=value1',
'scheme': 'http',
'hostname': 'www.google.com',
'port': None,
'hostport': 'www.google.com',
'path': '/index.html',
'userinfo': '',
'username': '',
'password': '',
'params': {
'param1': 'value1'
},
'relative': False
},
"http://www.example.com:8080/index.html" : {
'uri': 'http://www.example.com:8080/index.html',
'scheme': 'http',
'hostname': 'www.example.com',
'port': 8080,
'hostport': 'www.example.com:8080',
'path': '/index.html',
'userinfo': '',
'username': '',
'password': '',
'params': {},
'relative': False
},
"cvs://anoncvs@cvs.handhelds.org/cvs;module=familiar/dist/ipkg" : {
'uri': 'cvs://anoncvs@cvs.handhelds.org/cvs;module=familiar/dist/ipkg',
'scheme': 'cvs',
'hostname': 'cvs.handhelds.org',
'port': None,
'hostport': 'cvs.handhelds.org',
'path': '/cvs',
'userinfo': 'anoncvs',
'username': 'anoncvs',
'password': '',
'params': {
'module': 'familiar/dist/ipkg'
},
'relative': False
},
"cvs://anoncvs:anonymous@cvs.handhelds.org/cvs;tag=V0-99-81;module=familiar/dist/ipkg": {
'uri': 'cvs://anoncvs:anonymous@cvs.handhelds.org/cvs;tag=V0-99-81;module=familiar/dist/ipkg',
'scheme': 'cvs',
'hostname': 'cvs.handhelds.org',
'port': None,
'hostport': 'cvs.handhelds.org',
'path': '/cvs',
'userinfo': 'anoncvs:anonymous',
'username': 'anoncvs',
'password': 'anonymous',
'params': {
'tag': 'V0-99-81',
'module': 'familiar/dist/ipkg'
},
'relative': False
},
"file://example.diff": { # NOTE: Not RFC compliant!
'uri': 'file:example.diff',
'scheme': 'file',
'hostname': '',
'port': None,
'hostport': '',
'path': 'example.diff',
'userinfo': '',
'username': '',
'password': '',
'params': {},
'relative': True
},
"file:example.diff": { # NOTE: RFC compliant version of the former
'uri': 'file:example.diff',
'scheme': 'file',
'hostname': '',
'port': None,
'hostport': '',
'path': 'example.diff',
'userinfo': '',
'userinfo': '',
'username': '',
'password': '',
'params': {},
'relative': True
},
"file:///tmp/example.diff": {
'uri': 'file:///tmp/example.diff',
'scheme': 'file',
'hostname': '',
'port': None,
'hostport': '',
'path': '/tmp/example.diff',
'userinfo': '',
'userinfo': '',
'username': '',
'password': '',
'params': {},
'relative': False
},
"git:///path/example.git": {
'uri': 'git:///path/example.git',
'scheme': 'git',
'hostname': '',
'port': None,
'hostport': '',
'path': '/path/example.git',
'userinfo': '',
'userinfo': '',
'username': '',
'password': '',
'params': {},
'relative': False
},
"git:path/example.git": {
'uri': 'git:path/example.git',
'scheme': 'git',
'hostname': '',
'port': None,
'hostport': '',
'path': 'path/example.git',
'userinfo': '',
'userinfo': '',
'username': '',
'password': '',
'params': {},
'relative': True
},
"git://example.net/path/example.git": {
'uri': 'git://example.net/path/example.git',
'scheme': 'git',
'hostname': 'example.net',
'port': None,
'hostport': 'example.net',
'path': '/path/example.git',
'userinfo': '',
'userinfo': '',
'username': '',
'password': '',
'params': {},
'relative': False
}
}
def test_uri(self):
for test_uri, ref in self.test_uris.items():
uri = URI(test_uri)
self.assertEqual(str(uri), ref['uri'])
# expected attributes
self.assertEqual(uri.scheme, ref['scheme'])
self.assertEqual(uri.userinfo, ref['userinfo'])
self.assertEqual(uri.username, ref['username'])
self.assertEqual(uri.password, ref['password'])
self.assertEqual(uri.hostname, ref['hostname'])
self.assertEqual(uri.port, ref['port'])
self.assertEqual(uri.hostport, ref['hostport'])
self.assertEqual(uri.path, ref['path'])
self.assertEqual(uri.params, ref['params'])
self.assertEqual(uri.relative, ref['relative'])
def test_dict(self):
for test in self.test_uris.values():
uri = URI()
self.assertEqual(uri.scheme, '')
self.assertEqual(uri.userinfo, '')
self.assertEqual(uri.username, '')
self.assertEqual(uri.password, '')
self.assertEqual(uri.hostname, '')
self.assertEqual(uri.port, None)
self.assertEqual(uri.path, '')
self.assertEqual(uri.params, {})
uri.scheme = test['scheme']
self.assertEqual(uri.scheme, test['scheme'])
uri.userinfo = test['userinfo']
self.assertEqual(uri.userinfo, test['userinfo'])
self.assertEqual(uri.username, test['username'])
self.assertEqual(uri.password, test['password'])
uri.hostname = test['hostname']
self.assertEqual(uri.hostname, test['hostname'])
self.assertEqual(uri.hostport, test['hostname'])
uri.port = test['port']
self.assertEqual(uri.port, test['port'])
self.assertEqual(uri.hostport, test['hostport'])
uri.path = test['path']
self.assertEqual(uri.path, test['path'])
uri.params = test['params']
self.assertEqual(uri.params, test['params'])
self.assertEqual(str(uri)+str(uri.relative), str(test['uri'])+str(test['relative']))
self.assertEqual(str(uri), test['uri'])
uri.params = {}
self.assertEqual(uri.params, {})
self.assertEqual(str(uri), (str(uri).split(";"))[0])
class FetcherTest(unittest.TestCase):
def setUp(self):
self.d = bb.data.init()
self.tempdir = tempfile.mkdtemp()
self.dldir = os.path.join(self.tempdir, "download")
os.mkdir(self.dldir)
self.d.setVar("DL_DIR", self.dldir)
self.unpackdir = os.path.join(self.tempdir, "unpacked")
os.mkdir(self.unpackdir)
persistdir = os.path.join(self.tempdir, "persistdata")
self.d.setVar("PERSISTENT_DIR", persistdir)
def tearDown(self):
bb.utils.prunedir(self.tempdir)
class MirrorUriTest(FetcherTest):
replaceuris = {
("git://git.invalid.infradead.org/mtd-utils.git;tag=1234567890123456789012345678901234567890", "git://.*/.*", "http://somewhere.org/somedir/")
: "http://somewhere.org/somedir/git2_git.invalid.infradead.org.mtd-utils.git.tar.gz",
@@ -309,6 +66,87 @@ class MirrorUriTest(FetcherTest):
"https://.*/.* file:///someotherpath/downloads/ \n" \
"http://.*/.* file:///someotherpath/downloads/ \n"
def setUp(self):
self.d = bb.data.init()
self.tempdir = tempfile.mkdtemp()
self.dldir = os.path.join(self.tempdir, "download")
os.mkdir(self.dldir)
self.d.setVar("DL_DIR", self.dldir)
self.unpackdir = os.path.join(self.tempdir, "unpacked")
os.mkdir(self.unpackdir)
persistdir = os.path.join(self.tempdir, "persistdata")
self.d.setVar("PERSISTENT_DIR", persistdir)
def tearDown(self):
bb.utils.prunedir(self.tempdir)
def test_fetch(self):
fetcher = bb.fetch.Fetch(["http://downloads.yoctoproject.org/releases/bitbake/bitbake-1.0.tar.gz", "http://downloads.yoctoproject.org/releases/bitbake/bitbake-1.1.tar.gz"], self.d)
fetcher.download()
self.assertEqual(os.path.getsize(self.dldir + "/bitbake-1.0.tar.gz"), 57749)
self.assertEqual(os.path.getsize(self.dldir + "/bitbake-1.1.tar.gz"), 57892)
self.d.setVar("BB_NO_NETWORK", "1")
fetcher = bb.fetch.Fetch(["http://downloads.yoctoproject.org/releases/bitbake/bitbake-1.0.tar.gz", "http://downloads.yoctoproject.org/releases/bitbake/bitbake-1.1.tar.gz"], self.d)
fetcher.download()
fetcher.unpack(self.unpackdir)
self.assertEqual(len(os.listdir(self.unpackdir + "/bitbake-1.0/")), 9)
self.assertEqual(len(os.listdir(self.unpackdir + "/bitbake-1.1/")), 9)
def test_fetch_mirror(self):
self.d.setVar("MIRRORS", "http://.*/.* http://downloads.yoctoproject.org/releases/bitbake")
fetcher = bb.fetch.Fetch(["http://invalid.yoctoproject.org/releases/bitbake/bitbake-1.0.tar.gz"], self.d)
fetcher.download()
self.assertEqual(os.path.getsize(self.dldir + "/bitbake-1.0.tar.gz"), 57749)
def test_fetch_premirror(self):
self.d.setVar("PREMIRRORS", "http://.*/.* http://downloads.yoctoproject.org/releases/bitbake")
fetcher = bb.fetch.Fetch(["http://invalid.yoctoproject.org/releases/bitbake/bitbake-1.0.tar.gz"], self.d)
fetcher.download()
self.assertEqual(os.path.getsize(self.dldir + "/bitbake-1.0.tar.gz"), 57749)
def gitfetcher(self, url1, url2):
def checkrevision(self, fetcher):
fetcher.unpack(self.unpackdir)
revision = subprocess.check_output("git rev-parse HEAD", shell=True, cwd=self.unpackdir + "/git").strip()
self.assertEqual(revision, "270a05b0b4ba0959fe0624d2a4885d7b70426da5")
self.d.setVar("BB_GENERATE_MIRROR_TARBALLS", "1")
self.d.setVar("SRCREV", "270a05b0b4ba0959fe0624d2a4885d7b70426da5")
fetcher = bb.fetch.Fetch([url1], self.d)
fetcher.download()
checkrevision(self, fetcher)
# Wipe out the dldir clone and the unpacked source, turn off the network and check mirror tarball works
bb.utils.prunedir(self.dldir + "/git2/")
bb.utils.prunedir(self.unpackdir)
self.d.setVar("BB_NO_NETWORK", "1")
fetcher = bb.fetch.Fetch([url2], self.d)
fetcher.download()
checkrevision(self, fetcher)
def test_gitfetch(self):
url1 = url2 = "git://git.openembedded.org/bitbake"
self.gitfetcher(url1, url2)
def test_gitfetch_premirror(self):
url1 = "git://git.openembedded.org/bitbake"
url2 = "git://someserver.org/bitbake"
self.d.setVar("PREMIRRORS", "git://someserver.org/bitbake git://git.openembedded.org/bitbake \n")
self.gitfetcher(url1, url2)
def test_gitfetch_premirror2(self):
url1 = url2 = "git://someserver.org/bitbake"
self.d.setVar("PREMIRRORS", "git://someserver.org/bitbake git://git.openembedded.org/bitbake \n")
self.gitfetcher(url1, url2)
def test_gitfetch_premirror3(self):
realurl = "git://git.openembedded.org/bitbake"
dummyurl = "git://someserver.org/bitbake"
self.sourcedir = self.unpackdir.replace("unpacked", "sourcemirror.git")
os.chdir(self.tempdir)
subprocess.check_output("git clone %s %s 2> /dev/null" % (realurl, self.sourcedir), shell=True)
self.d.setVar("PREMIRRORS", "%s git://%s;protocol=file \n" % (dummyurl, self.sourcedir))
self.gitfetcher(dummyurl, dummyurl)
def test_urireplace(self):
for k, v in self.replaceuris.items():
ud = bb.fetch.FetchData(k[0], self.d)
@@ -330,77 +168,6 @@ class MirrorUriTest(FetcherTest):
uris, uds = bb.fetch2.build_mirroruris(fetcher, mirrors, self.d)
self.assertEqual(uris, ['file:///someotherpath/downloads/bitbake-1.0.tar.gz'])
class FetcherNetworkTest(FetcherTest):
if os.environ.get("BB_SKIP_NETTESTS") == "yes":
print("Unset BB_SKIP_NETTESTS to run network tests")
else:
def test_fetch(self):
fetcher = bb.fetch.Fetch(["http://downloads.yoctoproject.org/releases/bitbake/bitbake-1.0.tar.gz", "http://downloads.yoctoproject.org/releases/bitbake/bitbake-1.1.tar.gz"], self.d)
fetcher.download()
self.assertEqual(os.path.getsize(self.dldir + "/bitbake-1.0.tar.gz"), 57749)
self.assertEqual(os.path.getsize(self.dldir + "/bitbake-1.1.tar.gz"), 57892)
self.d.setVar("BB_NO_NETWORK", "1")
fetcher = bb.fetch.Fetch(["http://downloads.yoctoproject.org/releases/bitbake/bitbake-1.0.tar.gz", "http://downloads.yoctoproject.org/releases/bitbake/bitbake-1.1.tar.gz"], self.d)
fetcher.download()
fetcher.unpack(self.unpackdir)
self.assertEqual(len(os.listdir(self.unpackdir + "/bitbake-1.0/")), 9)
self.assertEqual(len(os.listdir(self.unpackdir + "/bitbake-1.1/")), 9)
def test_fetch_mirror(self):
self.d.setVar("MIRRORS", "http://.*/.* http://downloads.yoctoproject.org/releases/bitbake")
fetcher = bb.fetch.Fetch(["http://invalid.yoctoproject.org/releases/bitbake/bitbake-1.0.tar.gz"], self.d)
fetcher.download()
self.assertEqual(os.path.getsize(self.dldir + "/bitbake-1.0.tar.gz"), 57749)
def test_fetch_premirror(self):
self.d.setVar("PREMIRRORS", "http://.*/.* http://downloads.yoctoproject.org/releases/bitbake")
fetcher = bb.fetch.Fetch(["http://invalid.yoctoproject.org/releases/bitbake/bitbake-1.0.tar.gz"], self.d)
fetcher.download()
self.assertEqual(os.path.getsize(self.dldir + "/bitbake-1.0.tar.gz"), 57749)
def gitfetcher(self, url1, url2):
def checkrevision(self, fetcher):
fetcher.unpack(self.unpackdir)
revision = bb.process.run("git rev-parse HEAD", shell=True, cwd=self.unpackdir + "/git")[0].strip()
self.assertEqual(revision, "270a05b0b4ba0959fe0624d2a4885d7b70426da5")
self.d.setVar("BB_GENERATE_MIRROR_TARBALLS", "1")
self.d.setVar("SRCREV", "270a05b0b4ba0959fe0624d2a4885d7b70426da5")
fetcher = bb.fetch.Fetch([url1], self.d)
fetcher.download()
checkrevision(self, fetcher)
# Wipe out the dldir clone and the unpacked source, turn off the network and check mirror tarball works
bb.utils.prunedir(self.dldir + "/git2/")
bb.utils.prunedir(self.unpackdir)
self.d.setVar("BB_NO_NETWORK", "1")
fetcher = bb.fetch.Fetch([url2], self.d)
fetcher.download()
checkrevision(self, fetcher)
def test_gitfetch(self):
url1 = url2 = "git://git.openembedded.org/bitbake"
self.gitfetcher(url1, url2)
def test_gitfetch_premirror(self):
url1 = "git://git.openembedded.org/bitbake"
url2 = "git://someserver.org/bitbake"
self.d.setVar("PREMIRRORS", "git://someserver.org/bitbake git://git.openembedded.org/bitbake \n")
self.gitfetcher(url1, url2)
def test_gitfetch_premirror2(self):
url1 = url2 = "git://someserver.org/bitbake"
self.d.setVar("PREMIRRORS", "git://someserver.org/bitbake git://git.openembedded.org/bitbake \n")
self.gitfetcher(url1, url2)
def test_gitfetch_premirror3(self):
realurl = "git://git.openembedded.org/bitbake"
dummyurl = "git://someserver.org/bitbake"
self.sourcedir = self.unpackdir.replace("unpacked", "sourcemirror.git")
os.chdir(self.tempdir)
bb.process.run("git clone %s %s 2> /dev/null" % (realurl, self.sourcedir), shell=True)
self.d.setVar("PREMIRRORS", "%s git://%s;protocol=file \n" % (dummyurl, self.sourcedir))
self.gitfetcher(dummyurl, dummyurl)
class URLHandle(unittest.TestCase):

View File

@@ -1,5 +1,3 @@
# ex:ts=4:sw=4:sts=4:et
# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
#
# BitBake Tests for utils.py
#

View File

@@ -25,30 +25,28 @@ import bb.cache
import bb.cooker
import bb.providers
import bb.utils
from bb.cooker import state, BBCooker
from bb.cookerdata import CookerConfiguration, ConfigParameters
from bb.cooker import state
import bb.fetch2
class Tinfoil:
def __init__(self, output=sys.stdout):
def __init__(self):
# Needed to avoid deprecation warnings with python 2.6
warnings.filterwarnings("ignore", category=DeprecationWarning)
# Set up logging
self.logger = logging.getLogger('BitBake')
console = logging.StreamHandler(output)
bb.msg.addDefaultlogFilter(console)
console = logging.StreamHandler(sys.stdout)
format = bb.msg.BBLogFormatter("%(levelname)s: %(message)s")
if output.isatty():
format.enable_color()
bb.msg.addDefaultlogFilter(console)
console.setFormatter(format)
self.logger.addHandler(console)
self.config = CookerConfiguration()
configparams = TinfoilConfigParameters(parse_only=True)
self.config.setConfigParameters(configparams)
self.config.setServerRegIdleCallback(self.register_idle_function)
self.cooker = BBCooker(self.config)
initialenv = os.environ.copy()
bb.utils.clean_environment()
self.config = TinfoilConfig(parse_only=True)
self.cooker = bb.cooker.BBCooker(self.config,
self.register_idle_function,
initialenv)
self.config_data = self.cooker.configuration.data
bb.providers.logger.setLevel(logging.ERROR)
self.cooker_data = None
@@ -71,26 +69,30 @@ class Tinfoil:
self.logger.setLevel(logging.INFO)
sys.stderr.write("done.\n")
self.cooker_data = self.cooker.recipecache
self.cooker_data = self.cooker.status
def prepare(self, config_only = False):
if not self.cooker_data:
if config_only:
self.cooker.parseConfiguration()
self.cooker_data = self.cooker.recipecache
self.cooker_data = self.cooker.status
else:
self.parseRecipes()
class TinfoilConfigParameters(ConfigParameters):
class TinfoilConfig(object):
def __init__(self, **options):
self.initial_options = options
super(TinfoilConfigParameters, self).__init__()
self.pkgs_to_build = []
self.debug_domains = []
self.extra_assume_provided = []
self.prefile = []
self.postfile = []
self.debug = 0
self.__dict__.update(options)
def parseCommandLine(self):
class DummyOptions:
def __init__(self, initial_options):
for key, val in initial_options.items():
setattr(self, key, val)
def __getattr__(self, attribute):
try:
return super(TinfoilConfig, self).__getattribute__(attribute)
except AttributeError:
return None
return DummyOptions(self.initial_options), None

View File

@@ -204,6 +204,8 @@ class BuildDetailsPage (HobPage):
def add_build_fail_top_bar(self, actions, log_file=None):
primary_action = "Edit %s" % actions
self.notebook.set_page("Issues")
color = HobColors.ERROR
build_fail_top = gtk.EventBox()
#build_fail_top.set_size_request(-1, 200)
@@ -224,16 +226,7 @@ class BuildDetailsPage (HobPage):
label = gtk.Label()
label.set_alignment(0.0, 0.5)
# Ensure variable disk_full is defined
if not hasattr(self.builder, 'disk_full'):
self.builder.disk_full = False
if self.builder.disk_full:
markup = "<span size='medium'>There is no disk space left, so Hob cannot finish building your image. Free up some disk space\n"
markup += "and restart the build. Check the \"Issues\" tab for more details</span>"
label.set_markup(markup)
else:
label.set_markup("<span size='medium'>Check the \"Issues\" information for more details</span>")
label.set_markup("<span size='medium'>Check the \"Issues\" information for more details</span>")
build_fail_tab.attach(label, 4, 40, 4, 9)
# create button 'Edit packages'
@@ -241,36 +234,22 @@ class BuildDetailsPage (HobPage):
#action_button.set_size_request(-1, 40)
action_button.set_tooltip_text("Edit the %s parameters" % actions)
action_button.connect('clicked', self.failure_primary_action_button_clicked_cb, primary_action)
build_fail_tab.attach(action_button, 4, 13, 9, 12)
if log_file:
open_log_button = HobAltButton("Open log")
open_log_button.set_relief(gtk.RELIEF_HALF)
open_log_button.set_tooltip_text("Open the build's log file")
open_log_button.connect('clicked', self.open_log_button_clicked_cb, log_file)
build_fail_tab.attach(open_log_button, 14, 23, 9, 12)
attach_pos = (24 if log_file else 14)
file_bug_button = HobAltButton('File a bug')
file_bug_button.set_relief(gtk.RELIEF_HALF)
file_bug_button.set_tooltip_text("Open the Yocto Project bug tracking website")
file_bug_button.connect('clicked', self.failure_activate_file_bug_link_cb)
build_fail_tab.attach(file_bug_button, attach_pos, attach_pos + 9, 9, 12)
if not self.builder.disk_full:
build_fail_tab.attach(action_button, 4, 13, 9, 12)
if log_file:
build_fail_tab.attach(open_log_button, 14, 23, 9, 12)
build_fail_tab.attach(file_bug_button, attach_pos, attach_pos + 9, 9, 12)
else:
restart_build = HobButton("Restart the build")
restart_build.set_tooltip_text("Restart the build")
restart_build.connect('clicked', self.restart_build_button_clicked_cb)
build_fail_tab.attach(restart_build, 4, 13, 9, 12)
build_fail_tab.attach(action_button, 14, 23, 9, 12)
if log_file:
build_fail_tab.attach(open_log_button, attach_pos, attach_pos + 9, 9, 12)
self.builder.disk_full = False
return build_fail_top
def show_fail_page(self, title):
@@ -285,7 +264,6 @@ class BuildDetailsPage (HobPage):
self.vbox.pack_start(self.notebook, expand=True, fill=True)
self.show_all()
self.notebook.set_page("Issues")
self.back_button.hide()
def add_build_stop_top_bar(self, action, log_file=None):
@@ -370,7 +348,6 @@ class BuildDetailsPage (HobPage):
self.box_group_area.pack_end(self.button_box, expand=False, fill=False)
self.show_all()
self.notebook.set_page("Log")
self.back_button.hide()
self.reset_build_status()
@@ -416,9 +393,6 @@ class BuildDetailsPage (HobPage):
elif "Edit image" in action:
self.builder.show_configuration()
def restart_build_button_clicked_cb(self, button):
self.builder.just_bake()
def stop_primary_action_button_clicked_cb(self, button, action):
if "recipes" in action:
self.builder.show_recipes()
@@ -429,8 +403,7 @@ class BuildDetailsPage (HobPage):
def open_log_button_clicked_cb(self, button, log_file):
if log_file:
log_file = "file:///" + log_file
gtk.show_uri(screen=button.get_screen(), uri=log_file, timestamp=0)
os.system("xdg-open /%s" % log_file)
def failure_activate_file_bug_link_cb(self, button):
button.child.emit('activate-link', "http://bugzilla.yoctoproject.org")

View File

@@ -38,16 +38,11 @@ from bb.ui.crumbs.builddetailspage import BuildDetailsPage
from bb.ui.crumbs.imagedetailspage import ImageDetailsPage
from bb.ui.crumbs.sanitycheckpage import SanityCheckPage
from bb.ui.crumbs.hobwidget import hwc, HobButton, HobAltButton
from bb.ui.crumbs.hig import CrumbsMessageDialog, ImageSelectionDialog, \
AdvancedSettingDialog, SimpleSettingsDialog, \
LayerSelectionDialog, DeployImageDialog
from bb.ui.crumbs.persistenttooltip import PersistentTooltip
import bb.ui.crumbs.utils
from bb.ui.crumbs.hig.crumbsmessagedialog import CrumbsMessageDialog
from bb.ui.crumbs.hig.simplesettingsdialog import SimpleSettingsDialog
from bb.ui.crumbs.hig.advancedsettingsdialog import AdvancedSettingsDialog
from bb.ui.crumbs.hig.deployimagedialog import DeployImageDialog
from bb.ui.crumbs.hig.layerselectiondialog import LayerSelectionDialog
from bb.ui.crumbs.hig.imageselectiondialog import ImageSelectionDialog
from bb.ui.crumbs.hig.parsingwarningsdialog import ParsingWarningsDialog
from bb.ui.crumbs.hig.propertydialog import PropertyDialog
hobVer = 20120808
@@ -56,10 +51,10 @@ class Configuration:
@classmethod
def parse_proxy_string(cls, proxy):
pattern = "^\s*((http|https|ftp|socks|cvs)://)?((\S+):(\S+)@)?([^\s:]+)(:(\d+))?/?"
pattern = "^\s*((http|https|ftp|git|cvs)://)?((\S+):(\S+)@)?(\S+):(\d+)/?"
match = re.search(pattern, proxy)
if match:
return match.group(2), match.group(4), match.group(5), match.group(6), match.group(8)
return match.group(2), match.group(4), match.group(5), match.group(6), match.group(7)
else:
return None, None, None, "", ""
@@ -87,14 +82,13 @@ class Configuration:
@classmethod
def make_proxy_string(cls, prot, user, passwd, host, port, default_prot=""):
if host == None or host == "":# or port == None or port == "":
if host == None or host == "" or port == None or port == "":
return ""
return Configuration.make_host_string(prot, user, passwd, host, default_prot) + (":" + Configuration.make_port_string(port) if port else "")
return Configuration.make_host_string(prot, user, passwd, host, default_prot) + ":" + Configuration.make_port_string(port)
def __init__(self):
self.curr_mach = ""
self.selected_image = None
# settings
self.curr_distro = ""
self.dldir = self.sstatedir = self.sstatemirror = ""
@@ -108,8 +102,6 @@ class Configuration:
self.extra_setting = {}
self.toolchain_build = False
self.image_fstypes = ""
self.image_size = None
self.image_packages = []
# bblayers.conf
self.layers = []
# image/recipes/packages
@@ -126,14 +118,14 @@ class Configuration:
"http" : [None, None, None, "", ""], # protocol : [prot, user, passwd, host, port]
"https" : [None, None, None, "", ""],
"ftp" : [None, None, None, "", ""],
"socks" : [None, None, None, "", ""],
"git" : [None, None, None, "", ""],
"cvs" : [None, None, None, "", ""],
}
def clear_selection(self):
self.selected_image = None
self.selected_recipes = []
self.selected_packages = []
self.initial_selected_image = None
self.initial_selected_packages = []
self.initial_user_selected_packages = []
@@ -179,20 +171,33 @@ class Configuration:
# self.extra_setting/self.toolchain_build
# bblayers.conf
self.layers = params["layer"].split()
self.layers_non_removable = params["layers_non_removable"].split()
self.default_task = params["default_task"]
# proxy settings
self.enable_proxy = params["http_proxy"] != "" or params["https_proxy"] != "" \
or params["ftp_proxy"] != "" or params["socks_proxy"] != "" \
self.enable_proxy = params["http_proxy"] != "" or params["https_proxy"] != "" or params["ftp_proxy"] != "" \
or params["git_proxy_host"] != "" or params["git_proxy_port"] != "" \
or params["cvs_proxy_host"] != "" or params["cvs_proxy_port"] != ""
self.split_proxy("http", params["http_proxy"])
self.split_proxy("https", params["https_proxy"])
self.split_proxy("ftp", params["ftp_proxy"])
self.split_proxy("socks", params["socks_proxy"])
self.split_proxy("git", params["git_proxy_host"] + ":" + params["git_proxy_port"])
self.split_proxy("cvs", params["cvs_proxy_host"] + ":" + params["cvs_proxy_port"])
def load(self, template):
self.curr_mach = template.getVar("MACHINE")
self.curr_package_format = " ".join(template.getVar("PACKAGE_CLASSES").split("package_")).strip()
self.curr_distro = template.getVar("DISTRO")
self.dldir = template.getVar("DL_DIR")
self.sstatedir = template.getVar("SSTATE_DIR")
self.sstatemirror = template.getVar("SSTATE_MIRRORS")
try:
self.pmake = int(template.getVar("PARALLEL_MAKE").split()[1])
except:
pass
try:
self.bbthread = int(template.getVar("BB_NUMBER_THREADS"))
except:
pass
try:
self.image_rootfs_size = int(template.getVar("IMAGE_ROOTFS_SIZE"))
except:
@@ -204,9 +209,13 @@ class Configuration:
# image_overhead_factor is read-only.
self.incompat_license = template.getVar("INCOMPATIBLE_LICENSE")
self.curr_sdk_machine = template.getVar("SDKMACHINE")
self.conf_version = template.getVar("CONF_VERSION")
self.lconf_version = template.getVar("LCONF_VERSION")
self.extra_setting = eval(template.getVar("EXTRA_SETTING"))
self.toolchain_build = eval(template.getVar("TOOLCHAIN_BUILD"))
self.image_fstypes = template.getVar("IMAGE_FSTYPES")
# bblayers.conf
self.layers = template.getVar("BBLAYERS").split()
# image/recipes/packages
self.selected_image = template.getVar("__SELECTED_IMAGE__")
self.selected_recipes = template.getVar("DEPENDS").split()
@@ -217,35 +226,29 @@ class Configuration:
self.split_proxy("http", template.getVar("http_proxy"))
self.split_proxy("https", template.getVar("https_proxy"))
self.split_proxy("ftp", template.getVar("ftp_proxy"))
self.split_proxy("socks", template.getVar("all_proxy"))
self.split_proxy("git", template.getVar("GIT_PROXY_HOST") + ":" + template.getVar("GIT_PROXY_PORT"))
self.split_proxy("cvs", template.getVar("CVS_PROXY_HOST") + ":" + template.getVar("CVS_PROXY_PORT"))
def save(self, handler, template, defaults=False):
def save(self, template, defaults=False):
template.setVar("VERSION", "%s" % hobVer)
# bblayers.conf
handler.set_var_in_file("BBLAYERS", self.layers, "bblayers.conf")
template.setVar("BBLAYERS", " ".join(self.layers))
# local.conf
if not defaults:
handler.set_var_in_file("MACHINE", self.curr_mach, "local.conf")
handler.set_var_in_file("DISTRO", self.curr_distro, "local.conf")
handler.set_var_in_file("DL_DIR", self.dldir, "local.conf")
handler.set_var_in_file("SSTATE_DIR", self.sstatedir, "local.conf")
sstate_mirror_list = self.sstatemirror.split("\\n ")
sstate_mirror_list_modified = []
for mirror in sstate_mirror_list:
if mirror != "":
mirror = mirror + "\\n"
sstate_mirror_list_modified.append(mirror)
handler.set_var_in_file("SSTATE_MIRRORS", sstate_mirror_list_modified, "local.conf")
handler.set_var_in_file("PARALLEL_MAKE", "-j %s" % self.pmake, "local.conf")
handler.set_var_in_file("BB_NUMBER_THREADS", self.bbthread, "local.conf")
handler.set_var_in_file("PACKAGE_CLASSES", " ".join(["package_" + i for i in self.curr_package_format.split()]), "local.conf")
template.setVar("MACHINE", self.curr_mach)
template.setVar("DISTRO", self.curr_distro)
template.setVar("DL_DIR", self.dldir)
template.setVar("SSTATE_DIR", self.sstatedir)
template.setVar("SSTATE_MIRRORS", self.sstatemirror)
template.setVar("PARALLEL_MAKE", "-j %s" % self.pmake)
template.setVar("BB_NUMBER_THREADS", self.bbthread)
template.setVar("PACKAGE_CLASSES", " ".join(["package_" + i for i in self.curr_package_format.split()]))
template.setVar("IMAGE_ROOTFS_SIZE", self.image_rootfs_size)
template.setVar("IMAGE_EXTRA_SPACE", self.image_extra_size)
template.setVar("INCOMPATIBLE_LICENSE", self.incompat_license)
template.setVar("SDKMACHINE", self.curr_sdk_machine)
handler.set_var_in_file("CONF_VERSION", self.conf_version, "local.conf")
handler.set_var_in_file("LCONF_VERSION", self.lconf_version, "bblayers.conf")
template.setVar("CONF_VERSION", self.conf_version)
template.setVar("LCONF_VERSION", self.lconf_version)
template.setVar("EXTRA_SETTING", self.extra_setting)
template.setVar("TOOLCHAIN_BUILD", self.toolchain_build)
template.setVar("IMAGE_FSTYPES", self.image_fstypes)
@@ -260,7 +263,8 @@ class Configuration:
template.setVar("http_proxy", self.combine_proxy("http"))
template.setVar("https_proxy", self.combine_proxy("https"))
template.setVar("ftp_proxy", self.combine_proxy("ftp"))
template.setVar("all_proxy", self.combine_proxy("socks"))
template.setVar("GIT_PROXY_HOST", self.combine_host_only("git"))
template.setVar("GIT_PROXY_PORT", self.combine_port_only("git"))
template.setVar("CVS_PROXY_HOST", self.combine_host_only("cvs"))
template.setVar("CVS_PROXY_PORT", self.combine_port_only("cvs"))
@@ -275,8 +279,8 @@ class Configuration:
(self.lconf_version, self.extra_setting, self.toolchain_build, self.image_fstypes, self.selected_image)
s += "DEPENDS: '%s', IMAGE_INSTALL: '%s', enable_proxy: '%s', use_same_proxy: '%s', http_proxy: '%s', " % \
(self.selected_recipes, self.user_selected_packages, self.enable_proxy, self.same_proxy, self.combine_proxy("http"))
s += "https_proxy: '%s', ftp_proxy: '%s', all_proxy: '%s', CVS_PROXY_HOST: '%s', CVS_PROXY_PORT: '%s'" % \
(self.combine_proxy("https"), self.combine_proxy("ftp"), self.combine_proxy("socks"),
s += "https_proxy: '%s', ftp_proxy: '%s', GIT_PROXY_HOST: '%s', GIT_PROXY_PORT: '%s', CVS_PROXY_HOST: '%s', CVS_PROXY_PORT: '%s'" % \
(self.combine_proxy("https"), self.combine_proxy("ftp"),self.combine_host_only("git"), self.combine_port_only("git"),
self.combine_host_only("cvs"), self.combine_port_only("cvs"))
return s
@@ -434,12 +438,6 @@ class Builder(gtk.Window):
# Indicate whether the UI is working
self.sensitive = True
# Indicate whether the sanity check ran
self.sanity_checked = False
# save parsing warnings
self.parsing_warnings = []
# create visual elements
self.create_visual_elements()
@@ -457,20 +455,19 @@ class Builder(gtk.Window):
self.handler.build.connect("build-failed", self.handler_build_failed_cb)
self.handler.build.connect("build-aborted", self.handler_build_aborted_cb)
self.handler.build.connect("task-started", self.handler_task_started_cb)
self.handler.build.connect("disk-full", self.handler_disk_full_cb)
self.handler.build.connect("log-error", self.handler_build_failure_cb)
self.handler.build.connect("log-warning", self.handler_build_failure_cb)
self.handler.build.connect("log", self.handler_build_log_cb)
self.handler.build.connect("no-provider", self.handler_no_provider_cb)
self.handler.connect("generating-data", self.handler_generating_data_cb)
self.handler.connect("data-generated", self.handler_data_generated_cb)
self.handler.connect("command-succeeded", self.handler_command_succeeded_cb)
self.handler.connect("command-failed", self.handler_command_failed_cb)
self.handler.connect("parsing-warning", self.handler_parsing_warning_cb)
self.handler.connect("sanity-failed", self.handler_sanity_failed_cb)
self.handler.connect("recipe-populated", self.handler_recipe_populated_cb)
self.handler.connect("package-populated", self.handler_package_populated_cb)
self.handler.set_config_filter(hob_conf_filter)
self.initiate_new_build_async()
def create_visual_elements(self):
@@ -540,19 +537,19 @@ class Builder(gtk.Window):
if not self.display_sanity_check:
func()
else:
self.sanity_check_post_func = func
sanity_check_post_func = func
def generate_configuration(self):
if not self.sanity_checked:
self.show_sanity_check_page()
self.show_sanity_check_page()
self.handler.generate_configuration()
def initiate_new_build_async(self):
self.switch_page(self.MACHINE_SELECTION)
self.handler.init_cooker()
self.handler.set_extra_inherit("image_types")
self.generate_configuration()
self.load_template(TemplateMgr.convert_to_template_pathfilename("default", ".hob/"))
if self.load_template(TemplateMgr.convert_to_template_pathfilename("default", ".hob/")) == False:
self.show_sanity_check_page()
self.handler.init_cooker()
self.handler.set_extra_inherit("image_types")
self.generate_configuration()
def update_config_async(self):
self.switch_page(self.MACHINE_SELECTION)
@@ -606,18 +603,15 @@ class Builder(gtk.Window):
# Build image
self.set_user_config()
toolchain_packages = []
base_image = None
if self.configuration.toolchain_build:
toolchain_packages = self.package_model.get_selected_packages_toolchain()
if self.configuration.selected_image == self.recipe_model.__custom_image__:
packages = self.package_model.get_selected_packages()
image = self.hob_image
base_image = self.configuration.initial_selected_image
else:
packages = []
image = self.configuration.selected_image
self.handler.generate_image(image,
base_image,
self.hob_toolchain,
packages,
toolchain_packages,
@@ -661,7 +655,8 @@ class Builder(gtk.Window):
if not os.path.exists(layer+'/conf/layer.conf'):
return False
self.set_user_config_extra()
self.save_defaults() # remember layers and settings
self.update_config_async()
return True
def save_template(self, path, defaults=False):
@@ -675,7 +670,7 @@ class Builder(gtk.Window):
self.template = TemplateMgr()
try:
self.template.open(filename, path)
self.configuration.save(self.handler, self.template, defaults)
self.configuration.save(self.template, defaults)
self.template.save()
except Exception as e:
@@ -751,31 +746,6 @@ class Builder(gtk.Window):
self.previous_step = self.current_step
self.current_step = next_step
def set_user_config_proxies(self):
if self.configuration.enable_proxy == True:
self.handler.set_http_proxy(self.configuration.combine_proxy("http"))
self.handler.set_https_proxy(self.configuration.combine_proxy("https"))
self.handler.set_ftp_proxy(self.configuration.combine_proxy("ftp"))
self.handler.set_socks_proxy(self.configuration.combine_proxy("socks"))
self.handler.set_cvs_proxy(self.configuration.combine_host_only("cvs"), self.configuration.combine_port_only("cvs"))
elif self.configuration.enable_proxy == False:
self.handler.set_http_proxy("")
self.handler.set_https_proxy("")
self.handler.set_ftp_proxy("")
self.handler.set_socks_proxy("")
self.handler.set_cvs_proxy("", "")
def set_user_config_extra(self):
self.handler.set_rootfs_size(self.configuration.image_rootfs_size)
self.handler.set_extra_size(self.configuration.image_extra_size)
self.handler.set_incompatible_license(self.configuration.incompat_license)
self.handler.set_sdk_machine(self.configuration.curr_sdk_machine)
self.handler.set_image_fstypes(self.configuration.image_fstypes)
self.handler.set_extra_config(self.configuration.extra_setting)
self.handler.set_extra_inherit("packageinfo")
self.handler.set_extra_inherit("image_types")
self.set_user_config_proxies()
def set_user_config(self):
self.handler.init_cooker()
# set bb layers
@@ -789,7 +759,27 @@ class Builder(gtk.Window):
self.handler.set_sstate_mirrors(self.configuration.sstatemirror)
self.handler.set_pmake(self.configuration.pmake)
self.handler.set_bbthreads(self.configuration.bbthread)
self.set_user_config_extra()
self.handler.set_rootfs_size(self.configuration.image_rootfs_size)
self.handler.set_extra_size(self.configuration.image_extra_size)
self.handler.set_incompatible_license(self.configuration.incompat_license)
self.handler.set_sdk_machine(self.configuration.curr_sdk_machine)
self.handler.set_image_fstypes(self.configuration.image_fstypes)
self.handler.set_extra_config(self.configuration.extra_setting)
self.handler.set_extra_inherit("packageinfo")
self.handler.set_extra_inherit("image_types")
# set proxies
if self.configuration.enable_proxy == True:
self.handler.set_http_proxy(self.configuration.combine_proxy("http"))
self.handler.set_https_proxy(self.configuration.combine_proxy("https"))
self.handler.set_ftp_proxy(self.configuration.combine_proxy("ftp"))
self.handler.set_git_proxy(self.configuration.combine_host_only("git"), self.configuration.combine_port_only("git"))
self.handler.set_cvs_proxy(self.configuration.combine_host_only("cvs"), self.configuration.combine_port_only("cvs"))
elif self.configuration.enable_proxy == False:
self.handler.set_http_proxy("")
self.handler.set_https_proxy("")
self.handler.set_ftp_proxy("")
self.handler.set_git_proxy("", "")
self.handler.set_cvs_proxy("", "")
def update_recipe_model(self, selected_image, selected_recipes):
self.recipe_model.set_selected_image(selected_image)
@@ -840,9 +830,7 @@ class Builder(gtk.Window):
if not self.configuration.curr_mach:
self.configuration.curr_mach = self.handler.runCommand(["getVariable", "HOB_MACHINE"]) or ""
self.update_configuration_parameters(self.get_parameters_sync())
if not self.sanity_checked:
self.sanity_check()
self.sanity_checked = True
self.sanity_check()
elif initcmd == self.handler.SANITY_CHECK:
if self.had_network_error:
self.had_network_error = False
@@ -874,15 +862,6 @@ class Builder(gtk.Window):
response = dialog.run()
dialog.destroy()
def show_warning_dialog(self):
dialog = ParsingWarningsDialog(title = "View warnings",
warnings = self.parsing_warnings,
parent = None,
flags = gtk.DIALOG_DESTROY_WITH_PARENT
| gtk.DIALOG_NO_SEPARATOR)
response = dialog.run()
dialog.destroy()
def show_network_error_dialog(self):
lbl = "<b>Hob cannot connect to the network</b>\n"
msg = "Please check your network connection. If you are using a proxy server, please make sure it is configured correctly."
@@ -906,9 +885,6 @@ class Builder(gtk.Window):
self.show_error_dialog(msg)
self.reset()
def handler_parsing_warning_cb(self, handler, warn_msg):
self.parsing_warnings.append(warn_msg)
def handler_sanity_failed_cb(self, handler, msg, network_error):
self.reset()
if network_error:
@@ -968,10 +944,10 @@ class Builder(gtk.Window):
self.package_details_page.refresh_selection()
def handler_recipe_populated_cb(self, handler):
self.image_configuration_page.update_progress_bar("Populating recipes", 0.99)
self.image_configuration_page.update_progress_bar("Populated recipes", 0.99)
def handler_package_populated_cb(self, handler):
self.image_configuration_page.update_progress_bar("Populating packages", 1.0)
self.image_configuration_page.update_progress_bar("Populated packages", 1.0)
def handler_parsing_started_cb(self, handler, message):
if self.current_step != self.RCPPKGINFO_POPULATING:
@@ -981,10 +957,10 @@ class Builder(gtk.Window):
if message["eventname"] == "TreeDataPreparationStarted":
fraction = 0.6 + fraction
self.image_configuration_page.stop_button.set_sensitive(False)
self.image_configuration_page.update_progress_bar("Generating dependency tree", fraction)
else:
self.image_configuration_page.stop_button.set_sensitive(True)
self.image_configuration_page.update_progress_bar(message["title"], fraction)
self.image_configuration_page.update_progress_bar(message["title"], fraction)
def handler_parsing_cb(self, handler, message):
if self.current_step != self.RCPPKGINFO_POPULATING:
@@ -993,10 +969,9 @@ class Builder(gtk.Window):
fraction = message["current"] * 1.0/message["total"]
if message["eventname"] == "TreeDataPreparationProgress":
fraction = 0.6 + 0.38 * fraction
self.image_configuration_page.update_progress_bar("Generating dependency tree", fraction)
else:
fraction = 0.6 * fraction
self.image_configuration_page.update_progress_bar(message["title"], fraction)
self.image_configuration_page.update_progress_bar(message["title"], fraction)
def handler_parsing_completed_cb(self, handler, message):
if self.current_step != self.RCPPKGINFO_POPULATING:
@@ -1006,7 +981,7 @@ class Builder(gtk.Window):
fraction = 0.98
else:
fraction = 0.6
self.image_configuration_page.update_progress_bar("Generating dependency tree", fraction)
self.image_configuration_page.update_progress_bar(message["title"], fraction)
def handler_build_started_cb(self, running_build):
if self.current_step == self.FAST_IMAGE_GENERATING:
@@ -1026,13 +1001,10 @@ class Builder(gtk.Window):
fraction = 0.9
elif self.current_step == self.IMAGE_GENERATING:
fraction = 1.0
version = ""
self.parameters.image_names = []
selected_image = self.recipe_model.get_selected_image()
if selected_image == self.recipe_model.__custom_image__:
if self.configuration.initial_selected_image != selected_image:
version = self.recipe_model.get_custom_image_version()
linkname = 'hob-image' + version+ "-" + self.configuration.curr_mach
linkname = 'hob-image-' + self.configuration.curr_mach
else:
linkname = selected_image + '-' + self.configuration.curr_mach
image_extension = self.get_image_extension()
@@ -1145,9 +1117,6 @@ class Builder(gtk.Window):
self.build_details_page.update_progress_bar(title + ": ", fraction)
self.build_details_page.update_build_status(message["current"], message["total"], message["task"])
def handler_disk_full_cb(self, running_build):
self.disk_full = True
def handler_build_failure_cb(self, running_build):
self.build_details_page.show_issues()
@@ -1207,42 +1176,15 @@ class Builder(gtk.Window):
self.fast_generate_image_async(True)
def show_recipe_property_dialog(self, properties):
information = {}
dialog = PropertyDialog(title = properties["name"] +' '+ "properties",
parent = self,
information = properties,
flags = gtk.DIALOG_DESTROY_WITH_PARENT
| gtk.DIALOG_NO_SEPARATOR)
def show_binb_dialog(self, binb):
markup = "<b>Brought in by:</b>\n%s" % binb
ptip = PersistentTooltip(markup, self)
dialog.set_modal(False)
button = dialog.add_button("Close", gtk.RESPONSE_NO)
HobAltButton.style_button(button)
button.connect("clicked", lambda w: dialog.destroy())
dialog.run()
def show_packages_property_dialog(self, properties):
information = {}
dialog = PropertyDialog(title = properties["name"] +' '+ "properties",
parent = self,
information = properties,
flags = gtk.DIALOG_DESTROY_WITH_PARENT
| gtk.DIALOG_NO_SEPARATOR)
dialog.set_modal(False)
button = dialog.add_button("Close", gtk.RESPONSE_NO)
HobAltButton.style_button(button)
button.connect("clicked", lambda w: dialog.destroy())
dialog.run()
ptip.show()
def show_layer_selection_dialog(self):
dialog = LayerSelectionDialog(title = "Layers",
layers = copy.deepcopy(self.configuration.layers),
layers_non_removable = copy.deepcopy(self.configuration.layers_non_removable),
all_layers = self.parameters.all_layers,
parent = self,
flags = gtk.DIALOG_MODAL
@@ -1261,6 +1203,39 @@ class Builder(gtk.Window):
self.update_config_async()
dialog.destroy()
def show_load_template_dialog(self):
dialog = gtk.FileChooserDialog("Load Template Files", self,
gtk.FILE_CHOOSER_ACTION_OPEN)
button = dialog.add_button("Cancel", gtk.RESPONSE_NO)
HobAltButton.style_button(button)
button = dialog.add_button("Open", gtk.RESPONSE_YES)
HobButton.style_button(button)
filter = gtk.FileFilter()
filter.set_name("Hob Files")
filter.add_pattern("*.hob")
dialog.add_filter(filter)
response = dialog.run()
path = None
if response == gtk.RESPONSE_YES:
path = dialog.get_filename()
dialog.destroy()
return response == gtk.RESPONSE_YES, path
def show_save_template_dialog(self):
dialog = gtk.FileChooserDialog("Save Template Files", self,
gtk.FILE_CHOOSER_ACTION_SAVE)
button = dialog.add_button("Cancel", gtk.RESPONSE_NO)
HobAltButton.style_button(button)
button = dialog.add_button("Save", gtk.RESPONSE_YES)
HobButton.style_button(button)
dialog.set_current_name("hob")
response = dialog.run()
if response == gtk.RESPONSE_YES:
path = dialog.get_filename()
self.save_template(path)
dialog.destroy()
def get_image_extension(self):
image_extension = {}
for type in self.parameters.image_types:
@@ -1299,7 +1274,7 @@ class Builder(gtk.Window):
dialog.destroy()
def show_adv_settings_dialog(self, tab=None):
dialog = AdvancedSettingsDialog(title = "Advanced configuration",
dialog = AdvancedSettingDialog(title = "Advanced configuration",
configuration = copy.deepcopy(self.configuration),
all_image_types = self.parameters.image_types,
all_package_formats = self.parameters.all_package_formats,
@@ -1335,8 +1310,7 @@ class Builder(gtk.Window):
parent = self,
flags = gtk.DIALOG_MODAL
| gtk.DIALOG_DESTROY_WITH_PARENT
| gtk.DIALOG_NO_SEPARATOR,
handler = self.handler)
| gtk.DIALOG_NO_SEPARATOR)
button = dialog.add_button("Cancel", gtk.RESPONSE_NO)
HobAltButton.style_button(button)
button = dialog.add_button("Save", gtk.RESPONSE_YES)
@@ -1349,14 +1323,6 @@ class Builder(gtk.Window):
self.configuration = dialog.configuration
self.save_defaults() # remember settings
settings_changed = dialog.settings_changed
if dialog.proxy_settings_changed:
self.set_user_config_proxies()
elif dialog.proxy_test_ran:
# The user might have modified the proxies in the "Proxy"
# tab, which in turn made the proxy settings modify in bb.
# If "Cancel" was pressed, restore the previous proxy
# settings inside bb.
self.set_user_config_proxies()
dialog.destroy()
return response == gtk.RESPONSE_YES, settings_changed
@@ -1514,7 +1480,7 @@ class Builder(gtk.Window):
if response != gtk.RESPONSE_CANCEL:
self.stopping = True
if response == gtk.RESPONSE_OK:
self.build_details_page.progress_bar.set_stop_title("Stopping the build....")
self.build_details_page.progress_bar.set_title("Stopping the build...")
self.build_details_page.progress_bar.set_rcstyle("stop")
self.cancel_build_sync()
elif response == gtk.RESPONSE_YES:

File diff suppressed because it is too large Load Diff

View File

@@ -1,336 +0,0 @@
#
# BitBake Graphical GTK User Interface
#
# Copyright (C) 2011-2012 Intel Corporation
#
# Authored by Joshua Lock <josh@linux.intel.com>
# Authored by Dongxiao Xu <dongxiao.xu@intel.com>
# Authored by Shane Wang <shane.wang@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 hashlib
from bb.ui.crumbs.hobwidget import HobInfoButton, HobButton
from bb.ui.crumbs.progressbar import HobProgressBar
from bb.ui.crumbs.hig.settingsuihelper import SettingsUIHelper
from bb.ui.crumbs.hig.crumbsdialog import CrumbsDialog
from bb.ui.crumbs.hig.crumbsmessagedialog import CrumbsMessageDialog
from bb.ui.crumbs.hig.proxydetailsdialog import ProxyDetailsDialog
"""
The following are convenience classes for implementing GNOME HIG compliant
BitBake GUI's
In summary: spacing = 12px, border-width = 6px
"""
class AdvancedSettingsDialog (CrumbsDialog, SettingsUIHelper):
def details_cb(self, button, parent, protocol):
dialog = ProxyDetailsDialog(title = protocol.upper() + " Proxy Details",
user = self.configuration.proxies[protocol][1],
passwd = self.configuration.proxies[protocol][2],
parent = parent,
flags = gtk.DIALOG_MODAL
| gtk.DIALOG_DESTROY_WITH_PARENT
| gtk.DIALOG_NO_SEPARATOR)
dialog.add_button(gtk.STOCK_CLOSE, gtk.RESPONSE_OK)
response = dialog.run()
if response == gtk.RESPONSE_OK:
self.configuration.proxies[protocol][1] = dialog.user
self.configuration.proxies[protocol][2] = dialog.passwd
self.refresh_proxy_components()
dialog.destroy()
def set_save_button(self, button):
self.save_button = button
def rootfs_combo_changed_cb(self, rootfs_combo, all_package_format, check_hbox):
combo_item = self.rootfs_combo.get_active_text()
modified = False
for child in check_hbox.get_children():
if isinstance(child, gtk.CheckButton):
check_hbox.remove(child)
modified = True
for format in all_package_format:
if format != combo_item:
check_button = gtk.CheckButton(format)
check_hbox.pack_start(check_button, expand=False, fill=False)
modified = True
if modified:
check_hbox.remove(self.pkgfmt_info)
check_hbox.pack_start(self.pkgfmt_info, expand=False, fill=False)
check_hbox.show_all()
def gen_pkgfmt_widget(self, curr_package_format, all_package_format, tooltip_combo="", tooltip_extra=""):
pkgfmt_vbox = gtk.VBox(False, 6)
label = self.gen_label_widget("Root file system package format")
pkgfmt_vbox.pack_start(label, expand=False, fill=False)
rootfs_format = ""
if curr_package_format:
rootfs_format = curr_package_format.split()[0]
rootfs_format_widget, rootfs_combo = self.gen_combo_widget(rootfs_format, all_package_format, tooltip_combo)
pkgfmt_vbox.pack_start(rootfs_format_widget, expand=False, fill=False)
label = self.gen_label_widget("Additional package formats")
pkgfmt_vbox.pack_start(label, expand=False, fill=False)
check_hbox = gtk.HBox(False, 12)
pkgfmt_vbox.pack_start(check_hbox, expand=False, fill=False)
for format in all_package_format:
if format != rootfs_format:
check_button = gtk.CheckButton(format)
is_active = (format in curr_package_format.split())
check_button.set_active(is_active)
check_hbox.pack_start(check_button, expand=False, fill=False)
self.pkgfmt_info = HobInfoButton(tooltip_extra, self)
check_hbox.pack_start(self.pkgfmt_info, expand=False, fill=False)
rootfs_combo.connect("changed", self.rootfs_combo_changed_cb, all_package_format, check_hbox)
pkgfmt_vbox.show_all()
return pkgfmt_vbox, rootfs_combo, check_hbox
def __init__(self, title, configuration, all_image_types,
all_package_formats, all_distros, all_sdk_machines,
max_threads, parent, flags, buttons=None):
super(AdvancedSettingsDialog, self).__init__(title, parent, flags, buttons)
# class members from other objects
# bitbake settings from Builder.Configuration
self.configuration = configuration
self.image_types = all_image_types
self.all_package_formats = all_package_formats
self.all_distros = all_distros[:]
self.all_sdk_machines = all_sdk_machines
self.max_threads = max_threads
# class members for internal use
self.distro_combo = None
self.dldir_text = None
self.sstatedir_text = None
self.sstatemirror_text = None
self.bb_spinner = None
self.pmake_spinner = None
self.rootfs_size_spinner = None
self.extra_size_spinner = None
self.gplv3_checkbox = None
self.toolchain_checkbox = None
self.image_types_checkbuttons = {}
self.md5 = self.config_md5()
self.settings_changed = False
# create visual elements on the dialog
self.save_button = None
self.create_visual_elements()
self.connect("response", self.response_cb)
def _get_sorted_value(self, var):
return " ".join(sorted(str(var).split())) + "\n"
def config_md5(self):
data = ""
data += ("PACKAGE_CLASSES: " + self.configuration.curr_package_format + '\n')
data += ("DISTRO: " + self._get_sorted_value(self.configuration.curr_distro))
data += ("IMAGE_ROOTFS_SIZE: " + self._get_sorted_value(self.configuration.image_rootfs_size))
data += ("IMAGE_EXTRA_SIZE: " + self._get_sorted_value(self.configuration.image_extra_size))
data += ("INCOMPATIBLE_LICENSE: " + self._get_sorted_value(self.configuration.incompat_license))
data += ("SDK_MACHINE: " + self._get_sorted_value(self.configuration.curr_sdk_machine))
data += ("TOOLCHAIN_BUILD: " + self._get_sorted_value(self.configuration.toolchain_build))
data += ("IMAGE_FSTYPES: " + self._get_sorted_value(self.configuration.image_fstypes))
return hashlib.md5(data).hexdigest()
def create_visual_elements(self):
self.nb = gtk.Notebook()
self.nb.set_show_tabs(True)
self.nb.append_page(self.create_image_types_page(), gtk.Label("Image types"))
self.nb.append_page(self.create_output_page(), gtk.Label("Output"))
self.nb.set_current_page(0)
self.vbox.pack_start(self.nb, expand=True, fill=True)
self.vbox.pack_end(gtk.HSeparator(), expand=True, fill=True)
self.show_all()
def get_num_checked_image_types(self):
total = 0
for b in self.image_types_checkbuttons.values():
if b.get_active():
total = total + 1
return total
def set_save_button_state(self):
if self.save_button:
self.save_button.set_sensitive(self.get_num_checked_image_types() > 0)
def image_type_checkbutton_clicked_cb(self, button):
self.set_save_button_state()
if self.get_num_checked_image_types() == 0:
# Show an error dialog
lbl = "<b>Select an image type</b>\n\nYou need to select at least one image type."
dialog = CrumbsMessageDialog(self, lbl, gtk.STOCK_DIALOG_WARNING)
button = dialog.add_button("OK", gtk.RESPONSE_OK)
HobButton.style_button(button)
response = dialog.run()
dialog.destroy()
def create_image_types_page(self):
main_vbox = gtk.VBox(False, 16)
main_vbox.set_border_width(6)
advanced_vbox = gtk.VBox(False, 6)
advanced_vbox.set_border_width(6)
distro_vbox = gtk.VBox(False, 6)
label = self.gen_label_widget("Distro:")
tooltip = "Selects the Yocto Project distribution you want"
try:
i = self.all_distros.index( "defaultsetup" )
except ValueError:
i = -1
if i != -1:
self.all_distros[ i ] = "Default"
if self.configuration.curr_distro == "defaultsetup":
self.configuration.curr_distro = "Default"
distro_widget, self.distro_combo = self.gen_combo_widget(self.configuration.curr_distro, self.all_distros,"<b>Distro</b>" + "*" + tooltip)
distro_vbox.pack_start(label, expand=False, fill=False)
distro_vbox.pack_start(distro_widget, expand=False, fill=False)
main_vbox.pack_start(distro_vbox, expand=False, fill=False)
rows = (len(self.image_types)+1)/3
table = gtk.Table(rows + 1, 10, True)
advanced_vbox.pack_start(table, expand=False, fill=False)
tooltip = "Image file system types you want."
info = HobInfoButton("<b>Image types</b>" + "*" + tooltip, self)
label = self.gen_label_widget("Image types:")
align = gtk.Alignment(0, 0.5, 0, 0)
table.attach(align, 0, 4, 0, 1)
align.add(label)
table.attach(info, 4, 5, 0, 1)
i = 1
j = 1
for image_type in sorted(self.image_types):
self.image_types_checkbuttons[image_type] = gtk.CheckButton(image_type)
self.image_types_checkbuttons[image_type].connect("toggled", self.image_type_checkbutton_clicked_cb)
article = ""
if image_type.startswith(("a", "e", "i", "o", "u")):
article = "n"
self.image_types_checkbuttons[image_type].set_tooltip_text("Build a%s %s image" % (article, image_type))
table.attach(self.image_types_checkbuttons[image_type], j - 1, j + 3, i, i + 1)
if image_type in self.configuration.image_fstypes.split():
self.image_types_checkbuttons[image_type].set_active(True)
i += 1
if i > rows:
i = 1
j = j + 4
main_vbox.pack_start(advanced_vbox, expand=False, fill=False)
self.set_save_button_state()
return main_vbox
def create_output_page(self):
advanced_vbox = gtk.VBox(False, 6)
advanced_vbox.set_border_width(6)
advanced_vbox.pack_start(self.gen_label_widget('<span weight="bold">Package format</span>'), expand=False, fill=False)
sub_vbox = gtk.VBox(False, 6)
advanced_vbox.pack_start(sub_vbox, expand=False, fill=False)
tooltip_combo = "Selects the package format used to generate rootfs."
tooltip_extra = "Selects extra package formats to build"
pkgfmt_widget, self.rootfs_combo, self.check_hbox = self.gen_pkgfmt_widget(self.configuration.curr_package_format, self.all_package_formats,"<b>Root file system package format</b>" + "*" + tooltip_combo,"<b>Additional package formats</b>" + "*" + tooltip_extra)
sub_vbox.pack_start(pkgfmt_widget, expand=False, fill=False)
advanced_vbox.pack_start(self.gen_label_widget('<span weight="bold">Image size</span>'), expand=False, fill=False)
sub_vbox = gtk.VBox(False, 6)
advanced_vbox.pack_start(sub_vbox, expand=False, fill=False)
label = self.gen_label_widget("Image basic size (in MB)")
tooltip = "Defines the size for the generated image. The OpenEmbedded build system determines the final size for the generated image using an algorithm that takes into account the initial disk space used for the generated image, the Image basic size value, and the Additional free space value.\n\nFor more information, check the <a href=\"http://www.yoctoproject.org/docs/current/poky-ref-manual/poky-ref-manual.html#var-IMAGE_ROOTFS_SIZE\">Yocto Project Reference Manual</a>."
rootfs_size_widget, self.rootfs_size_spinner = self.gen_spinner_widget(int(self.configuration.image_rootfs_size*1.0/1024), 0, 65536,"<b>Image basic size</b>" + "*" + tooltip)
sub_vbox.pack_start(label, expand=False, fill=False)
sub_vbox.pack_start(rootfs_size_widget, expand=False, fill=False)
sub_vbox = gtk.VBox(False, 6)
advanced_vbox.pack_start(sub_vbox, expand=False, fill=False)
label = self.gen_label_widget("Additional free space (in MB)")
tooltip = "Sets extra free disk space to be added to the generated image. Use this variable when you want to ensure that a specific amount of free disk space is available on a device after an image is installed and running."
extra_size_widget, self.extra_size_spinner = self.gen_spinner_widget(int(self.configuration.image_extra_size*1.0/1024), 0, 65536,"<b>Additional free space</b>" + "*" + tooltip)
sub_vbox.pack_start(label, expand=False, fill=False)
sub_vbox.pack_start(extra_size_widget, expand=False, fill=False)
advanced_vbox.pack_start(self.gen_label_widget('<span weight="bold">Licensing</span>'), expand=False, fill=False)
self.gplv3_checkbox = gtk.CheckButton("Exclude GPLv3 packages")
self.gplv3_checkbox.set_tooltip_text("Check this box to prevent GPLv3 packages from being included in your image")
if "GPLv3" in self.configuration.incompat_license.split():
self.gplv3_checkbox.set_active(True)
else:
self.gplv3_checkbox.set_active(False)
advanced_vbox.pack_start(self.gplv3_checkbox, expand=False, fill=False)
advanced_vbox.pack_start(self.gen_label_widget('<span weight="bold">Toolchain</span>'), expand=False, fill=False)
sub_hbox = gtk.HBox(False, 6)
advanced_vbox.pack_start(sub_hbox, expand=False, fill=False)
self.toolchain_checkbox = gtk.CheckButton("Build toolchain")
self.toolchain_checkbox.set_tooltip_text("Check this box to build the related toolchain with your image")
self.toolchain_checkbox.set_active(self.configuration.toolchain_build)
sub_hbox.pack_start(self.toolchain_checkbox, expand=False, fill=False)
tooltip = "Selects the host platform for which you want to run the toolchain"
sdk_machine_widget, self.sdk_machine_combo = self.gen_combo_widget(self.configuration.curr_sdk_machine, self.all_sdk_machines,"<b>Build toolchain</b>" + "*" + tooltip)
sub_hbox.pack_start(sdk_machine_widget, expand=False, fill=False)
return advanced_vbox
def response_cb(self, dialog, response_id):
package_format = []
package_format.append(self.rootfs_combo.get_active_text())
for child in self.check_hbox:
if isinstance(child, gtk.CheckButton) and child.get_active():
package_format.append(child.get_label())
self.configuration.curr_package_format = " ".join(package_format)
distro = self.distro_combo.get_active_text()
if distro == "Default":
distro = "defaultsetup"
self.configuration.curr_distro = distro
self.configuration.image_rootfs_size = self.rootfs_size_spinner.get_value_as_int() * 1024
self.configuration.image_extra_size = self.extra_size_spinner.get_value_as_int() * 1024
self.configuration.image_fstypes = ""
for image_type in self.image_types:
if self.image_types_checkbuttons[image_type].get_active():
self.configuration.image_fstypes += (" " + image_type)
self.configuration.image_fstypes.strip()
if self.gplv3_checkbox.get_active():
if "GPLv3" not in self.configuration.incompat_license.split():
self.configuration.incompat_license += " GPLv3"
else:
if "GPLv3" in self.configuration.incompat_license.split():
self.configuration.incompat_license = self.configuration.incompat_license.split().remove("GPLv3")
self.configuration.incompat_license = " ".join(self.configuration.incompat_license or [])
self.configuration.incompat_license = self.configuration.incompat_license.strip()
self.configuration.toolchain_build = self.toolchain_checkbox.get_active()
self.configuration.curr_sdk_machine = self.sdk_machine_combo.get_active_text()
md5 = self.config_md5()
self.settings_changed = (self.md5 != md5)

View File

@@ -1,44 +0,0 @@
#
# BitBake Graphical GTK User Interface
#
# Copyright (C) 2011-2012 Intel Corporation
#
# Authored by Joshua Lock <josh@linux.intel.com>
# Authored by Dongxiao Xu <dongxiao.xu@intel.com>
# Authored by Shane Wang <shane.wang@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
"""
The following are convenience classes for implementing GNOME HIG compliant
BitBake GUI's
In summary: spacing = 12px, border-width = 6px
"""
class CrumbsDialog(gtk.Dialog):
"""
A GNOME HIG compliant dialog widget.
Add buttons with gtk.Dialog.add_button or gtk.Dialog.add_buttons
"""
def __init__(self, title="", parent=None, flags=0, buttons=None):
super(CrumbsDialog, self).__init__(title, parent, flags, buttons)
self.set_property("has-separator", False) # note: deprecated in 2.22
self.set_border_width(6)
self.vbox.set_property("spacing", 12)
self.action_area.set_property("spacing", 12)
self.action_area.set_property("border-width", 6)

View File

@@ -1,95 +0,0 @@
#
# BitBake Graphical GTK User Interface
#
# Copyright (C) 2011-2012 Intel Corporation
#
# Authored by Joshua Lock <josh@linux.intel.com>
# Authored by Dongxiao Xu <dongxiao.xu@intel.com>
# Authored by Shane Wang <shane.wang@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 glib
import gtk
from bb.ui.crumbs.hobwidget import HobIconChecker
from bb.ui.crumbs.hig.crumbsdialog import CrumbsDialog
"""
The following are convenience classes for implementing GNOME HIG compliant
BitBake GUI's
In summary: spacing = 12px, border-width = 6px
"""
class CrumbsMessageDialog(CrumbsDialog):
"""
A GNOME HIG compliant dialog widget.
Add buttons with gtk.Dialog.add_button or gtk.Dialog.add_buttons
"""
def __init__(self, parent=None, label="", icon=gtk.STOCK_INFO, msg=""):
super(CrumbsMessageDialog, self).__init__("", parent, gtk.DIALOG_MODAL)
self.set_border_width(6)
self.vbox.set_property("spacing", 12)
self.action_area.set_property("spacing", 12)
self.action_area.set_property("border-width", 6)
first_column = gtk.HBox(spacing=12)
first_column.set_property("border-width", 6)
first_column.show()
self.vbox.add(first_column)
self.icon = gtk.Image()
# We have our own Info icon which should be used in preference of the stock icon
self.icon_chk = HobIconChecker()
self.icon.set_from_stock(self.icon_chk.check_stock_icon(icon), gtk.ICON_SIZE_DIALOG)
self.icon.set_property("yalign", 0.00)
self.icon.show()
first_column.pack_start(self.icon, expand=False, fill=True, padding=0)
if 0 <= len(msg) < 200:
lbl = label + "%s" % glib.markup_escape_text(msg)
self.label_short = gtk.Label()
self.label_short.set_use_markup(True)
self.label_short.set_line_wrap(True)
self.label_short.set_markup(lbl)
self.label_short.set_property("yalign", 0.00)
self.label_short.show()
first_column.add(self.label_short)
else:
second_row = gtk.VBox(spacing=12)
second_row.set_property("border-width", 6)
self.label_long = gtk.Label()
self.label_long.set_use_markup(True)
self.label_long.set_line_wrap(True)
self.label_long.set_markup(label)
self.label_long.set_alignment(0.0, 0.0)
second_row.pack_start(self.label_long, expand=False, fill=False, padding=0)
self.label_long.show()
self.textWindow = gtk.ScrolledWindow()
self.textWindow.set_shadow_type(gtk.SHADOW_IN)
self.textWindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
self.msgView = gtk.TextView()
self.msgView.set_editable(False)
self.msgView.set_wrap_mode(gtk.WRAP_WORD)
self.msgView.set_cursor_visible(False)
self.msgView.set_size_request(300, 300)
self.buf = gtk.TextBuffer()
self.buf.set_text(msg)
self.msgView.set_buffer(self.buf)
self.textWindow.add(self.msgView)
self.msgView.show()
second_row.add(self.textWindow)
self.textWindow.show()
first_column.add(second_row)
second_row.show()

View File

@@ -1,215 +0,0 @@
#
# BitBake Graphical GTK User Interface
#
# Copyright (C) 2011-2012 Intel Corporation
#
# Authored by Joshua Lock <josh@linux.intel.com>
# Authored by Dongxiao Xu <dongxiao.xu@intel.com>
# Authored by Shane Wang <shane.wang@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 glob
import gtk
import gobject
import os
import re
import shlex
import subprocess
import tempfile
from bb.ui.crumbs.hobwidget import hic, HobButton
from bb.ui.crumbs.progressbar import HobProgressBar
import bb.ui.crumbs.utils
import bb.process
from bb.ui.crumbs.hig.crumbsdialog import CrumbsDialog
from bb.ui.crumbs.hig.crumbsmessagedialog import CrumbsMessageDialog
"""
The following are convenience classes for implementing GNOME HIG compliant
BitBake GUI's
In summary: spacing = 12px, border-width = 6px
"""
class DeployImageDialog (CrumbsDialog):
__dummy_usb__ = "--select a usb drive--"
def __init__(self, title, image_path, parent, flags, buttons=None, standalone=False):
super(DeployImageDialog, self).__init__(title, parent, flags, buttons)
self.image_path = image_path
self.standalone = standalone
self.create_visual_elements()
self.connect("response", self.response_cb)
def create_visual_elements(self):
self.set_size_request(600, 400)
label = gtk.Label()
label.set_alignment(0.0, 0.5)
markup = "<span font_desc='12'>The image to be written into usb drive:</span>"
label.set_markup(markup)
self.vbox.pack_start(label, expand=False, fill=False, padding=2)
table = gtk.Table(2, 10, False)
table.set_col_spacings(5)
table.set_row_spacings(5)
self.vbox.pack_start(table, expand=True, fill=True)
scroll = gtk.ScrolledWindow()
scroll.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
scroll.set_shadow_type(gtk.SHADOW_IN)
tv = gtk.TextView()
tv.set_editable(False)
tv.set_wrap_mode(gtk.WRAP_WORD)
tv.set_cursor_visible(False)
self.buf = gtk.TextBuffer()
self.buf.set_text(self.image_path)
tv.set_buffer(self.buf)
scroll.add(tv)
table.attach(scroll, 0, 10, 0, 1)
# There are 2 ways to use DeployImageDialog
# One way is that called by HOB when the 'Deploy Image' button is clicked
# The other way is that called by a standalone script.
# Following block of codes handles the latter way. It adds a 'Select Image' button and
# emit a signal when the button is clicked.
if self.standalone:
gobject.signal_new("select_image_clicked", self, gobject.SIGNAL_RUN_FIRST,
gobject.TYPE_NONE, ())
icon = gtk.Image()
pix_buffer = gtk.gdk.pixbuf_new_from_file(hic.ICON_IMAGES_DISPLAY_FILE)
icon.set_from_pixbuf(pix_buffer)
button = gtk.Button("Select Image")
button.set_image(icon)
#button.set_size_request(140, 50)
table.attach(button, 9, 10, 1, 2, gtk.FILL, 0, 0, 0)
button.connect("clicked", self.select_image_button_clicked_cb)
separator = gtk.HSeparator()
self.vbox.pack_start(separator, expand=False, fill=False, padding=10)
self.usb_desc = gtk.Label()
self.usb_desc.set_alignment(0.0, 0.5)
markup = "<span font_desc='12'>You haven't chosen any USB drive.</span>"
self.usb_desc.set_markup(markup)
self.usb_combo = gtk.combo_box_new_text()
self.usb_combo.connect("changed", self.usb_combo_changed_cb)
model = self.usb_combo.get_model()
model.clear()
self.usb_combo.append_text(self.__dummy_usb__)
for usb in self.find_all_usb_devices():
self.usb_combo.append_text("/dev/" + usb)
self.usb_combo.set_active(0)
self.vbox.pack_start(self.usb_combo, expand=False, fill=False)
self.vbox.pack_start(self.usb_desc, expand=False, fill=False, padding=2)
self.progress_bar = HobProgressBar()
self.vbox.pack_start(self.progress_bar, expand=False, fill=False)
separator = gtk.HSeparator()
self.vbox.pack_start(separator, expand=False, fill=True, padding=10)
self.vbox.show_all()
self.progress_bar.hide()
def set_image_text_buffer(self, image_path):
self.buf.set_text(image_path)
def set_image_path(self, image_path):
self.image_path = image_path
def popen_read(self, cmd):
tmpout, errors = bb.process.run("%s" % cmd)
return tmpout.strip()
def find_all_usb_devices(self):
usb_devs = [ os.readlink(u)
for u in glob.glob('/dev/disk/by-id/usb*')
if not re.search(r'part\d+', u) ]
return [ '%s' % u[u.rfind('/')+1:] for u in usb_devs ]
def get_usb_info(self, dev):
return "%s %s" % \
(self.popen_read('cat /sys/class/block/%s/device/vendor' % dev),
self.popen_read('cat /sys/class/block/%s/device/model' % dev))
def select_image_button_clicked_cb(self, button):
self.emit('select_image_clicked')
def usb_combo_changed_cb(self, usb_combo):
combo_item = self.usb_combo.get_active_text()
if not combo_item or combo_item == self.__dummy_usb__:
markup = "<span font_desc='12'>You haven't chosen any USB drive.</span>"
self.usb_desc.set_markup(markup)
else:
markup = "<span font_desc='12'>" + self.get_usb_info(combo_item.lstrip("/dev/")) + "</span>"
self.usb_desc.set_markup(markup)
def response_cb(self, dialog, response_id):
if response_id == gtk.RESPONSE_YES:
lbl = ''
combo_item = self.usb_combo.get_active_text()
if combo_item and combo_item != self.__dummy_usb__ and self.image_path:
cmdline = bb.ui.crumbs.utils.which_terminal()
if cmdline:
tmpfile = tempfile.NamedTemporaryFile()
cmdline += "\"sudo dd if=" + self.image_path + \
" of=" + combo_item + "; echo $? > " + tmpfile.name + "\""
subprocess.call(shlex.split(cmdline))
if int(tmpfile.readline().strip()) == 0:
lbl = "<b>Deploy image successfully.</b>"
else:
lbl = "<b>Failed to deploy image.</b>\nPlease check image <b>%s</b> exists and USB device <b>%s</b> is writable." % (self.image_path, combo_item)
tmpfile.close()
else:
if not self.image_path:
lbl = "<b>No selection made.</b>\nYou have not selected an image to deploy."
else:
lbl = "<b>No selection made.</b>\nYou have not selected a USB device."
if len(lbl):
crumbs_dialog = CrumbsMessageDialog(self, lbl, gtk.STOCK_DIALOG_INFO)
button = crumbs_dialog.add_button("Close", gtk.RESPONSE_OK)
HobButton.style_button(button)
crumbs_dialog.run()
crumbs_dialog.destroy()
def update_progress_bar(self, title, fraction, status=None):
self.progress_bar.update(fraction)
self.progress_bar.set_title(title)
self.progress_bar.set_rcstyle(status)
def write_file(self, ifile, ofile):
self.progress_bar.reset()
self.progress_bar.show()
f_from = os.open(ifile, os.O_RDONLY)
f_to = os.open(ofile, os.O_WRONLY)
total_size = os.stat(ifile).st_size
written_size = 0
while True:
buf = os.read(f_from, 1024*1024)
if not buf:
break
os.write(f_to, buf)
written_size += 1024*1024
self.update_progress_bar("Writing to usb:", written_size * 1.0/total_size)
self.update_progress_bar("Writing completed:", 1.0)
os.close(f_from)
os.close(f_to)
self.progress_bar.hide()

View File

@@ -1,172 +0,0 @@
#
# BitBake Graphical GTK User Interface
#
# Copyright (C) 2011-2012 Intel Corporation
#
# Authored by Joshua Lock <josh@linux.intel.com>
# Authored by Dongxiao Xu <dongxiao.xu@intel.com>
# Authored by Shane Wang <shane.wang@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
import os
from bb.ui.crumbs.hobwidget import HobViewTable, HobInfoButton, HobButton, HobAltButton
from bb.ui.crumbs.hig.crumbsdialog import CrumbsDialog
from bb.ui.crumbs.hig.layerselectiondialog import LayerSelectionDialog
"""
The following are convenience classes for implementing GNOME HIG compliant
BitBake GUI's
In summary: spacing = 12px, border-width = 6px
"""
class ImageSelectionDialog (CrumbsDialog):
__columns__ = [{
'col_name' : 'Image name',
'col_id' : 0,
'col_style': 'text',
'col_min' : 400,
'col_max' : 400
}, {
'col_name' : 'Select',
'col_id' : 1,
'col_style': 'radio toggle',
'col_min' : 160,
'col_max' : 160
}]
def __init__(self, image_folder, image_types, title, parent, flags, buttons=None, image_extension = {}):
super(ImageSelectionDialog, self).__init__(title, parent, flags, buttons)
self.connect("response", self.response_cb)
self.image_folder = image_folder
self.image_types = image_types
self.image_list = []
self.image_names = []
self.image_extension = image_extension
# create visual elements on the dialog
self.create_visual_elements()
self.image_store = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_BOOLEAN)
self.fill_image_store()
def create_visual_elements(self):
hbox = gtk.HBox(False, 6)
self.vbox.pack_start(hbox, expand=False, fill=False)
entry = gtk.Entry()
entry.set_text(self.image_folder)
table = gtk.Table(1, 10, True)
table.set_size_request(560, -1)
hbox.pack_start(table, expand=False, fill=False)
table.attach(entry, 0, 9, 0, 1)
image = gtk.Image()
image.set_from_stock(gtk.STOCK_OPEN, gtk.ICON_SIZE_BUTTON)
open_button = gtk.Button()
open_button.set_image(image)
open_button.connect("clicked", self.select_path_cb, self, entry)
table.attach(open_button, 9, 10, 0, 1)
self.image_table = HobViewTable(self.__columns__, "Images")
self.image_table.set_size_request(-1, 300)
self.image_table.connect("toggled", self.toggled_cb)
self.image_table.connect_group_selection(self.table_selected_cb)
self.image_table.connect("row-activated", self.row_actived_cb)
self.vbox.pack_start(self.image_table, expand=True, fill=True)
self.show_all()
def change_image_cb(self, model, path, columnid):
if not model:
return
iter = model.get_iter_first()
while iter:
rowpath = model.get_path(iter)
model[rowpath][columnid] = False
iter = model.iter_next(iter)
model[path][columnid] = True
def toggled_cb(self, table, cell, path, columnid, tree):
model = tree.get_model()
self.change_image_cb(model, path, columnid)
def table_selected_cb(self, selection):
model, paths = selection.get_selected_rows()
if paths:
self.change_image_cb(model, paths[0], 1)
def row_actived_cb(self, tab, model, path):
self.change_image_cb(model, path, 1)
self.emit('response', gtk.RESPONSE_YES)
def select_path_cb(self, action, parent, entry):
dialog = gtk.FileChooserDialog("", parent,
gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER)
text = entry.get_text()
dialog.set_current_folder(text if len(text) > 0 else os.getcwd())
button = dialog.add_button("Cancel", gtk.RESPONSE_NO)
HobAltButton.style_button(button)
button = dialog.add_button("Open", gtk.RESPONSE_YES)
HobButton.style_button(button)
response = dialog.run()
if response == gtk.RESPONSE_YES:
path = dialog.get_filename()
entry.set_text(path)
self.image_folder = path
self.fill_image_store()
dialog.destroy()
def fill_image_store(self):
self.image_list = []
self.image_store.clear()
imageset = set()
for root, dirs, files in os.walk(self.image_folder):
# ignore the sub directories
dirs[:] = []
for f in files:
for image_type in self.image_types:
if image_type in self.image_extension:
real_types = self.image_extension[image_type]
else:
real_types = [image_type]
for real_image_type in real_types:
if f.endswith('.' + real_image_type):
imageset.add(f.rsplit('.' + real_image_type)[0].rsplit('.rootfs')[0])
self.image_list.append(f)
for image in imageset:
self.image_store.set(self.image_store.append(), 0, image, 1, False)
self.image_table.set_model(self.image_store)
def response_cb(self, dialog, response_id):
self.image_names = []
if response_id == gtk.RESPONSE_YES:
iter = self.image_store.get_iter_first()
while iter:
path = self.image_store.get_path(iter)
if self.image_store[path][1]:
for f in self.image_list:
if f.startswith(self.image_store[path][0] + '.'):
self.image_names.append(f)
break
iter = self.image_store.iter_next(iter)

View File

@@ -1,296 +0,0 @@
#
# BitBake Graphical GTK User Interface
#
# Copyright (C) 2011-2012 Intel Corporation
#
# Authored by Joshua Lock <josh@linux.intel.com>
# Authored by Dongxiao Xu <dongxiao.xu@intel.com>
# Authored by Shane Wang <shane.wang@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
import os
import tempfile
from bb.ui.crumbs.hobwidget import hic, HobButton, HobAltButton
from bb.ui.crumbs.hig.crumbsdialog import CrumbsDialog
from bb.ui.crumbs.hig.crumbsmessagedialog import CrumbsMessageDialog
"""
The following are convenience classes for implementing GNOME HIG compliant
BitBake GUI's
In summary: spacing = 12px, border-width = 6px
"""
class CellRendererPixbufActivatable(gtk.CellRendererPixbuf):
"""
A custom CellRenderer implementation which is activatable
so that we can handle user clicks
"""
__gsignals__ = { 'clicked' : (gobject.SIGNAL_RUN_LAST,
gobject.TYPE_NONE,
(gobject.TYPE_STRING,)), }
def __init__(self):
gtk.CellRendererPixbuf.__init__(self)
self.set_property('mode', gtk.CELL_RENDERER_MODE_ACTIVATABLE)
self.set_property('follow-state', True)
"""
Respond to a user click on a cell
"""
def do_activate(self, even, widget, path, background_area, cell_area, flags):
self.emit('clicked', path)
#
# LayerSelectionDialog
#
class LayerSelectionDialog (CrumbsDialog):
TARGETS = [
("MY_TREE_MODEL_ROW", gtk.TARGET_SAME_WIDGET, 0),
("text/plain", 0, 1),
("TEXT", 0, 2),
("STRING", 0, 3),
]
def gen_label_widget(self, content):
label = gtk.Label()
label.set_alignment(0, 0)
label.set_markup(content)
label.show()
return label
def layer_widget_toggled_cb(self, cell, path, layer_store):
name = layer_store[path][0]
toggle = not layer_store[path][1]
layer_store[path][1] = toggle
def layer_widget_add_clicked_cb(self, action, layer_store, parent):
dialog = gtk.FileChooserDialog("Add new layer", parent,
gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER)
button = dialog.add_button("Cancel", gtk.RESPONSE_NO)
HobAltButton.style_button(button)
button = dialog.add_button("Open", gtk.RESPONSE_YES)
HobButton.style_button(button)
label = gtk.Label("Select the layer you wish to add")
label.show()
dialog.set_extra_widget(label)
response = dialog.run()
path = dialog.get_filename()
dialog.destroy()
lbl = "<b>Error</b>\nUnable to load layer <i>%s</i> because " % path
if response == gtk.RESPONSE_YES:
import os
import os.path
layers = []
it = layer_store.get_iter_first()
while it:
layers.append(layer_store.get_value(it, 0))
it = layer_store.iter_next(it)
if not path:
lbl += "it is an invalid path."
elif not os.path.exists(path+"/conf/layer.conf"):
lbl += "there is no layer.conf inside the directory."
elif path in layers:
lbl += "it is already in loaded layers."
else:
layer_store.append([path])
return
dialog = CrumbsMessageDialog(parent, lbl)
dialog.add_button(gtk.STOCK_CLOSE, gtk.RESPONSE_OK)
response = dialog.run()
dialog.destroy()
def layer_widget_del_clicked_cb(self, action, tree_selection, layer_store):
model, iter = tree_selection.get_selected()
if iter:
layer_store.remove(iter)
def gen_layer_widget(self, layers, layers_avail, window, tooltip=""):
hbox = gtk.HBox(False, 6)
layer_tv = gtk.TreeView()
layer_tv.set_rules_hint(True)
layer_tv.set_headers_visible(False)
tree_selection = layer_tv.get_selection()
tree_selection.set_mode(gtk.SELECTION_SINGLE)
# Allow enable drag and drop of rows including row move
layer_tv.enable_model_drag_source( gtk.gdk.BUTTON1_MASK,
self.TARGETS,
gtk.gdk.ACTION_DEFAULT|
gtk.gdk.ACTION_MOVE)
layer_tv.enable_model_drag_dest(self.TARGETS,
gtk.gdk.ACTION_DEFAULT)
layer_tv.connect("drag_data_get", self.drag_data_get_cb)
layer_tv.connect("drag_data_received", self.drag_data_received_cb)
col0= gtk.TreeViewColumn('Path')
cell0 = gtk.CellRendererText()
cell0.set_padding(5,2)
col0.pack_start(cell0, True)
col0.set_cell_data_func(cell0, self.draw_layer_path_cb)
layer_tv.append_column(col0)
scroll = gtk.ScrolledWindow()
scroll.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
scroll.set_shadow_type(gtk.SHADOW_IN)
scroll.add(layer_tv)
table_layer = gtk.Table(2, 10, False)
hbox.pack_start(table_layer, expand=True, fill=True)
table_layer.attach(scroll, 0, 10, 0, 1)
layer_store = gtk.ListStore(gobject.TYPE_STRING)
for layer in layers:
layer_store.append([layer])
col1 = gtk.TreeViewColumn('Enabled')
layer_tv.append_column(col1)
cell1 = CellRendererPixbufActivatable()
cell1.set_fixed_size(-1,35)
cell1.connect("clicked", self.del_cell_clicked_cb, layer_store)
col1.pack_start(cell1, True)
col1.set_cell_data_func(cell1, self.draw_delete_button_cb, layer_tv)
add_button = gtk.Button()
add_button.set_relief(gtk.RELIEF_NONE)
box = gtk.HBox(False, 6)
box.show()
add_button.add(box)
add_button.connect("enter-notify-event", self.add_hover_cb)
add_button.connect("leave-notify-event", self.add_leave_cb)
self.im = gtk.Image()
self.im.set_from_file(hic.ICON_INDI_ADD_FILE)
self.im.show()
box.pack_start(self.im, expand=False, fill=False, padding=6)
lbl = gtk.Label("Add layer")
lbl.set_alignment(0.0, 0.5)
lbl.show()
box.pack_start(lbl, expand=True, fill=True, padding=6)
add_button.connect("clicked", self.layer_widget_add_clicked_cb, layer_store, window)
table_layer.attach(add_button, 0, 10, 1, 2, gtk.EXPAND | gtk.FILL, 0, 0, 6)
layer_tv.set_model(layer_store)
hbox.show_all()
return hbox, layer_store
def drag_data_get_cb(self, treeview, context, selection, target_id, etime):
treeselection = treeview.get_selection()
model, iter = treeselection.get_selected()
data = model.get_value(iter, 0)
selection.set(selection.target, 8, data)
def drag_data_received_cb(self, treeview, context, x, y, selection, info, etime):
model = treeview.get_model()
data = selection.data
drop_info = treeview.get_dest_row_at_pos(x, y)
if drop_info:
path, position = drop_info
iter = model.get_iter(path)
if (position == gtk.TREE_VIEW_DROP_BEFORE or position == gtk.TREE_VIEW_DROP_INTO_OR_BEFORE):
model.insert_before(iter, [data])
else:
model.insert_after(iter, [data])
else:
model.append([data])
if context.action == gtk.gdk.ACTION_MOVE:
context.finish(True, True, etime)
return
def add_hover_cb(self, button, event):
self.im.set_from_file(hic.ICON_INDI_ADD_HOVER_FILE)
def add_leave_cb(self, button, event):
self.im.set_from_file(hic.ICON_INDI_ADD_FILE)
def __init__(self, title, layers, layers_non_removable, all_layers, parent, flags, buttons=None):
super(LayerSelectionDialog, self).__init__(title, parent, flags, buttons)
# class members from other objects
self.layers = layers
self.layers_non_removable = layers_non_removable
self.all_layers = all_layers
self.layers_changed = False
# icon for remove button in TreeView
im = gtk.Image()
im.set_from_file(hic.ICON_INDI_REMOVE_FILE)
self.rem_icon = im.get_pixbuf()
# class members for internal use
self.layer_store = None
# create visual elements on the dialog
self.create_visual_elements()
self.connect("response", self.response_cb)
def create_visual_elements(self):
layer_widget, self.layer_store = self.gen_layer_widget(self.layers, self.all_layers, self, None)
layer_widget.set_size_request(450, 250)
self.vbox.pack_start(layer_widget, expand=True, fill=True)
self.show_all()
def response_cb(self, dialog, response_id):
model = self.layer_store
it = model.get_iter_first()
layers = []
while it:
layers.append(model.get_value(it, 0))
it = model.iter_next(it)
self.layers_changed = (self.layers != layers)
self.layers = layers
"""
A custom cell_data_func to draw a delete 'button' in the TreeView for layers
other than the meta layer. The deletion of which is prevented so that the
user can't shoot themselves in the foot too badly.
"""
def draw_delete_button_cb(self, col, cell, model, it, tv):
path = model.get_value(it, 0)
if path in self.layers_non_removable:
cell.set_sensitive(False)
cell.set_property('pixbuf', None)
cell.set_property('mode', gtk.CELL_RENDERER_MODE_INERT)
else:
cell.set_property('pixbuf', self.rem_icon)
cell.set_sensitive(True)
cell.set_property('mode', gtk.CELL_RENDERER_MODE_ACTIVATABLE)
return True
"""
A custom cell_data_func to write an extra message into the layer path cell
for the meta layer. We should inform the user that they can't remove it for
their own safety.
"""
def draw_layer_path_cb(self, col, cell, model, it):
path = model.get_value(it, 0)
if path in self.layers_non_removable:
cell.set_property('markup', "<b>It cannot be removed</b>\n%s" % path)
else:
cell.set_property('text', path)
def del_cell_clicked_cb(self, cell, path, model):
it = model.get_iter_from_string(path)
model.remove(it)

View File

@@ -1,163 +0,0 @@
#
# BitBake Graphical GTK User Interface
#
# Copyright (C) 2011-2012 Intel Corporation
#
# Authored by Cristiana Voicu <cristiana.voicu@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
from bb.ui.crumbs.hobwidget import HobAltButton
from bb.ui.crumbs.hig.crumbsdialog import CrumbsDialog
"""
The following are convenience classes for implementing GNOME HIG compliant
BitBake GUI's
In summary: spacing = 12px, border-width = 6px
"""
#
# ParsingWarningsDialog
#
class ParsingWarningsDialog (CrumbsDialog):
def __init__(self, title, warnings, parent, flags, buttons=None):
super(ParsingWarningsDialog, self).__init__(title, parent, flags, buttons)
self.warnings = warnings
self.warning_on = 0
self.warn_nb = len(warnings)
# create visual elements on the dialog
self.create_visual_elements()
def cancel_button_cb(self, button):
self.destroy()
def previous_button_cb(self, button):
self.warning_on = self.warning_on - 1
self.refresh_components()
def next_button_cb(self, button):
self.warning_on = self.warning_on + 1
self.refresh_components()
def refresh_components(self):
lbl = self.warnings[self.warning_on]
#when the warning text has more than 400 chars, it uses a scroll bar
if 0<= len(lbl) < 400:
self.warning_label.set_size_request(320, 230)
self.warning_label.set_use_markup(True)
self.warning_label.set_line_wrap(True)
self.warning_label.set_markup(lbl)
self.warning_label.set_property("yalign", 0.00)
else:
self.textWindow.set_shadow_type(gtk.SHADOW_IN)
self.textWindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
self.msgView = gtk.TextView()
self.msgView.set_editable(False)
self.msgView.set_wrap_mode(gtk.WRAP_WORD)
self.msgView.set_cursor_visible(False)
self.msgView.set_size_request(320, 230)
self.buf = gtk.TextBuffer()
self.buf.set_text(lbl)
self.msgView.set_buffer(self.buf)
self.textWindow.add(self.msgView)
self.msgView.show()
if self.warning_on==0:
self.previous_button.set_sensitive(False)
else:
self.previous_button.set_sensitive(True)
if self.warning_on==self.warn_nb-1:
self.next_button.set_sensitive(False)
else:
self.next_button.set_sensitive(True)
if self.warn_nb>1:
self.heading = "Warning " + str(self.warning_on + 1) + " of " + str(self.warn_nb)
self.heading_label.set_markup('<span weight="bold">%s</span>' % self.heading)
else:
self.heading = "Warning"
self.heading_label.set_markup('<span weight="bold">%s</span>' % self.heading)
self.show_all()
if 0<= len(lbl) < 400:
self.textWindow.hide()
else:
self.warning_label.hide()
def create_visual_elements(self):
self.set_size_request(350, 350)
self.heading_label = gtk.Label()
self.heading_label.set_alignment(0, 0)
self.warning_label = gtk.Label()
self.warning_label.set_selectable(True)
self.warning_label.set_alignment(0, 0)
self.textWindow = gtk.ScrolledWindow()
table = gtk.Table(1, 10, False)
cancel_button = gtk.Button()
cancel_button.set_label("Close")
cancel_button.connect("clicked", self.cancel_button_cb)
cancel_button.set_size_request(110, 30)
self.previous_button = gtk.Button()
image1 = gtk.image_new_from_stock(gtk.STOCK_GO_BACK, gtk.ICON_SIZE_BUTTON)
image1.show()
box = gtk.HBox(False, 6)
box.show()
self.previous_button.add(box)
lbl = gtk.Label("Previous")
lbl.show()
box.pack_start(image1, expand=False, fill=False, padding=3)
box.pack_start(lbl, expand=True, fill=True, padding=3)
self.previous_button.connect("clicked", self.previous_button_cb)
self.previous_button.set_size_request(110, 30)
self.next_button = gtk.Button()
image2 = gtk.image_new_from_stock(gtk.STOCK_GO_FORWARD, gtk.ICON_SIZE_BUTTON)
image2.show()
box = gtk.HBox(False, 6)
box.show()
self.next_button.add(box)
lbl = gtk.Label("Next")
lbl.show()
box.pack_start(lbl, expand=True, fill=True, padding=3)
box.pack_start(image2, expand=False, fill=False, padding=3)
self.next_button.connect("clicked", self.next_button_cb)
self.next_button.set_size_request(110, 30)
#when there more than one warning, we need "previous" and "next" button
if self.warn_nb>1:
self.vbox.pack_start(self.heading_label, expand=False, fill=False)
self.vbox.pack_start(self.warning_label, expand=False, fill=False)
self.vbox.pack_start(self.textWindow, expand=False, fill=False)
table.attach(cancel_button, 6, 7, 0, 1, xoptions=gtk.SHRINK)
table.attach(self.previous_button, 7, 8, 0, 1, xoptions=gtk.SHRINK)
table.attach(self.next_button, 8, 9, 0, 1, xoptions=gtk.SHRINK)
self.vbox.pack_end(table, expand=False, fill=False)
else:
self.vbox.pack_start(self.heading_label, expand=False, fill=False)
self.vbox.pack_start(self.warning_label, expand=False, fill=False)
self.vbox.pack_start(self.textWindow, expand=False, fill=False)
cancel_button = self.add_button("Close", gtk.RESPONSE_CANCEL)
HobAltButton.style_button(cancel_button)
self.refresh_components()

View File

@@ -1,438 +0,0 @@
#
# BitBake Graphical GTK User Interface
#
# Copyright (C) 2011-2013 Intel Corporation
#
# Authored by Andrei Dinu <andrei.adrianx.dinu@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 string
import gtk
import gobject
import os
import tempfile
import glib
from bb.ui.crumbs.hig.crumbsdialog import CrumbsDialog
from bb.ui.crumbs.hig.settingsuihelper import SettingsUIHelper
from bb.ui.crumbs.hig.crumbsmessagedialog import CrumbsMessageDialog
from bb.ui.crumbs.hig.layerselectiondialog import LayerSelectionDialog
"""
The following are convenience classes for implementing GNOME HIG compliant
BitBake GUI's
In summary: spacing = 12px, border-width = 6px
"""
class PropertyDialog(CrumbsDialog):
def __init__(self, title, parent, information, flags, buttons=None):
super(PropertyDialog, self).__init__(title, parent, flags, buttons)
self.properties = information
if len(self.properties) == 10:
self.create_recipe_visual_elements()
elif len(self.properties) == 5:
self.create_package_visual_elements()
else:
self.create_information_visual_elements()
def create_information_visual_elements(self):
HOB_ICON_BASE_DIR = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), ("icons/"))
ICON_PACKAGES_DISPLAY_FILE = os.path.join(HOB_ICON_BASE_DIR, ('info/info_display.png'))
self.set_resizable(False)
self.table = gtk.Table(1,1,False)
self.table.set_row_spacings(0)
self.table.set_col_spacings(0)
self.image = gtk.Image()
self.image.set_from_file(ICON_PACKAGES_DISPLAY_FILE)
self.image.set_property("xalign",0)
#self.vbox.add(self.image)
image_info = self.properties.split("*")[0]
info = self.properties.split("*")[1]
vbox = gtk.VBox(True, spacing=30)
self.label_short = gtk.Label()
self.label_short.set_line_wrap(False)
self.label_short.set_markup(image_info)
self.label_short.set_property("xalign", 0)
self.info_label = gtk.Label()
self.info_label.set_line_wrap(True)
self.info_label.set_markup(info)
self.info_label.set_property("yalign", 0.5)
self.table.attach(self.image, 0,1,0,1, xoptions=gtk.FILL|gtk.EXPAND, yoptions=gtk.FILL,xpadding=5,ypadding=5)
self.table.attach(self.label_short, 0,1,0,1, xoptions=gtk.FILL|gtk.EXPAND, yoptions=gtk.FILL,xpadding=40,ypadding=5)
self.table.attach(self.info_label, 0,1,1,2, xoptions=gtk.FILL|gtk.EXPAND, yoptions=gtk.FILL,xpadding=40,ypadding=10)
self.vbox.add(self.table)
self.connect('delete-event', lambda w, e: self.destroy() or True)
def treeViewTooltip( self, widget, e, tooltips, cell, emptyText="" ):
try:
(path,col,x,y) = widget.get_path_at_pos( int(e.x), int(e.y) )
it = widget.get_model().get_iter(path)
value = widget.get_model().get_value(it,cell)
if value in self.tooltip_items:
tooltips.set_tip(widget, self.tooltip_items[value])
tooltips.enable()
else:
tooltips.set_tip(widget, emptyText)
except:
tooltips.set_tip(widget, emptyText)
def create_package_visual_elements(self):
name = self.properties['name']
binb = self.properties['binb']
size = self.properties['size']
recipe = self.properties['recipe']
file_list = self.properties['files_list']
file_list = file_list.strip("{}'")
files_temp = ''
paths_temp = ''
files_binb = []
paths_binb = []
self.tooltip_items = {}
self.set_resizable(False)
#cleaning out the recipe variable
recipe = recipe.split("+")[0]
vbox = gtk.VBox(True,spacing = 0)
###################################### NAME ROW + COL #################################
self.label_short = gtk.Label()
self.label_short.set_size_request(300,-1)
self.label_short.set_selectable(True)
self.label_short.set_line_wrap(True)
self.label_short.set_markup("<span weight=\"bold\">Name: </span>" + name)
self.label_short.set_property("xalign", 0)
self.vbox.add(self.label_short)
###################################### SIZE ROW + COL ######################################
self.label_short = gtk.Label()
self.label_short.set_size_request(300,-1)
self.label_short.set_selectable(True)
self.label_short.set_line_wrap(True)
self.label_short.set_markup("<span weight=\"bold\">Size: </span>" + size)
self.label_short.set_property("xalign", 0)
self.vbox.add(self.label_short)
##################################### RECIPE ROW + COL #########################################
self.label_short = gtk.Label()
self.label_short.set_size_request(300,-1)
self.label_short.set_selectable(True)
self.label_short.set_line_wrap(True)
self.label_short.set_markup("<span weight=\"bold\">Recipe: </span>" + recipe)
self.label_short.set_property("xalign", 0)
self.vbox.add(self.label_short)
##################################### BINB ROW + COL #######################################
if binb != '':
self.label_short = gtk.Label()
self.label_short.set_selectable(True)
self.label_short.set_line_wrap(True)
self.label_short.set_markup("<span weight=\"bold\">Brought in by: </span>")
self.label_short.set_property("xalign", 0)
self.label_info = gtk.Label()
self.label_info.set_size_request(300,-1)
self.label_info.set_selectable(True)
self.label_info.set_line_wrap(True)
self.label_info.set_markup(binb)
self.label_info.set_property("xalign", 0)
self.vbox.add(self.label_short)
self.vbox.add(self.label_info)
#################################### FILES BROUGHT BY PACKAGES ###################################
if file_list != '':
self.textWindow = gtk.ScrolledWindow()
self.textWindow.set_shadow_type(gtk.SHADOW_IN)
self.textWindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
self.textWindow.set_size_request(100, 170)
sstatemirrors_store = gtk.ListStore(str)
self.sstatemirrors_tv = gtk.TreeView()
self.sstatemirrors_tv.set_rules_hint(True)
self.sstatemirrors_tv.set_headers_visible(True)
self.textWindow.add(self.sstatemirrors_tv)
self.cell1 = gtk.CellRendererText()
col1 = gtk.TreeViewColumn('Package files', self.cell1)
col1.set_cell_data_func(self.cell1, self.regex_field)
self.sstatemirrors_tv.append_column(col1)
for items in file_list.split(']'):
if len(items) > 1:
paths_temp = items.split(":")[0]
paths_binb.append(paths_temp.strip(" ,'"))
files_temp = items.split(":")[1]
files_binb.append(files_temp.strip(" ['"))
unsorted_list = []
for items in range(len(paths_binb)):
if len(files_binb[items]) > 1:
for aduse in (files_binb[items].split(",")):
unsorted_list.append(paths_binb[items].split(name)[len(paths_binb[items].split(name))-1] + '/' + aduse.strip(" '"))
unsorted_list.sort()
for items in unsorted_list:
temp = items
while len(items) > 35:
items = items[:len(items)/2] + "" + items[len(items)/2+1:]
if len(items) == 35:
items = items[:len(items)/2] + "..." + items[len(items)/2+3:]
self.tooltip_items[items] = temp
sstatemirrors_store.append([str(items)])
self.sstatemirrors_tv.set_model(sstatemirrors_store)
tips = gtk.Tooltips()
tips.set_tip(self.sstatemirrors_tv, "")
self.sstatemirrors_tv.connect("motion-notify-event", self.treeViewTooltip, tips, 0)
self.sstatemirrors_tv.set_events(gtk.gdk.POINTER_MOTION_MASK)
self.vbox.add(self.textWindow)
self.vbox.show_all()
def regex_field(self, column, cell, model, iter):
cell.set_property('text', model.get_value(iter, 0))
return
def create_recipe_visual_elements(self):
summary = self.properties['summary']
name = self.properties['name']
version = self.properties['version']
revision = self.properties['revision']
binb = self.properties['binb']
group = self.properties['group']
license = self.properties['license']
homepage = self.properties['homepage']
bugtracker = self.properties['bugtracker']
description = self.properties['description']
self.set_resizable(False)
#cleaning out the version variable and also the summary
version = version.split(":")[1]
if len(version) > 30:
version = version.split("+")[0]
else:
version = version.split("-")[0]
license = license.replace("&" , "and")
if (homepage == ''):
homepage = 'unknown'
if (bugtracker == ''):
bugtracker = 'unknown'
summary = summary.split("+")[0]
#calculating the rows needed for the table
binb_items_count = len(binb.split(','))
binb_items = binb.split(',')
vbox = gtk.VBox(True,spacing = 0)
######################################## SUMMARY LABEL #########################################
if summary != '':
self.label_short = gtk.Label()
self.label_short.set_size_request(300,-1)
self.label_short.set_selectable(True)
self.label_short.set_line_wrap(True)
self.label_short.set_markup("<b>" + summary + "</b>")
self.label_short.set_property("xalign", 0)
self.vbox.pack_start(self.label_short, expand=False, fill=False, padding=0)
########################################## NAME ROW + COL #######################################
self.label_short = gtk.Label()
self.label_short.set_size_request(300,-1)
self.label_short.set_selectable(True)
self.label_short.set_line_wrap(True)
self.label_short.set_markup("<span weight=\"bold\">Name: </span>" + name)
self.label_short.set_property("xalign", 0)
self.vbox.add(self.label_short)
####################################### VERSION ROW + COL ####################################
self.label_short = gtk.Label()
self.label_short.set_size_request(300,-1)
self.label_short.set_selectable(True)
self.label_short.set_line_wrap(True)
self.label_short.set_markup("<span weight=\"bold\">Version: </span>" + version)
self.label_short.set_property("xalign", 0)
self.vbox.add(self.label_short)
##################################### REVISION ROW + COL #####################################
self.label_short = gtk.Label()
self.label_short.set_size_request(300,-1)
self.label_short.set_line_wrap(True)
self.label_short.set_selectable(True)
self.label_short.set_markup("<span weight=\"bold\">Revision: </span>" + revision)
self.label_short.set_property("xalign", 0)
self.vbox.add(self.label_short)
################################## GROUP ROW + COL ############################################
self.label_short = gtk.Label()
self.label_short.set_size_request(300,-1)
self.label_short.set_selectable(True)
self.label_short.set_line_wrap(True)
self.label_short.set_markup("<span weight=\"bold\">Group: </span>" + group)
self.label_short.set_property("xalign", 0)
self.vbox.add(self.label_short)
################################# HOMEPAGE ROW + COL ############################################
if homepage != 'unknown':
self.label_info = gtk.Label()
self.label_info.set_selectable(True)
self.label_info.set_line_wrap(True)
if len(homepage) > 35:
self.label_info.set_markup("<a href=\"" + homepage + "\">" + homepage[0:35] + "..." + "</a>")
else:
self.label_info.set_markup("<a href=\"" + homepage + "\">" + homepage[0:60] + "</a>")
self.label_info.set_property("xalign", 0)
self.label_short = gtk.Label()
self.label_short.set_size_request(300,-1)
self.label_short.set_selectable(True)
self.label_short.set_line_wrap(True)
self.label_short.set_markup("<b>Homepage: </b>")
self.label_short.set_property("xalign", 0)
self.vbox.add(self.label_short)
self.vbox.add(self.label_info)
################################# BUGTRACKER ROW + COL ###########################################
if bugtracker != 'unknown':
self.label_info = gtk.Label()
self.label_info.set_selectable(True)
self.label_info.set_line_wrap(True)
if len(bugtracker) > 35:
self.label_info.set_markup("<a href=\"" + bugtracker + "\">" + bugtracker[0:35] + "..." + "</a>")
else:
self.label_info.set_markup("<a href=\"" + bugtracker + "\">" + bugtracker[0:60] + "</a>")
self.label_info.set_property("xalign", 0)
self.label_short = gtk.Label()
self.label_short.set_size_request(300,-1)
self.label_short.set_selectable(True)
self.label_short.set_line_wrap(True)
self.label_short.set_markup("<b>Bugtracker: </b>")
self.label_short.set_property("xalign", 0)
self.vbox.add(self.label_short)
self.vbox.add(self.label_info)
################################# LICENSE ROW + COL ############################################
self.label_info = gtk.Label()
self.label_info.set_size_request(300,-1)
self.label_info.set_selectable(True)
self.label_info.set_line_wrap(True)
self.label_info.set_markup(license)
self.label_info.set_property("xalign", 0)
self.label_short = gtk.Label()
self.label_short.set_selectable(True)
self.label_short.set_line_wrap(True)
self.label_short.set_markup("<span weight=\"bold\">License: </span>")
self.label_short.set_property("xalign", 0)
self.vbox.add(self.label_short)
self.vbox.add(self.label_info)
################################### BINB ROW+COL #############################################
if binb != '':
self.label_short = gtk.Label()
self.label_short.set_selectable(True)
self.label_short.set_line_wrap(True)
self.label_short.set_markup("<span weight=\"bold\">Brought in by: </span>")
self.label_short.set_property("xalign", 0)
self.label_info = gtk.Label()
self.label_info.set_size_request(300,-1)
self.label_info.set_selectable(True)
self.label_info.set_markup(binb)
self.label_info.set_property("xalign", 0)
self.label_info.set_line_wrap(True)
self.vbox.add(self.label_short)
self.vbox.add(self.label_info)
################################ DESCRIPTION TAG ROW #################################################
self.label_short = gtk.Label()
self.label_short.set_line_wrap(True)
self.label_short.set_markup("<span weight=\"bold\">Description </span>")
self.label_short.set_property("xalign", 0)
self.vbox.add(self.label_short)
################################ DESCRIPTION INFORMATION ROW ##########################################
hbox = gtk.HBox(True,spacing = 0)
self.label_short = gtk.Label()
self.label_short.set_size_request(300,-1)
self.label_short.set_selectable(True)
self.label_short.set_text(description)
self.label_short.set_line_wrap(True)
self.label_short.set_property("xalign", 0)
self.vbox.add(self.label_short)
self.vbox.show_all()

View File

@@ -1,90 +0,0 @@
#
# BitBake Graphical GTK User Interface
#
# Copyright (C) 2011-2012 Intel Corporation
#
# Authored by Joshua Lock <josh@linux.intel.com>
# Authored by Dongxiao Xu <dongxiao.xu@intel.com>
# Authored by Shane Wang <shane.wang@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
from bb.ui.crumbs.hig.crumbsdialog import CrumbsDialog
"""
The following are convenience classes for implementing GNOME HIG compliant
BitBake GUI's
In summary: spacing = 12px, border-width = 6px
"""
class ProxyDetailsDialog (CrumbsDialog):
def __init__(self, title, user, passwd, parent, flags, buttons=None):
super(ProxyDetailsDialog, self).__init__(title, parent, flags, buttons)
self.connect("response", self.response_cb)
self.auth = not (user == None or passwd == None or user == "")
self.user = user or ""
self.passwd = passwd or ""
# create visual elements on the dialog
self.create_visual_elements()
def create_visual_elements(self):
self.auth_checkbox = gtk.CheckButton("Use authentication")
self.auth_checkbox.set_tooltip_text("Check this box to set the username and the password")
self.auth_checkbox.set_active(self.auth)
self.auth_checkbox.connect("toggled", self.auth_checkbox_toggled_cb)
self.vbox.pack_start(self.auth_checkbox, expand=False, fill=False)
hbox = gtk.HBox(False, 6)
self.user_label = gtk.Label("Username:")
self.user_text = gtk.Entry()
self.user_text.set_text(self.user)
hbox.pack_start(self.user_label, expand=False, fill=False)
hbox.pack_end(self.user_text, expand=False, fill=False)
self.vbox.pack_start(hbox, expand=False, fill=False)
hbox = gtk.HBox(False, 6)
self.passwd_label = gtk.Label("Password:")
self.passwd_text = gtk.Entry()
self.passwd_text.set_text(self.passwd)
hbox.pack_start(self.passwd_label, expand=False, fill=False)
hbox.pack_end(self.passwd_text, expand=False, fill=False)
self.vbox.pack_start(hbox, expand=False, fill=False)
self.refresh_auth_components()
self.show_all()
def refresh_auth_components(self):
self.user_label.set_sensitive(self.auth)
self.user_text.set_editable(self.auth)
self.user_text.set_sensitive(self.auth)
self.passwd_label.set_sensitive(self.auth)
self.passwd_text.set_editable(self.auth)
self.passwd_text.set_sensitive(self.auth)
def auth_checkbox_toggled_cb(self, button):
self.auth = self.auth_checkbox.get_active()
self.refresh_auth_components()
def response_cb(self, dialog, response_id):
if response_id == gtk.RESPONSE_OK:
if self.auth:
self.user = self.user_text.get_text()
self.passwd = self.passwd_text.get_text()
else:
self.user = None
self.passwd = None

View File

@@ -1,122 +0,0 @@
#
# BitBake Graphical GTK User Interface
#
# Copyright (C) 2011-2012 Intel Corporation
#
# Authored by Joshua Lock <josh@linux.intel.com>
# Authored by Dongxiao Xu <dongxiao.xu@intel.com>
# Authored by Shane Wang <shane.wang@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 os
from bb.ui.crumbs.hobwidget import HobInfoButton, HobButton, HobAltButton
"""
The following are convenience classes for implementing GNOME HIG compliant
BitBake GUI's
In summary: spacing = 12px, border-width = 6px
"""
class SettingsUIHelper():
def gen_label_widget(self, content):
label = gtk.Label()
label.set_alignment(0, 0)
label.set_markup(content)
label.show()
return label
def gen_label_info_widget(self, content, tooltip):
table = gtk.Table(1, 10, False)
label = self.gen_label_widget(content)
info = HobInfoButton(tooltip, self)
table.attach(label, 0, 1, 0, 1, xoptions=gtk.FILL)
table.attach(info, 1, 2, 0, 1, xoptions=gtk.FILL, xpadding=10)
return table
def gen_spinner_widget(self, content, lower, upper, tooltip=""):
hbox = gtk.HBox(False, 12)
adjust = gtk.Adjustment(value=content, lower=lower, upper=upper, step_incr=1)
spinner = gtk.SpinButton(adjustment=adjust, climb_rate=1, digits=0)
spinner.set_value(content)
hbox.pack_start(spinner, expand=False, fill=False)
info = HobInfoButton(tooltip, self)
hbox.pack_start(info, expand=False, fill=False)
hbox.show_all()
return hbox, spinner
def gen_combo_widget(self, curr_item, all_item, tooltip=""):
hbox = gtk.HBox(False, 12)
combo = gtk.combo_box_new_text()
hbox.pack_start(combo, expand=False, fill=False)
index = 0
for item in all_item or []:
combo.append_text(item)
if item == curr_item:
combo.set_active(index)
index += 1
info = HobInfoButton(tooltip, self)
hbox.pack_start(info, expand=False, fill=False)
hbox.show_all()
return hbox, combo
def entry_widget_select_path_cb(self, action, parent, entry):
dialog = gtk.FileChooserDialog("", parent,
gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER)
text = entry.get_text()
dialog.set_current_folder(text if len(text) > 0 else os.getcwd())
button = dialog.add_button("Cancel", gtk.RESPONSE_NO)
HobAltButton.style_button(button)
button = dialog.add_button("Open", gtk.RESPONSE_YES)
HobButton.style_button(button)
response = dialog.run()
if response == gtk.RESPONSE_YES:
path = dialog.get_filename()
entry.set_text(path)
dialog.destroy()
def gen_entry_widget(self, content, parent, tooltip="", need_button=True):
hbox = gtk.HBox(False, 12)
entry = gtk.Entry()
entry.set_text(content)
entry.set_size_request(350,30)
if need_button:
table = gtk.Table(1, 10, False)
hbox.pack_start(table, expand=True, fill=True)
table.attach(entry, 0, 9, 0, 1, xoptions=gtk.SHRINK)
image = gtk.Image()
image.set_from_stock(gtk.STOCK_OPEN,gtk.ICON_SIZE_BUTTON)
open_button = gtk.Button()
open_button.set_image(image)
open_button.connect("clicked", self.entry_widget_select_path_cb, parent, entry)
table.attach(open_button, 9, 10, 0, 1, xoptions=gtk.SHRINK)
else:
hbox.pack_start(entry, expand=True, fill=True)
if tooltip != "":
info = HobInfoButton(tooltip, self)
hbox.pack_start(info, expand=False, fill=False)
hbox.show_all()
return hbox, entry

View File

@@ -1,900 +0,0 @@
#
# BitBake Graphical GTK User Interface
#
# Copyright (C) 2011-2012 Intel Corporation
#
# Authored by Joshua Lock <josh@linux.intel.com>
# Authored by Dongxiao Xu <dongxiao.xu@intel.com>
# Authored by Shane Wang <shane.wang@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
import hashlib
from bb.ui.crumbs.hobwidget import hic, HobInfoButton, HobButton, HobAltButton
from bb.ui.crumbs.progressbar import HobProgressBar
from bb.ui.crumbs.hig.settingsuihelper import SettingsUIHelper
from bb.ui.crumbs.hig.crumbsdialog import CrumbsDialog
from bb.ui.crumbs.hig.crumbsmessagedialog import CrumbsMessageDialog
from bb.ui.crumbs.hig.proxydetailsdialog import ProxyDetailsDialog
"""
The following are convenience classes for implementing GNOME HIG compliant
BitBake GUI's
In summary: spacing = 12px, border-width = 6px
"""
class SimpleSettingsDialog (CrumbsDialog, SettingsUIHelper):
(BUILD_ENV_PAGE_ID,
SHARED_STATE_PAGE_ID,
PROXIES_PAGE_ID,
OTHERS_PAGE_ID) = range(4)
(TEST_NETWORK_NONE,
TEST_NETWORK_INITIAL,
TEST_NETWORK_RUNNING,
TEST_NETWORK_PASSED,
TEST_NETWORK_FAILED,
TEST_NETWORK_CANCELED) = range(6)
TARGETS = [
("MY_TREE_MODEL_ROW", gtk.TARGET_SAME_WIDGET, 0),
("text/plain", 0, 1),
("TEXT", 0, 2),
("STRING", 0, 3),
]
def __init__(self, title, configuration, all_image_types,
all_package_formats, all_distros, all_sdk_machines,
max_threads, parent, flags, handler, buttons=None):
super(SimpleSettingsDialog, self).__init__(title, parent, flags, buttons)
# class members from other objects
# bitbake settings from Builder.Configuration
self.configuration = configuration
self.image_types = all_image_types
self.all_package_formats = all_package_formats
self.all_distros = all_distros
self.all_sdk_machines = all_sdk_machines
self.max_threads = max_threads
# class members for internal use
self.dldir_text = None
self.sstatedir_text = None
self.sstatemirrors_list = []
self.sstatemirrors_changed = 0
self.bb_spinner = None
self.pmake_spinner = None
self.rootfs_size_spinner = None
self.extra_size_spinner = None
self.gplv3_checkbox = None
self.toolchain_checkbox = None
self.setting_store = None
self.image_types_checkbuttons = {}
self.md5 = self.config_md5()
self.proxy_md5 = self.config_proxy_md5()
self.settings_changed = False
self.proxy_settings_changed = False
self.handler = handler
self.proxy_test_ran = False
self.selected_mirror_row = 0
self.new_mirror = False
# create visual elements on the dialog
self.create_visual_elements()
self.connect("response", self.response_cb)
def _get_sorted_value(self, var):
return " ".join(sorted(str(var).split())) + "\n"
def config_proxy_md5(self):
data = ("ENABLE_PROXY: " + self._get_sorted_value(self.configuration.enable_proxy))
if self.configuration.enable_proxy:
for protocol in self.configuration.proxies.keys():
data += (protocol + ": " + self._get_sorted_value(self.configuration.combine_proxy(protocol)))
return hashlib.md5(data).hexdigest()
def config_md5(self):
data = ""
for key in self.configuration.extra_setting.keys():
data += (key + ": " + self._get_sorted_value(self.configuration.extra_setting[key]))
return hashlib.md5(data).hexdigest()
def gen_proxy_entry_widget(self, protocol, parent, need_button=True, line=0):
label = gtk.Label(protocol.upper() + " proxy")
self.proxy_table.attach(label, 0, 1, line, line+1, xpadding=24)
proxy_entry = gtk.Entry()
proxy_entry.set_size_request(300, -1)
self.proxy_table.attach(proxy_entry, 1, 2, line, line+1, ypadding=4)
self.proxy_table.attach(gtk.Label(":"), 2, 3, line, line+1, xpadding=12, ypadding=4)
port_entry = gtk.Entry()
port_entry.set_size_request(60, -1)
self.proxy_table.attach(port_entry, 3, 4, line, line+1, ypadding=4)
details_button = HobAltButton("Details")
details_button.connect("clicked", self.details_cb, parent, protocol)
self.proxy_table.attach(details_button, 4, 5, line, line+1, xpadding=4, yoptions=gtk.EXPAND)
return proxy_entry, port_entry, details_button
def refresh_proxy_components(self):
self.same_checkbox.set_sensitive(self.configuration.enable_proxy)
self.http_proxy.set_text(self.configuration.combine_host_only("http"))
self.http_proxy.set_editable(self.configuration.enable_proxy)
self.http_proxy.set_sensitive(self.configuration.enable_proxy)
self.http_proxy_port.set_text(self.configuration.combine_port_only("http"))
self.http_proxy_port.set_editable(self.configuration.enable_proxy)
self.http_proxy_port.set_sensitive(self.configuration.enable_proxy)
self.http_proxy_details.set_sensitive(self.configuration.enable_proxy)
self.https_proxy.set_text(self.configuration.combine_host_only("https"))
self.https_proxy.set_editable(self.configuration.enable_proxy and (not self.configuration.same_proxy))
self.https_proxy.set_sensitive(self.configuration.enable_proxy and (not self.configuration.same_proxy))
self.https_proxy_port.set_text(self.configuration.combine_port_only("https"))
self.https_proxy_port.set_editable(self.configuration.enable_proxy and (not self.configuration.same_proxy))
self.https_proxy_port.set_sensitive(self.configuration.enable_proxy and (not self.configuration.same_proxy))
self.https_proxy_details.set_sensitive(self.configuration.enable_proxy and (not self.configuration.same_proxy))
self.ftp_proxy.set_text(self.configuration.combine_host_only("ftp"))
self.ftp_proxy.set_editable(self.configuration.enable_proxy and (not self.configuration.same_proxy))
self.ftp_proxy.set_sensitive(self.configuration.enable_proxy and (not self.configuration.same_proxy))
self.ftp_proxy_port.set_text(self.configuration.combine_port_only("ftp"))
self.ftp_proxy_port.set_editable(self.configuration.enable_proxy and (not self.configuration.same_proxy))
self.ftp_proxy_port.set_sensitive(self.configuration.enable_proxy and (not self.configuration.same_proxy))
self.ftp_proxy_details.set_sensitive(self.configuration.enable_proxy and (not self.configuration.same_proxy))
self.socks_proxy.set_text(self.configuration.combine_host_only("socks"))
self.socks_proxy.set_editable(self.configuration.enable_proxy and (not self.configuration.same_proxy))
self.socks_proxy.set_sensitive(self.configuration.enable_proxy and (not self.configuration.same_proxy))
self.socks_proxy_port.set_text(self.configuration.combine_port_only("socks"))
self.socks_proxy_port.set_editable(self.configuration.enable_proxy and (not self.configuration.same_proxy))
self.socks_proxy_port.set_sensitive(self.configuration.enable_proxy and (not self.configuration.same_proxy))
self.socks_proxy_details.set_sensitive(self.configuration.enable_proxy and (not self.configuration.same_proxy))
self.cvs_proxy.set_text(self.configuration.combine_host_only("cvs"))
self.cvs_proxy.set_editable(self.configuration.enable_proxy and (not self.configuration.same_proxy))
self.cvs_proxy.set_sensitive(self.configuration.enable_proxy and (not self.configuration.same_proxy))
self.cvs_proxy_port.set_text(self.configuration.combine_port_only("cvs"))
self.cvs_proxy_port.set_editable(self.configuration.enable_proxy and (not self.configuration.same_proxy))
self.cvs_proxy_port.set_sensitive(self.configuration.enable_proxy and (not self.configuration.same_proxy))
self.cvs_proxy_details.set_sensitive(self.configuration.enable_proxy and (not self.configuration.same_proxy))
if self.configuration.same_proxy:
if self.http_proxy.get_text():
[w.set_text(self.http_proxy.get_text()) for w in self.same_proxy_addresses]
if self.http_proxy_port.get_text():
[w.set_text(self.http_proxy_port.get_text()) for w in self.same_proxy_ports]
def proxy_checkbox_toggled_cb(self, button):
self.configuration.enable_proxy = self.proxy_checkbox.get_active()
if not self.configuration.enable_proxy:
self.configuration.same_proxy = False
self.same_checkbox.set_active(self.configuration.same_proxy)
self.save_proxy_data()
self.refresh_proxy_components()
def same_checkbox_toggled_cb(self, button):
self.configuration.same_proxy = self.same_checkbox.get_active()
self.save_proxy_data()
self.refresh_proxy_components()
def save_proxy_data(self):
self.configuration.split_proxy("http", self.http_proxy.get_text() + ":" + self.http_proxy_port.get_text())
if self.configuration.same_proxy:
self.configuration.split_proxy("https", self.http_proxy.get_text() + ":" + self.http_proxy_port.get_text())
self.configuration.split_proxy("ftp", self.http_proxy.get_text() + ":" + self.http_proxy_port.get_text())
self.configuration.split_proxy("socks", self.http_proxy.get_text() + ":" + self.http_proxy_port.get_text())
self.configuration.split_proxy("cvs", self.http_proxy.get_text() + ":" + self.http_proxy_port.get_text())
else:
self.configuration.split_proxy("https", self.https_proxy.get_text() + ":" + self.https_proxy_port.get_text())
self.configuration.split_proxy("ftp", self.ftp_proxy.get_text() + ":" + self.ftp_proxy_port.get_text())
self.configuration.split_proxy("socks", self.socks_proxy.get_text() + ":" + self.socks_proxy_port.get_text())
self.configuration.split_proxy("cvs", self.cvs_proxy.get_text() + ":" + self.cvs_proxy_port.get_text())
def response_cb(self, dialog, response_id):
if response_id == gtk.RESPONSE_YES:
# Check that all proxy entries have a corresponding port
for proxy, port in zip(self.all_proxy_addresses, self.all_proxy_ports):
if proxy.get_text() and not port.get_text():
lbl = "<b>Enter all port numbers</b>\n\n"
msg = "Proxy servers require a port number. Please make sure you have entered a port number for each proxy server."
dialog = CrumbsMessageDialog(self, lbl, gtk.STOCK_DIALOG_WARNING, msg)
button = dialog.add_button("Close", gtk.RESPONSE_OK)
HobButton.style_button(button)
response = dialog.run()
dialog.destroy()
self.emit_stop_by_name("response")
return
self.configuration.dldir = self.dldir_text.get_text()
self.configuration.sstatedir = self.sstatedir_text.get_text()
self.configuration.sstatemirror = ""
for mirror in self.sstatemirrors_list:
if mirror[1] != "" and mirror[2].startswith("file://"):
if mirror[1].endswith("\\1"):
smirror = mirror[2] + " " + mirror[1] + " \\n "
else:
smirror = mirror[2] + " " + mirror[1] + "\\1 \\n "
self.configuration.sstatemirror += smirror
self.configuration.bbthread = self.bb_spinner.get_value_as_int()
self.configuration.pmake = self.pmake_spinner.get_value_as_int()
self.save_proxy_data()
self.configuration.extra_setting = {}
it = self.setting_store.get_iter_first()
while it:
key = self.setting_store.get_value(it, 0)
value = self.setting_store.get_value(it, 1)
self.configuration.extra_setting[key] = value
it = self.setting_store.iter_next(it)
md5 = self.config_md5()
self.settings_changed = (self.md5 != md5)
self.proxy_settings_changed = (self.proxy_md5 != self.config_proxy_md5())
def create_build_environment_page(self):
advanced_vbox = gtk.VBox(False, 6)
advanced_vbox.set_border_width(6)
advanced_vbox.pack_start(self.gen_label_widget('<span weight="bold">Parallel threads</span>'), expand=False, fill=False)
sub_vbox = gtk.VBox(False, 6)
advanced_vbox.pack_start(sub_vbox, expand=False, fill=False)
label = self.gen_label_widget("BitBake parallel threads")
tooltip = "Sets the number of threads that BitBake tasks can simultaneously run. See the <a href=\""
tooltip += "http://www.yoctoproject.org/docs/current/poky-ref-manual/"
tooltip += "poky-ref-manual.html#var-BB_NUMBER_THREADS\">Poky reference manual</a> for information"
bbthread_widget, self.bb_spinner = self.gen_spinner_widget(self.configuration.bbthread, 1, self.max_threads,"<b>BitBake prallalel threads</b>" + "*" + tooltip)
sub_vbox.pack_start(label, expand=False, fill=False)
sub_vbox.pack_start(bbthread_widget, expand=False, fill=False)
sub_vbox = gtk.VBox(False, 6)
advanced_vbox.pack_start(sub_vbox, expand=False, fill=False)
label = self.gen_label_widget("Make parallel threads")
tooltip = "Sets the maximum number of threads the host can use during the build. See the <a href=\""
tooltip += "http://www.yoctoproject.org/docs/current/poky-ref-manual/"
tooltip += "poky-ref-manual.html#var-PARALLEL_MAKE\">Poky reference manual</a> for information"
pmake_widget, self.pmake_spinner = self.gen_spinner_widget(self.configuration.pmake, 1, self.max_threads,"<b>Make parallel threads</b>" + "*" + tooltip)
sub_vbox.pack_start(label, expand=False, fill=False)
sub_vbox.pack_start(pmake_widget, expand=False, fill=False)
advanced_vbox.pack_start(self.gen_label_widget('<span weight="bold">Downloaded source code</span>'), expand=False, fill=False)
sub_vbox = gtk.VBox(False, 6)
advanced_vbox.pack_start(sub_vbox, expand=False, fill=False)
label = self.gen_label_widget("Downloads directory")
tooltip = "Select a folder that caches the upstream project source code"
dldir_widget, self.dldir_text = self.gen_entry_widget(self.configuration.dldir, self,"<b>Downloaded source code</b>" + "*" + tooltip)
sub_vbox.pack_start(label, expand=False, fill=False)
sub_vbox.pack_start(dldir_widget, expand=False, fill=False)
return advanced_vbox
def create_shared_state_page(self):
advanced_vbox = gtk.VBox(False)
advanced_vbox.set_border_width(12)
sub_vbox = gtk.VBox(False)
advanced_vbox.pack_start(sub_vbox, expand=False, fill=False, padding=24)
content = "<span>Shared state directory</span>"
tooltip = "Select a folder that caches your prebuilt results"
label = self.gen_label_info_widget(content,"<b>Shared state directory</b>" + "*" + tooltip)
sstatedir_widget, self.sstatedir_text = self.gen_entry_widget(self.configuration.sstatedir, self)
sub_vbox.pack_start(label, expand=False, fill=False)
sub_vbox.pack_start(sstatedir_widget, expand=False, fill=False, padding=6)
content = "<span weight=\"bold\">Shared state mirrors</span>"
tooltip = "URLs pointing to pre-built mirrors that will speed your build. "
tooltip += "Select the \'Standard\' configuration if the structure of your "
tooltip += "mirror replicates the structure of your local shared state directory. "
tooltip += "For more information on shared state mirrors, check the <a href=\""
tooltip += "http://www.yoctoproject.org/docs/current/poky-ref-manual/"
tooltip += "poky-ref-manual.html#shared-state\">Yocto Project Reference Manual</a>."
table = self.gen_label_info_widget(content,"<b>Shared state mirrors</b>" + "*" + tooltip)
advanced_vbox.pack_start(table, expand=False, fill=False, padding=6)
sub_vbox = gtk.VBox(False)
advanced_vbox.pack_start(sub_vbox, gtk.TRUE, gtk.TRUE, 0)
searched_string = "file://"
if self.sstatemirrors_changed == 0:
self.sstatemirrors_changed = 1
sstatemirrors = self.configuration.sstatemirror
if sstatemirrors == "":
sm_list = ["Standard", "", "file://(.*)"]
self.sstatemirrors_list.append(sm_list)
else:
while sstatemirrors.find(searched_string) != -1:
if sstatemirrors.find(searched_string,1) != -1:
sstatemirror = sstatemirrors[:sstatemirrors.find(searched_string,1)]
sstatemirrors = sstatemirrors[sstatemirrors.find(searched_string,1):]
else:
sstatemirror = sstatemirrors
sstatemirrors = sstatemirrors[1:]
sstatemirror_fields = [x for x in sstatemirror.split(' ') if x.strip()]
if len(sstatemirror_fields):
if sstatemirror_fields[0] == "file://(.*)":
sm_list = ["Standard", sstatemirror_fields[1], "file://(.*)"]
else:
sm_list = ["Custom", sstatemirror_fields[1], sstatemirror_fields[0]]
self.sstatemirrors_list.append(sm_list)
sstatemirrors_widget, sstatemirrors_store = self.gen_shared_sstate_widget(self.sstatemirrors_list, self)
sub_vbox.pack_start(sstatemirrors_widget, expand=True, fill=True)
table = gtk.Table(1, 10, False)
table.set_col_spacings(6)
add_mirror_button = HobAltButton("Add mirror")
add_mirror_button.connect("clicked", self.add_mirror)
add_mirror_button.set_size_request(120,30)
table.attach(add_mirror_button, 1, 2, 0, 1, xoptions=gtk.SHRINK)
self.delete_button = HobAltButton("Delete mirror")
self.delete_button.connect("clicked", self.delete_cb)
self.delete_button.set_size_request(120, 30)
table.attach(self.delete_button, 3, 4, 0, 1, xoptions=gtk.SHRINK)
advanced_vbox.pack_start(table, expand=False, fill=False, padding=6)
return advanced_vbox
def gen_shared_sstate_widget(self, sstatemirrors_list, window):
hbox = gtk.HBox(False)
sstatemirrors_store = gtk.ListStore(str, str, str)
for sstatemirror in sstatemirrors_list:
sstatemirrors_store.append(sstatemirror)
self.sstatemirrors_tv = gtk.TreeView()
self.sstatemirrors_tv.set_rules_hint(True)
self.sstatemirrors_tv.set_headers_visible(True)
tree_selection = self.sstatemirrors_tv.get_selection()
tree_selection.set_mode(gtk.SELECTION_SINGLE)
# Allow enable drag and drop of rows including row move
self.sstatemirrors_tv.enable_model_drag_source( gtk.gdk.BUTTON1_MASK,
self.TARGETS,
gtk.gdk.ACTION_DEFAULT|
gtk.gdk.ACTION_MOVE)
self.sstatemirrors_tv.enable_model_drag_dest(self.TARGETS,
gtk.gdk.ACTION_DEFAULT)
self.sstatemirrors_tv.connect("drag_data_get", self.drag_data_get_cb)
self.sstatemirrors_tv.connect("drag_data_received", self.drag_data_received_cb)
self.scroll = gtk.ScrolledWindow()
self.scroll.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
self.scroll.set_shadow_type(gtk.SHADOW_IN)
self.scroll.connect('size-allocate', self.scroll_changed)
self.scroll.add(self.sstatemirrors_tv)
#list store for cell renderer
m = gtk.ListStore(gobject.TYPE_STRING)
m.append(["Standard"])
m.append(["Custom"])
cell0 = gtk.CellRendererCombo()
cell0.set_property("model",m)
cell0.set_property("text-column", 0)
cell0.set_property("editable", True)
cell0.set_property("has-entry", False)
col0 = gtk.TreeViewColumn("Configuration")
col0.pack_start(cell0, False)
col0.add_attribute(cell0, "text", 0)
col0.set_cell_data_func(cell0, self.configuration_field)
self.sstatemirrors_tv.append_column(col0)
cell0.connect("edited", self.combo_changed, sstatemirrors_store)
self.cell1 = gtk.CellRendererText()
self.cell1.set_padding(5,2)
col1 = gtk.TreeViewColumn('Regex', self.cell1)
col1.set_cell_data_func(self.cell1, self.regex_field)
self.sstatemirrors_tv.append_column(col1)
self.cell1.connect("edited", self.regex_changed, sstatemirrors_store)
cell2 = gtk.CellRendererText()
cell2.set_padding(5,2)
cell2.set_property("editable", True)
col2 = gtk.TreeViewColumn('URL', cell2)
col2.set_cell_data_func(cell2, self.url_field)
self.sstatemirrors_tv.append_column(col2)
cell2.connect("edited", self.url_changed, sstatemirrors_store)
self.sstatemirrors_tv.set_model(sstatemirrors_store)
self.sstatemirrors_tv.set_cursor(self.selected_mirror_row)
hbox.pack_start(self.scroll, expand=True, fill=True)
hbox.show_all()
return hbox, sstatemirrors_store
def drag_data_get_cb(self, treeview, context, selection, target_id, etime):
treeselection = treeview.get_selection()
model, iter = treeselection.get_selected()
data = model.get_string_from_iter(iter)
selection.set(selection.target, 8, data)
def drag_data_received_cb(self, treeview, context, x, y, selection, info, etime):
model = treeview.get_model()
data = []
tree_iter = model.get_iter_from_string(selection.data)
data.append(model.get_value(tree_iter, 0))
data.append(model.get_value(tree_iter, 1))
data.append(model.get_value(tree_iter, 2))
drop_info = treeview.get_dest_row_at_pos(x, y)
if drop_info:
path, position = drop_info
iter = model.get_iter(path)
if (position == gtk.TREE_VIEW_DROP_BEFORE or position == gtk.TREE_VIEW_DROP_INTO_OR_BEFORE):
model.insert_before(iter, data)
else:
model.insert_after(iter, data)
else:
model.append(data)
if context.action == gtk.gdk.ACTION_MOVE:
context.finish(True, True, etime)
return
def delete_cb(self, button):
selection = self.sstatemirrors_tv.get_selection()
tree_model, tree_iter = selection.get_selected()
index = int(tree_model.get_string_from_iter(tree_iter))
if index == 0:
self.selected_mirror_row = index
else:
self.selected_mirror_row = index - 1
self.sstatemirrors_list.pop(index)
self.refresh_shared_state_page()
if not self.sstatemirrors_list:
self.delete_button.set_sensitive(False)
def add_mirror(self, button):
self.new_mirror = True
tooltip = "Select the pre-built mirror that will speed your build"
index = len(self.sstatemirrors_list)
self.selected_mirror_row = index
sm_list = ["Standard", "", "file://(.*)"]
self.sstatemirrors_list.append(sm_list)
self.refresh_shared_state_page()
def scroll_changed(self, widget, event, data=None):
if self.new_mirror == True:
adj = widget.get_vadjustment()
adj.set_value(adj.upper - adj.page_size)
self.new_mirror = False
def combo_changed(self, widget, path, text, model):
model[path][0] = text
selection = self.sstatemirrors_tv.get_selection()
tree_model, tree_iter = selection.get_selected()
index = int(tree_model.get_string_from_iter(tree_iter))
self.sstatemirrors_list[index][0] = text
def regex_changed(self, cell, path, new_text, user_data):
user_data[path][2] = new_text
selection = self.sstatemirrors_tv.get_selection()
tree_model, tree_iter = selection.get_selected()
index = int(tree_model.get_string_from_iter(tree_iter))
self.sstatemirrors_list[index][2] = new_text
return
def url_changed(self, cell, path, new_text, user_data):
if new_text!="Enter the mirror URL" and new_text!="Match regex and replace it with this URL":
user_data[path][1] = new_text
selection = self.sstatemirrors_tv.get_selection()
tree_model, tree_iter = selection.get_selected()
index = int(tree_model.get_string_from_iter(tree_iter))
self.sstatemirrors_list[index][1] = new_text
return
def configuration_field(self, column, cell, model, iter):
cell.set_property('text', model.get_value(iter, 0))
if model.get_value(iter, 0) == "Standard":
self.cell1.set_property("sensitive", False)
self.cell1.set_property("editable", False)
else:
self.cell1.set_property("sensitive", True)
self.cell1.set_property("editable", True)
return
def regex_field(self, column, cell, model, iter):
cell.set_property('text', model.get_value(iter, 2))
return
def url_field(self, column, cell, model, iter):
text = model.get_value(iter, 1)
if text == "":
if model.get_value(iter, 0) == "Standard":
text = "Enter the mirror URL"
else:
text = "Match regex and replace it with this URL"
cell.set_property('text', text)
return
def refresh_shared_state_page(self):
page_num = self.nb.get_current_page()
self.nb.remove_page(page_num);
self.nb.insert_page(self.create_shared_state_page(), gtk.Label("Shared state"),page_num)
self.show_all()
self.nb.set_current_page(page_num)
def test_proxy_ended(self, passed):
self.proxy_test_running = False
self.set_test_proxy_state(self.TEST_NETWORK_PASSED if passed else self.TEST_NETWORK_FAILED)
self.set_sensitive(True)
self.refresh_proxy_components()
def timer_func(self):
self.test_proxy_progress.pulse()
return self.proxy_test_running
def test_network_button_cb(self, b):
self.set_test_proxy_state(self.TEST_NETWORK_RUNNING)
self.set_sensitive(False)
self.save_proxy_data()
if self.configuration.enable_proxy == True:
self.handler.set_http_proxy(self.configuration.combine_proxy("http"))
self.handler.set_https_proxy(self.configuration.combine_proxy("https"))
self.handler.set_ftp_proxy(self.configuration.combine_proxy("ftp"))
self.handler.set_socks_proxy(self.configuration.combine_proxy("socks"))
self.handler.set_cvs_proxy(self.configuration.combine_host_only("cvs"), self.configuration.combine_port_only("cvs"))
elif self.configuration.enable_proxy == False:
self.handler.set_http_proxy("")
self.handler.set_https_proxy("")
self.handler.set_ftp_proxy("")
self.handler.set_socks_proxy("")
self.handler.set_cvs_proxy("", "")
self.proxy_test_ran = True
self.proxy_test_running = True
gobject.timeout_add(100, self.timer_func)
self.handler.trigger_network_test()
def test_proxy_focus_event(self, w, direction):
if self.test_proxy_state in [self.TEST_NETWORK_PASSED, self.TEST_NETWORK_FAILED]:
self.set_test_proxy_state(self.TEST_NETWORK_INITIAL)
return False
def http_proxy_changed(self, e):
if not self.configuration.same_proxy:
return
if e == self.http_proxy:
[w.set_text(self.http_proxy.get_text()) for w in self.same_proxy_addresses]
else:
[w.set_text(self.http_proxy_port.get_text()) for w in self.same_proxy_ports]
def proxy_address_focus_out_event(self, w, direction):
text = w.get_text()
if not text:
return False
if text.find("//") == -1:
w.set_text("http://" + text)
return False
def set_test_proxy_state(self, state):
if self.test_proxy_state == state:
return
[self.proxy_table.remove(w) for w in self.test_gui_elements]
if state == self.TEST_NETWORK_INITIAL:
self.proxy_table.attach(self.test_network_button, 1, 2, 5, 6)
self.test_network_button.show()
elif state == self.TEST_NETWORK_RUNNING:
self.test_proxy_progress.set_rcstyle("running")
self.test_proxy_progress.set_text("Testing network configuration")
self.proxy_table.attach(self.test_proxy_progress, 0, 5, 5, 6, xpadding=4)
self.test_proxy_progress.show()
else: # passed or failed
self.dummy_progress.update(1.0)
if state == self.TEST_NETWORK_PASSED:
self.dummy_progress.set_text("Your network is properly configured")
self.dummy_progress.set_rcstyle("running")
else:
self.dummy_progress.set_text("Network test failed")
self.dummy_progress.set_rcstyle("fail")
self.proxy_table.attach(self.dummy_progress, 0, 4, 5, 6)
self.proxy_table.attach(self.retest_network_button, 4, 5, 5, 6, xpadding=4)
self.dummy_progress.show()
self.retest_network_button.show()
self.test_proxy_state = state
def create_network_page(self):
advanced_vbox = gtk.VBox(False, 6)
advanced_vbox.set_border_width(6)
self.same_proxy_addresses = []
self.same_proxy_ports = []
self.all_proxy_ports = []
self.all_proxy_addresses = []
sub_vbox = gtk.VBox(False, 6)
advanced_vbox.pack_start(sub_vbox, expand=False, fill=False)
label = self.gen_label_widget("<span weight=\"bold\">Set the proxies used when fetching source code</span>")
tooltip = "Set the proxies used when fetching source code. A blank field uses a direct internet connection."
info = HobInfoButton("<span weight=\"bold\">Set the proxies used when fetching source code</span>" + "*" + tooltip, self)
hbox = gtk.HBox(False, 12)
hbox.pack_start(label, expand=True, fill=True)
hbox.pack_start(info, expand=False, fill=False)
sub_vbox.pack_start(hbox, expand=False, fill=False)
proxy_test_focus = []
self.direct_checkbox = gtk.RadioButton(None, "Direct network connection")
proxy_test_focus.append(self.direct_checkbox)
self.direct_checkbox.set_tooltip_text("Check this box to use a direct internet connection with no proxy")
self.direct_checkbox.set_active(not self.configuration.enable_proxy)
sub_vbox.pack_start(self.direct_checkbox, expand=False, fill=False)
self.proxy_checkbox = gtk.RadioButton(self.direct_checkbox, "Manual proxy configuration")
proxy_test_focus.append(self.proxy_checkbox)
self.proxy_checkbox.set_tooltip_text("Check this box to manually set up a specific proxy")
self.proxy_checkbox.set_active(self.configuration.enable_proxy)
sub_vbox.pack_start(self.proxy_checkbox, expand=False, fill=False)
self.same_checkbox = gtk.CheckButton("Use the HTTP proxy for all protocols")
proxy_test_focus.append(self.same_checkbox)
self.same_checkbox.set_tooltip_text("Check this box to use the HTTP proxy for all five proxies")
self.same_checkbox.set_active(self.configuration.same_proxy)
hbox = gtk.HBox(False, 12)
hbox.pack_start(self.same_checkbox, expand=False, fill=False, padding=24)
sub_vbox.pack_start(hbox, expand=False, fill=False)
self.proxy_table = gtk.Table(6, 5, False)
self.http_proxy, self.http_proxy_port, self.http_proxy_details = self.gen_proxy_entry_widget(
"http", self, True, 0)
proxy_test_focus +=[self.http_proxy, self.http_proxy_port]
self.http_proxy.connect("changed", self.http_proxy_changed)
self.http_proxy_port.connect("changed", self.http_proxy_changed)
self.https_proxy, self.https_proxy_port, self.https_proxy_details = self.gen_proxy_entry_widget(
"https", self, True, 1)
proxy_test_focus += [self.https_proxy, self.https_proxy_port]
self.same_proxy_addresses.append(self.https_proxy)
self.same_proxy_ports.append(self.https_proxy_port)
self.ftp_proxy, self.ftp_proxy_port, self.ftp_proxy_details = self.gen_proxy_entry_widget(
"ftp", self, True, 2)
proxy_test_focus += [self.ftp_proxy, self.ftp_proxy_port]
self.same_proxy_addresses.append(self.ftp_proxy)
self.same_proxy_ports.append(self.ftp_proxy_port)
self.socks_proxy, self.socks_proxy_port, self.socks_proxy_details = self.gen_proxy_entry_widget(
"socks", self, True, 3)
proxy_test_focus += [self.socks_proxy, self.socks_proxy_port]
self.same_proxy_addresses.append(self.socks_proxy)
self.same_proxy_ports.append(self.socks_proxy_port)
self.cvs_proxy, self.cvs_proxy_port, self.cvs_proxy_details = self.gen_proxy_entry_widget(
"cvs", self, True, 4)
proxy_test_focus += [self.cvs_proxy, self.cvs_proxy_port]
self.same_proxy_addresses.append(self.cvs_proxy)
self.same_proxy_ports.append(self.cvs_proxy_port)
self.all_proxy_ports = self.same_proxy_ports + [self.http_proxy_port]
self.all_proxy_addresses = self.same_proxy_addresses + [self.http_proxy]
sub_vbox.pack_start(self.proxy_table, expand=False, fill=False)
self.proxy_table.show_all()
# Create the graphical elements for the network test feature, but don't display them yet
self.test_network_button = HobAltButton("Test network configuration")
self.test_network_button.connect("clicked", self.test_network_button_cb)
self.test_proxy_progress = HobProgressBar()
self.dummy_progress = HobProgressBar()
self.retest_network_button = HobAltButton("Retest")
self.retest_network_button.connect("clicked", self.test_network_button_cb)
self.test_gui_elements = [self.test_network_button, self.test_proxy_progress, self.dummy_progress, self.retest_network_button]
# Initialize the network tester
self.test_proxy_state = self.TEST_NETWORK_NONE
self.set_test_proxy_state(self.TEST_NETWORK_INITIAL)
self.proxy_test_passed_id = self.handler.connect("network-passed", lambda h:self.test_proxy_ended(True))
self.proxy_test_failed_id = self.handler.connect("network-failed", lambda h:self.test_proxy_ended(False))
[w.connect("focus-in-event", self.test_proxy_focus_event) for w in proxy_test_focus]
[w.connect("focus-out-event", self.proxy_address_focus_out_event) for w in self.all_proxy_addresses]
self.direct_checkbox.connect("toggled", self.proxy_checkbox_toggled_cb)
self.proxy_checkbox.connect("toggled", self.proxy_checkbox_toggled_cb)
self.same_checkbox.connect("toggled", self.same_checkbox_toggled_cb)
self.refresh_proxy_components()
return advanced_vbox
def switch_to_page(self, page_id):
self.nb.set_current_page(page_id)
def details_cb(self, button, parent, protocol):
self.save_proxy_data()
dialog = ProxyDetailsDialog(title = protocol.upper() + " Proxy Details",
user = self.configuration.proxies[protocol][1],
passwd = self.configuration.proxies[protocol][2],
parent = parent,
flags = gtk.DIALOG_MODAL
| gtk.DIALOG_DESTROY_WITH_PARENT
| gtk.DIALOG_NO_SEPARATOR)
dialog.add_button(gtk.STOCK_CLOSE, gtk.RESPONSE_OK)
response = dialog.run()
if response == gtk.RESPONSE_OK:
self.configuration.proxies[protocol][1] = dialog.user
self.configuration.proxies[protocol][2] = dialog.passwd
self.refresh_proxy_components()
dialog.destroy()
def rootfs_combo_changed_cb(self, rootfs_combo, all_package_format, check_hbox):
combo_item = self.rootfs_combo.get_active_text()
for child in check_hbox.get_children():
if isinstance(child, gtk.CheckButton):
check_hbox.remove(child)
for format in all_package_format:
if format != combo_item:
check_button = gtk.CheckButton(format)
check_hbox.pack_start(check_button, expand=False, fill=False)
check_hbox.show_all()
def gen_pkgfmt_widget(self, curr_package_format, all_package_format, tooltip_combo="", tooltip_extra=""):
pkgfmt_hbox = gtk.HBox(False, 24)
rootfs_vbox = gtk.VBox(False, 6)
pkgfmt_hbox.pack_start(rootfs_vbox, expand=False, fill=False)
label = self.gen_label_widget("Root file system package format")
rootfs_vbox.pack_start(label, expand=False, fill=False)
rootfs_format = ""
if curr_package_format:
rootfs_format = curr_package_format.split()[0]
rootfs_format_widget, rootfs_combo = self.gen_combo_widget(rootfs_format, all_package_format, tooltip_combo)
rootfs_vbox.pack_start(rootfs_format_widget, expand=False, fill=False)
extra_vbox = gtk.VBox(False, 6)
pkgfmt_hbox.pack_start(extra_vbox, expand=False, fill=False)
label = self.gen_label_widget("Additional package formats")
extra_vbox.pack_start(label, expand=False, fill=False)
check_hbox = gtk.HBox(False, 12)
extra_vbox.pack_start(check_hbox, expand=False, fill=False)
for format in all_package_format:
if format != rootfs_format:
check_button = gtk.CheckButton(format)
is_active = (format in curr_package_format.split())
check_button.set_active(is_active)
check_hbox.pack_start(check_button, expand=False, fill=False)
info = HobInfoButton(tooltip_extra, self)
check_hbox.pack_end(info, expand=False, fill=False)
rootfs_combo.connect("changed", self.rootfs_combo_changed_cb, all_package_format, check_hbox)
pkgfmt_hbox.show_all()
return pkgfmt_hbox, rootfs_combo, check_hbox
def editable_settings_cell_edited(self, cell, path_string, new_text, model):
it = model.get_iter_from_string(path_string)
column = cell.get_data("column")
model.set(it, column, new_text)
def editable_settings_add_item_clicked(self, button, model):
new_item = ["##KEY##", "##VALUE##"]
iter = model.append()
model.set (iter,
0, new_item[0],
1, new_item[1],
)
def editable_settings_remove_item_clicked(self, button, treeview):
selection = treeview.get_selection()
model, iter = selection.get_selected()
if iter:
path = model.get_path(iter)[0]
model.remove(iter)
def gen_editable_settings(self, setting, tooltip=""):
setting_hbox = gtk.HBox(False, 12)
vbox = gtk.VBox(False, 12)
setting_hbox.pack_start(vbox, expand=True, fill=True)
setting_store = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING)
for key in setting.keys():
setting_store.set(setting_store.append(), 0, key, 1, setting[key])
setting_tree = gtk.TreeView(setting_store)
setting_tree.set_headers_visible(True)
setting_tree.set_size_request(300, 100)
col = gtk.TreeViewColumn('Key')
col.set_min_width(100)
col.set_max_width(150)
col.set_resizable(True)
col1 = gtk.TreeViewColumn('Value')
col1.set_min_width(100)
col1.set_max_width(150)
col1.set_resizable(True)
setting_tree.append_column(col)
setting_tree.append_column(col1)
cell = gtk.CellRendererText()
cell.set_property('width-chars', 10)
cell.set_property('editable', True)
cell.set_data("column", 0)
cell.connect("edited", self.editable_settings_cell_edited, setting_store)
cell1 = gtk.CellRendererText()
cell1.set_property('width-chars', 10)
cell1.set_property('editable', True)
cell1.set_data("column", 1)
cell1.connect("edited", self.editable_settings_cell_edited, setting_store)
col.pack_start(cell, True)
col1.pack_end(cell1, True)
col.set_attributes(cell, text=0)
col1.set_attributes(cell1, text=1)
scroll = gtk.ScrolledWindow()
scroll.set_shadow_type(gtk.SHADOW_IN)
scroll.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
scroll.add(setting_tree)
vbox.pack_start(scroll, expand=True, fill=True)
# some buttons
hbox = gtk.HBox(True, 6)
vbox.pack_start(hbox, False, False)
button = gtk.Button(stock=gtk.STOCK_ADD)
button.connect("clicked", self.editable_settings_add_item_clicked, setting_store)
hbox.pack_start(button)
button = gtk.Button(stock=gtk.STOCK_REMOVE)
button.connect("clicked", self.editable_settings_remove_item_clicked, setting_tree)
hbox.pack_start(button)
info = HobInfoButton(tooltip, self)
setting_hbox.pack_start(info, expand=False, fill=False)
return setting_hbox, setting_store
def create_others_page(self):
advanced_vbox = gtk.VBox(False, 6)
advanced_vbox.set_border_width(6)
sub_vbox = gtk.VBox(False, 6)
advanced_vbox.pack_start(sub_vbox, expand=True, fill=True)
label = self.gen_label_widget("<span weight=\"bold\">Add your own variables:</span>")
tooltip = "These are key/value pairs for your extra settings. Click \'Add\' and then directly edit the key and the value"
setting_widget, self.setting_store = self.gen_editable_settings(self.configuration.extra_setting,"<b>Add your own variables</b>" + "*" + tooltip)
sub_vbox.pack_start(label, expand=False, fill=False)
sub_vbox.pack_start(setting_widget, expand=True, fill=True)
return advanced_vbox
def create_visual_elements(self):
self.nb = gtk.Notebook()
self.nb.set_show_tabs(True)
self.nb.append_page(self.create_build_environment_page(), gtk.Label("Build environment"))
self.nb.append_page(self.create_shared_state_page(), gtk.Label("Shared state"))
self.nb.append_page(self.create_network_page(), gtk.Label("Network"))
self.nb.append_page(self.create_others_page(), gtk.Label("Others"))
self.nb.set_current_page(0)
self.vbox.pack_start(self.nb, expand=True, fill=True)
self.vbox.pack_end(gtk.HSeparator(), expand=True, fill=True)
self.show_all()
def destroy(self):
self.handler.disconnect(self.proxy_test_passed_id)
self.handler.disconnect(self.proxy_test_failed_id)
super(SimpleSettingsDialog, self).destroy()

View File

@@ -30,7 +30,6 @@ class HobColors:
BLACK = "#000000"
PALE_BLUE = "#53b8ff"
DEEP_RED = "#aa3e3e"
KHAKI = "#fff68f"
OK = WHITE
RUNNING = PALE_GREEN

View File

@@ -41,9 +41,6 @@ class HobHandler(gobject.GObject):
"command-failed" : (gobject.SIGNAL_RUN_LAST,
gobject.TYPE_NONE,
(gobject.TYPE_STRING,)),
"parsing-warning" : (gobject.SIGNAL_RUN_LAST,
gobject.TYPE_NONE,
(gobject.TYPE_STRING,)),
"sanity-failed" : (gobject.SIGNAL_RUN_LAST,
gobject.TYPE_NONE,
(gobject.TYPE_STRING, gobject.TYPE_INT)),
@@ -68,17 +65,10 @@ class HobHandler(gobject.GObject):
"package-populated" : (gobject.SIGNAL_RUN_LAST,
gobject.TYPE_NONE,
()),
"network-passed" : (gobject.SIGNAL_RUN_LAST,
gobject.TYPE_NONE,
()),
"network-failed" : (gobject.SIGNAL_RUN_LAST,
gobject.TYPE_NONE,
()),
}
(GENERATE_CONFIGURATION, GENERATE_RECIPES, GENERATE_PACKAGES, GENERATE_IMAGE, POPULATE_PACKAGEINFO, SANITY_CHECK, NETWORK_TEST) = range(7)
(SUB_PATH_LAYERS, SUB_FILES_DISTRO, SUB_FILES_MACH, SUB_FILES_SDKMACH, SUB_MATCH_CLASS, SUB_PARSE_CONFIG, SUB_SANITY_CHECK,
SUB_GNERATE_TGTS, SUB_GENERATE_PKGINFO, SUB_BUILD_RECIPES, SUB_BUILD_IMAGE, SUB_NETWORK_TEST) = range(12)
(GENERATE_CONFIGURATION, GENERATE_RECIPES, GENERATE_PACKAGES, GENERATE_IMAGE, POPULATE_PACKAGEINFO, SANITY_CHECK) = range(6)
(SUB_PATH_LAYERS, SUB_FILES_DISTRO, SUB_FILES_MACH, SUB_FILES_SDKMACH, SUB_MATCH_CLASS, SUB_PARSE_CONFIG, SUB_SANITY_CHECK, SUB_GNERATE_TGTS, SUB_GENERATE_PKGINFO, SUB_BUILD_RECIPES, SUB_BUILD_IMAGE) = range(11)
def __init__(self, server, recipe_model, package_model):
super(HobHandler, self).__init__()
@@ -98,7 +88,6 @@ class HobHandler(gobject.GObject):
self.server = server
self.error_msg = ""
self.initcmd = None
self.parsing = False
def set_busy(self):
if not self.generating:
@@ -112,9 +101,13 @@ class HobHandler(gobject.GObject):
def runCommand(self, commandline):
try:
result, error = self.server.runCommand(commandline)
if error:
raise Exception("Error running command '%s': %s" % (commandline, error))
result = self.server.runCommand(commandline)
result_str = str(result)
if (result_str.startswith("Busy (") or
result_str == "No such command"):
raise Exception('%s has failed with output "%s". ' %
(str(commandline), result_str) +
"We recommend that you restart Hob.")
return result
except Exception as e:
self.commands_async = []
@@ -146,17 +139,13 @@ class HobHandler(gobject.GObject):
elif next_command == self.SUB_MATCH_CLASS:
self.runCommand(["findFilesMatchingInDir", "rootfs_", "classes"])
elif next_command == self.SUB_PARSE_CONFIG:
self.runCommand(["enableDataTracking"])
self.runCommand(["parseConfigurationFiles", "", ""])
self.runCommand(["disableDataTracking"])
elif next_command == self.SUB_GNERATE_TGTS:
self.runCommand(["generateTargetsTree", "classes/image.bbclass", []])
elif next_command == self.SUB_GENERATE_PKGINFO:
self.runCommand(["triggerEvent", "bb.event.RequestPackageInfo()"])
elif next_command == self.SUB_SANITY_CHECK:
self.runCommand(["triggerEvent", "bb.event.SanityCheck()"])
elif next_command == self.SUB_NETWORK_TEST:
self.runCommand(["triggerEvent", "bb.event.NetworkTest()"])
elif next_command == self.SUB_BUILD_RECIPES:
self.clear_busy()
self.building = True
@@ -172,14 +161,6 @@ class HobHandler(gobject.GObject):
if self.toolchain_packages:
self.runCommand(["setVariable", "TOOLCHAIN_TARGET_TASK", " ".join(self.toolchain_packages)])
targets.append(self.toolchain)
if targets[0] == "hob-image":
hobImage = self.runCommand(["matchFile", "hob-image.bb"])
if self.base_image != "Create your own image":
baseImage = self.runCommand(["matchFile", self.base_image + ".bb"])
version = self.runCommand(["generateNewImage", hobImage, baseImage, self.package_queue])
targets[0] += version
self.recipe_model.set_custom_image_version(version)
self.runCommand(["buildTargets", targets, self.default_task])
def display_error(self):
@@ -202,10 +183,6 @@ class HobHandler(gobject.GObject):
self.run_next_command()
elif isinstance(event, bb.event.SanityCheckPassed):
reparse = self.runCommand(["getVariable", "BB_INVALIDCONF"]) or None
if reparse is True:
self.runCommand(["setVariable", "BB_INVALIDCONF", False])
self.runCommand(["parseConfigurationFiles", "", ""])
self.run_next_command()
elif isinstance(event, bb.event.SanityCheckFailed):
@@ -217,11 +194,6 @@ class HobHandler(gobject.GObject):
formatter = bb.msg.BBLogFormatter()
msg = formatter.format(event)
self.error_msg += msg + '\n'
elif event.levelno >= logging.WARNING and self.parsing == True:
formatter = bb.msg.BBLogFormatter()
msg = formatter.format(event)
warn_msg = msg + '\n'
self.emit("parsing-warning", warn_msg)
elif isinstance(event, bb.event.TargetsTreeGenerated):
self.current_phase = "data generation"
@@ -262,10 +234,8 @@ class HobHandler(gobject.GObject):
message["eventname"] = bb.event.getName(event)
message["current"] = 0
message["total"] = None
message["title"] = "Parsing recipes"
message["title"] = "Parsing recipes: "
self.emit("parsing-started", message)
if isinstance(event, bb.event.ParseStarted):
self.parsing = True
elif isinstance(event, (bb.event.ParseProgress,
bb.event.CacheLoadProgress,
bb.event.TreeDataPreparationProgress)):
@@ -273,7 +243,7 @@ class HobHandler(gobject.GObject):
message["eventname"] = bb.event.getName(event)
message["current"] = event.current
message["total"] = event.total
message["title"] = "Parsing recipes"
message["title"] = "Parsing recipes: "
self.emit("parsing", message)
elif isinstance(event, (bb.event.ParseCompleted,
bb.event.CacheLoadCompleted,
@@ -282,16 +252,8 @@ class HobHandler(gobject.GObject):
message["eventname"] = bb.event.getName(event)
message["current"] = event.total
message["total"] = event.total
message["title"] = "Parsing recipes"
message["title"] = "Parsing recipes: "
self.emit("parsing-completed", message)
if isinstance(event, bb.event.ParseCompleted):
self.parsing = False
elif isinstance(event, bb.event.NetworkTestFailed):
self.emit("network-failed")
self.run_next_command()
elif isinstance(event, bb.event.NetworkTestPassed):
self.emit("network-passed")
self.run_next_command()
if self.error_msg and not self.commands_async:
self.display_error()
@@ -307,42 +269,42 @@ class HobHandler(gobject.GObject):
self.runCommand(["setVariable", "INHERIT", inherits])
def set_bblayers(self, bblayers):
self.runCommand(["setVariable", "BBLAYERS", " ".join(bblayers)])
self.runCommand(["setVariable", "BBLAYERS_HOB", " ".join(bblayers)])
def set_machine(self, machine):
if machine:
self.runCommand(["setVariable", "MACHINE", machine])
self.runCommand(["setVariable", "MACHINE_HOB", machine])
def set_sdk_machine(self, sdk_machine):
self.runCommand(["setVariable", "SDKMACHINE", sdk_machine])
self.runCommand(["setVariable", "SDKMACHINE_HOB", sdk_machine])
def set_image_fstypes(self, image_fstypes):
self.runCommand(["setVariable", "IMAGE_FSTYPES", image_fstypes])
def set_distro(self, distro):
self.runCommand(["setVariable", "DISTRO", distro])
self.runCommand(["setVariable", "DISTRO_HOB", distro])
def set_package_format(self, format):
package_classes = ""
for pkgfmt in format.split():
package_classes += ("package_%s" % pkgfmt + " ")
self.runCommand(["setVariable", "PACKAGE_CLASSES", package_classes])
self.runCommand(["setVariable", "PACKAGE_CLASSES_HOB", package_classes])
def set_bbthreads(self, threads):
self.runCommand(["setVariable", "BB_NUMBER_THREADS", threads])
self.runCommand(["setVariable", "BB_NUMBER_THREADS_HOB", threads])
def set_pmake(self, threads):
pmake = "-j %s" % threads
self.runCommand(["setVariable", "PARALLEL_MAKE", pmake])
self.runCommand(["setVariable", "PARALLEL_MAKE_HOB", pmake])
def set_dl_dir(self, directory):
self.runCommand(["setVariable", "DL_DIR", directory])
self.runCommand(["setVariable", "DL_DIR_HOB", directory])
def set_sstate_dir(self, directory):
self.runCommand(["setVariable", "SSTATE_DIR", directory])
self.runCommand(["setVariable", "SSTATE_DIR_HOB", directory])
def set_sstate_mirrors(self, url):
self.runCommand(["setVariable", "SSTATE_MIRRORS", url])
self.runCommand(["setVariable", "SSTATE_MIRRORS_HOB", url])
def set_extra_size(self, image_extra_size):
self.runCommand(["setVariable", "IMAGE_ROOTFS_EXTRA_SPACE", str(image_extra_size)])
@@ -351,13 +313,16 @@ class HobHandler(gobject.GObject):
self.runCommand(["setVariable", "IMAGE_ROOTFS_SIZE", str(image_rootfs_size)])
def set_incompatible_license(self, incompat_license):
self.runCommand(["setVariable", "INCOMPATIBLE_LICENSE", incompat_license])
self.runCommand(["setVariable", "INCOMPATIBLE_LICENSE_HOB", incompat_license])
def set_extra_config(self, extra_setting):
for key in extra_setting.keys():
value = extra_setting[key]
self.runCommand(["setVariable", key, value])
def set_config_filter(self, config_filter):
self.runCommand(["setConfFilter", config_filter])
def set_http_proxy(self, http_proxy):
self.runCommand(["setVariable", "http_proxy", http_proxy])
@@ -367,8 +332,9 @@ class HobHandler(gobject.GObject):
def set_ftp_proxy(self, ftp_proxy):
self.runCommand(["setVariable", "ftp_proxy", ftp_proxy])
def set_socks_proxy(self, socks_proxy):
self.runCommand(["setVariable", "all_proxy", socks_proxy])
def set_git_proxy(self, host, port):
self.runCommand(["setVariable", "GIT_PROXY_HOST", host])
self.runCommand(["setVariable", "GIT_PROXY_PORT", port])
def set_cvs_proxy(self, host, port):
self.runCommand(["setVariable", "CVS_PROXY_HOST", host])
@@ -382,10 +348,6 @@ class HobHandler(gobject.GObject):
self.commands_async.append(self.SUB_SANITY_CHECK)
self.run_next_command(self.SANITY_CHECK)
def trigger_network_test(self):
self.commands_async.append(self.SUB_NETWORK_TEST)
self.run_next_command(self.NETWORK_TEST)
def generate_configuration(self):
self.commands_async.append(self.SUB_PARSE_CONFIG)
self.commands_async.append(self.SUB_PATH_LAYERS)
@@ -409,9 +371,8 @@ class HobHandler(gobject.GObject):
self.commands_async.append(self.SUB_BUILD_RECIPES)
self.run_next_command(self.GENERATE_PACKAGES)
def generate_image(self, image, base_image, toolchain, image_packages=[], toolchain_packages=[], default_task="build"):
def generate_image(self, image, toolchain, image_packages=[], toolchain_packages=[], default_task="build"):
self.image = image
self.base_image = base_image
self.toolchain = toolchain
self.package_queue = image_packages
self.toolchain_packages = toolchain_packages
@@ -444,7 +405,7 @@ class HobHandler(gobject.GObject):
self.build.reset()
def get_logfile(self):
return self.server.runCommand(["getVariable", "BB_CONSOLELOG"])[0]
return self.server.runCommand(["getVariable", "BB_CONSOLELOG"])
def _remove_redundant(self, string):
ret = []
@@ -453,20 +414,14 @@ class HobHandler(gobject.GObject):
ret.append(i)
return " ".join(ret)
def set_var_in_file(self, var, val, default_file=None):
self.server.runCommand(["setVarFile", var, val, default_file])
def get_parameters(self):
# retrieve the parameters from bitbake
params = {}
params["core_base"] = self.runCommand(["getVariable", "COREBASE"]) or ""
hob_layer = params["core_base"] + "/meta-hob"
params["layer"] = self.runCommand(["getVariable", "BBLAYERS"]) or ""
params["layers_non_removable"] = self.runCommand(["getVariable", "BBLAYERS_NON_REMOVABLE"]) or ""
if hob_layer not in params["layer"].split():
params["layer"] += (" " + hob_layer)
if hob_layer not in params["layers_non_removable"].split():
params["layers_non_removable"] += (" " + hob_layer)
params["dldir"] = self.runCommand(["getVariable", "DL_DIR"]) or ""
params["machine"] = self.runCommand(["getVariable", "MACHINE"]) or ""
params["distro"] = self.runCommand(["getVariable", "DISTRO"]) or "defaultsetup"
@@ -564,7 +519,9 @@ class HobHandler(gobject.GObject):
params["default_task"] = self.runCommand(["getVariable", "BB_DEFAULT_TASK"]) or "build"
params["socks_proxy"] = self.runCommand(["getVariable", "all_proxy"]) or ""
params["git_proxy_host"] = self.runCommand(["getVariable", "GIT_PROXY_HOST"]) or ""
params["git_proxy_port"] = self.runCommand(["getVariable", "GIT_PROXY_PORT"]) or ""
params["http_proxy"] = self.runCommand(["getVariable", "http_proxy"]) or ""
params["ftp_proxy"] = self.runCommand(["getVariable", "ftp_proxy"]) or ""
params["https_proxy"] = self.runCommand(["getVariable", "https_proxy"]) or ""

View File

@@ -27,15 +27,14 @@ from bb.ui.crumbs.hobpages import HobPage
#
# PackageListModel
#
class PackageListModel(gtk.ListStore):
class PackageListModel(gtk.TreeStore):
"""
This class defines an gtk.ListStore subclass which will convert the output
of the bb.event.TargetsTreeGenerated event into a gtk.ListStore whilst also
This class defines an gtk.TreeStore subclass which will convert the output
of the bb.event.TargetsTreeGenerated event into a gtk.TreeStore whilst also
providing convenience functions to access gtk.TreeModel subclasses which
provide filtered views of the data.
"""
(COL_NAME, COL_VER, COL_REV, COL_RNM, COL_SEC, COL_SUM, COL_RDEP, COL_RPROV, COL_SIZE, COL_RCP, COL_BINB, COL_INC, COL_FADE_INC, COL_FONT, COL_FLIST) = range(15)
(COL_NAME, COL_VER, COL_REV, COL_RNM, COL_SEC, COL_SUM, COL_RDEP, COL_RPROV, COL_SIZE, COL_BINB, COL_INC, COL_FADE_INC, COL_FONT) = range(13)
__gsignals__ = {
"package-selection-changed" : (gobject.SIGNAL_RUN_LAST,
@@ -46,9 +45,15 @@ class PackageListModel(gtk.ListStore):
__toolchain_required_packages__ = ["packagegroup-core-standalone-sdk-target", "packagegroup-core-standalone-sdk-target-dbg"]
def __init__(self):
self.contents = None
self.images = None
self.pkgs_size = 0
self.pn_path = {}
self.pkg_path = {}
self.rprov_pkg = {}
gtk.ListStore.__init__ (self,
gobject.TYPE_STRING,
gtk.TreeStore.__init__ (self,
gobject.TYPE_STRING,
gobject.TYPE_STRING,
gobject.TYPE_STRING,
@@ -61,9 +66,8 @@ class PackageListModel(gtk.ListStore):
gobject.TYPE_STRING,
gobject.TYPE_BOOLEAN,
gobject.TYPE_BOOLEAN,
gobject.TYPE_STRING,
gobject.TYPE_STRING)
self.sort_column_id, self.sort_order = PackageListModel.COL_NAME, gtk.SORT_ASCENDING
"""
Find the model path for the item_name
@@ -71,14 +75,14 @@ class PackageListModel(gtk.ListStore):
"""
def find_path_for_item(self, item_name):
pkg = item_name
if item_name not in self.pn_path.keys():
if item_name not in self.pkg_path.keys():
if item_name not in self.rprov_pkg.keys():
return None
pkg = self.rprov_pkg[item_name]
if pkg not in self.pn_path.keys():
if pkg not in self.pkg_path.keys():
return None
return self.pn_path[pkg]
return self.pkg_path[pkg]
def find_item_for_path(self, item_path):
return self[item_path][self.COL_NAME]
@@ -87,125 +91,25 @@ class PackageListModel(gtk.ListStore):
Helper function to determine whether an item is an item specified by filter
"""
def tree_model_filter(self, model, it, filter):
name = model.get_value(it, self.COL_NAME)
for key in filter.keys():
if key == self.COL_NAME:
if filter[key] != 'Search packages by name':
if name and filter[key] not in name:
return False
else:
if model.get_value(it, key) not in filter[key]:
return False
self.filtered_nb += 1
if model.get_value(it, key) not in filter[key]:
return False
return True
"""
Create, if required, and return a filtered gtk.TreeModelSort
containing only the items specified by filter
"""
def tree_model(self, filter, excluded_items_ahead=False, included_items_ahead=False, search_data=None, initial=False):
def tree_model(self, filter):
model = self.filter_new()
self.filtered_nb = 0
model.set_visible_func(self.tree_model_filter, filter)
sort = gtk.TreeModelSort(model)
sort.connect ('sort-column-changed', self.sort_column_changed_cb)
if initial:
sort.set_sort_column_id(PackageListModel.COL_NAME, gtk.SORT_ASCENDING)
sort.set_default_sort_func(None)
elif excluded_items_ahead:
sort.set_default_sort_func(self.exclude_item_sort_func, search_data)
elif included_items_ahead:
sort.set_default_sort_func(self.include_item_sort_func, search_data)
else:
if search_data and search_data!='Search recipes by name' and search_data!='Search package groups by name':
sort.set_default_sort_func(self.sort_func, search_data)
else:
sort.set_sort_column_id(self.sort_column_id, self.sort_order)
sort.set_default_sort_func(None)
sort.set_sort_func(PackageListModel.COL_INC, self.sort_column, PackageListModel.COL_INC)
sort.set_sort_func(PackageListModel.COL_SIZE, self.sort_column, PackageListModel.COL_SIZE)
sort.set_sort_func(PackageListModel.COL_BINB, self.sort_binb_column)
sort.set_sort_func(PackageListModel.COL_RCP, self.sort_column, PackageListModel.COL_RCP)
sort.set_sort_column_id(PackageListModel.COL_NAME, gtk.SORT_ASCENDING)
sort.set_default_sort_func(None)
return sort
def sort_column_changed_cb (self, data):
self.sort_column_id, self.sort_order = data.get_sort_column_id ()
def sort_column(self, model, row1, row2, col):
value1 = model.get_value(row1, col)
value2 = model.get_value(row2, col)
if col==PackageListModel.COL_SIZE:
value1 = HobPage._string_to_size(value1)
value2 = HobPage._string_to_size(value2)
cmp_res = cmp(value1, value2)
if cmp_res!=0:
if col==PackageListModel.COL_INC:
return -cmp_res
else:
return cmp_res
else:
name1 = model.get_value(row1, PackageListModel.COL_NAME)
name2 = model.get_value(row2, PackageListModel.COL_NAME)
return cmp(name1,name2)
def sort_binb_column(self, model, row1, row2):
value1 = model.get_value(row1, PackageListModel.COL_BINB)
value2 = model.get_value(row2, PackageListModel.COL_BINB)
value1_list = value1.split(', ')
value2_list = value2.split(', ')
value1 = value1_list[0]
value2 = value2_list[0]
cmp_res = cmp(value1, value2)
if cmp_res==0:
cmp_size = cmp(len(value1_list), len(value2_list))
if cmp_size==0:
name1 = model.get_value(row1, PackageListModel.COL_NAME)
name2 = model.get_value(row2, PackageListModel.COL_NAME)
return cmp(name1,name2)
else:
return cmp_size
else:
return cmp_res
def exclude_item_sort_func(self, model, iter1, iter2, user_data=None):
if user_data:
val1 = model.get_value(iter1, PackageListModel.COL_NAME)
val2 = model.get_value(iter2, PackageListModel.COL_NAME)
return self.cmp_vals(val1, val2, user_data)
else:
val1 = model.get_value(iter1, PackageListModel.COL_FADE_INC)
val2 = model.get_value(iter2, PackageListModel.COL_INC)
return ((val1 == True) and (val2 == False))
def include_item_sort_func(self, model, iter1, iter2, user_data=None):
if user_data:
val1 = model.get_value(iter1, PackageListModel.COL_NAME)
val2 = model.get_value(iter2, PackageListModel.COL_NAME)
return self.cmp_vals(val1, val2, user_data)
else:
val1 = model.get_value(iter1, PackageListModel.COL_INC)
val2 = model.get_value(iter2, PackageListModel.COL_INC)
return ((val1 == False) and (val2 == True))
def sort_func(self, model, iter1, iter2, user_data):
val1 = model.get_value(iter1, PackageListModel.COL_NAME)
val2 = model.get_value(iter2, PackageListModel.COL_NAME)
return self.cmp_vals(val1, val2, user_data)
def cmp_vals(self, val1, val2, user_data):
if val1.startswith(user_data) and not val2.startswith(user_data):
return -1
elif not val1.startswith(user_data) and val2.startswith(user_data):
return 1
else:
return cmp(val1, val2)
def convert_vpath_to_path(self, view_model, view_path):
# view_model is the model sorted
# get the path of the model filtered
@@ -217,13 +121,16 @@ class PackageListModel(gtk.ListStore):
return path
def convert_path_to_vpath(self, view_model, path):
name = self.find_item_for_path(path)
it = view_model.get_iter_first()
while it:
name = self.find_item_for_path(path)
view_name = view_model.get_value(it, PackageListModel.COL_NAME)
if view_name == name:
view_path = view_model.get_path(it)
return view_path
child_it = view_model.iter_children(it)
while child_it:
view_name = view_model.get_value(child_it, self.COL_NAME)
if view_name == name:
view_path = view_model.get_path(child_it)
return view_path
child_it = view_model.iter_next(child_it)
it = view_model.iter_next(it)
return None
@@ -232,8 +139,11 @@ class PackageListModel(gtk.ListStore):
bb.event.PackageInfo event and populates the package list.
"""
def populate(self, pkginfolist):
# First clear the model, in case repopulating
self.clear()
self.pkgs_size = 0
self.pn_path = {}
self.pkg_path = {}
self.rprov_pkg = {}
def getpkgvalue(pkgdict, key, pkgname, defaultval = None):
value = pkgdict.get('%s_%s' % (key, pkgname), None)
@@ -245,6 +155,15 @@ class PackageListModel(gtk.ListStore):
pn = pkginfo['PN']
pv = pkginfo['PV']
pr = pkginfo['PR']
if pn in self.pn_path.keys():
pniter = self.get_iter(self.pn_path[pn])
else:
pniter = self.append(None)
self.set(pniter, self.COL_NAME, pn + '-' + pv + '-' + pr,
self.COL_INC, False)
self.pn_path[pn] = self.get_path(pniter)
# PKG is always present
pkg = pkginfo['PKG']
pkgv = getpkgvalue(pkginfo, 'PKGV', pkg)
pkgr = getpkgvalue(pkginfo, 'PKGR', pkg)
@@ -258,12 +177,9 @@ class PackageListModel(gtk.ListStore):
rdep = getpkgvalue(pkginfo, 'RDEPENDS', pkg, "")
rrec = getpkgvalue(pkginfo, 'RRECOMMENDS', pkg, "")
rprov = getpkgvalue(pkginfo, 'RPROVIDES', pkg, "")
files_list = getpkgvalue(pkginfo, 'FILES_INFO', pkg, "")
for i in rprov.split():
self.rprov_pkg[i] = pkg
recipe = pn + '-' + pv + '-' + pr
allow_empty = getpkgvalue(pkginfo, 'ALLOW_EMPTY', pkg, "")
if pkgsize == "0" and not allow_empty:
@@ -271,27 +187,15 @@ class PackageListModel(gtk.ListStore):
# pkgsize is in KB
size = HobPage._size_to_string(HobPage._string_to_size(pkgsize + ' KB'))
self.set(self.append(), self.COL_NAME, pkg, self.COL_VER, pkgv,
it = self.append(pniter)
self.pkg_path[pkg] = self.get_path(it)
self.set(it, self.COL_NAME, pkg, self.COL_VER, pkgv,
self.COL_REV, pkgr, self.COL_RNM, pkg_rename,
self.COL_SEC, section, self.COL_SUM, summary,
self.COL_RDEP, rdep + ' ' + rrec,
self.COL_RPROV, rprov, self.COL_SIZE, size,
self.COL_RCP, recipe, self.COL_BINB, "",
self.COL_INC, False, self.COL_FONT, '10', self.COL_FLIST, files_list)
self.pn_path = {}
it = self.get_iter_first()
while it:
pn = self.get_value(it, self.COL_NAME)
path = self.get_path(it)
self.pn_path[pn] = path
it = self.iter_next(it)
"""
Update the model, send out the notification.
"""
def selection_change_notification(self):
self.emit("package-selection-changed")
self.COL_BINB, "", self.COL_INC, False, self.COL_FONT, '10')
"""
Check whether the item at item_path is included or not
@@ -300,26 +204,54 @@ class PackageListModel(gtk.ListStore):
return self[item_path][self.COL_INC]
"""
Add this item, and any of its dependencies, to the image contents
Update the model, send out the notification.
"""
def selection_change_notification(self):
self.emit("package-selection-changed")
"""
Mark a certain package as selected.
All its dependencies are marked as selected.
The recipe provides the package is marked as selected.
If user explicitly selects a recipe, all its providing packages are selected
"""
def include_item(self, item_path, binb=""):
if self.path_included(item_path):
return
item_name = self[item_path][self.COL_NAME]
item_deps = self[item_path][self.COL_RDEP]
item_rdep = self[item_path][self.COL_RDEP]
self[item_path][self.COL_INC] = True
it = self.get_iter(item_path)
# If user explicitly selects a recipe, all its providing packages are selected.
if not self[item_path][self.COL_VER] and binb == "User Selected":
child_it = self.iter_children(it)
while child_it:
child_path = self.get_path(child_it)
child_included = self.path_included(child_path)
if not child_included:
self.include_item(child_path, binb="User Selected")
child_it = self.iter_next(child_it)
return
# The recipe provides the package is also marked as selected
parent_it = self.iter_parent(it)
if parent_it:
parent_path = self.get_path(parent_it)
self[parent_path][self.COL_INC] = True
item_bin = self[item_path][self.COL_BINB].split(', ')
if binb and not binb in item_bin:
item_bin.append(binb)
self[item_path][self.COL_BINB] = ', '.join(item_bin).lstrip(', ')
if item_deps:
if item_rdep:
# Ensure all of the items deps are included and, where appropriate,
# add this item to their COL_BINB
for dep in item_deps.split(" "):
for dep in item_rdep.split(" "):
if dep.startswith('('):
continue
# If the contents model doesn't already contain dep, add it
@@ -338,6 +270,12 @@ class PackageListModel(gtk.ListStore):
elif not dep_included:
self.include_item(dep_path, binb=item_name)
"""
Mark a certain package as de-selected.
All other packages that depends on this package are marked as de-selected.
If none of the packages provided by the recipe, the recipe should be marked as de-selected.
If user explicitly de-select a recipe, all its providing packages are de-selected.
"""
def exclude_item(self, item_path):
if not self.path_included(item_path):
return
@@ -345,9 +283,37 @@ class PackageListModel(gtk.ListStore):
self[item_path][self.COL_INC] = False
item_name = self[item_path][self.COL_NAME]
item_deps = self[item_path][self.COL_RDEP]
if item_deps:
for dep in item_deps.split(" "):
item_rdep = self[item_path][self.COL_RDEP]
it = self.get_iter(item_path)
# If user explicitly de-select a recipe, all its providing packages are de-selected.
if not self[item_path][self.COL_VER]:
child_it = self.iter_children(it)
while child_it:
child_path = self.get_path(child_it)
child_included = self[child_path][self.COL_INC]
if child_included:
self.exclude_item(child_path)
child_it = self.iter_next(child_it)
return
# If none of the packages provided by the recipe, the recipe should be marked as de-selected.
parent_it = self.iter_parent(it)
peer_iter = self.iter_children(parent_it)
enabled = 0
while peer_iter:
peer_path = self.get_path(peer_iter)
if self[peer_path][self.COL_INC]:
enabled = 1
break
peer_iter = self.iter_next(peer_iter)
if not enabled:
parent_path = self.get_path(parent_it)
self[parent_path][self.COL_INC] = False
# All packages that depends on this package are de-selected.
if item_rdep:
for dep in item_rdep.split(" "):
if dep.startswith('('):
continue
dep_path = self.find_path_for_item(dep)
@@ -367,40 +333,51 @@ class PackageListModel(gtk.ListStore):
self.exclude_item(binb_path)
"""
Empty self.contents by setting the include of each entry to None
Package model may be incomplete, therefore when calling the
set_selected_packages(), some packages will not be set included.
Return the un-set packages list.
"""
def reset(self):
it = self.get_iter_first()
while it:
self.set(it,
self.COL_INC, False,
self.COL_BINB, "")
it = self.iter_next(it)
def set_selected_packages(self, packagelist, user_selected=False):
left = []
binb = 'User Selected' if user_selected else ''
for pn in packagelist:
if pn in self.pkg_path.keys():
path = self.pkg_path[pn]
self.include_item(item_path=path, binb=binb)
else:
left.append(pn)
self.selection_change_notification()
def get_selected_packages(self):
packagelist = []
it = self.get_iter_first()
while it:
if self.get_value(it, self.COL_INC):
name = self.get_value(it, self.COL_NAME)
packagelist.append(name)
it = self.iter_next(it)
return packagelist
return left
def get_user_selected_packages(self):
packagelist = []
it = self.get_iter_first()
while it:
if self.get_value(it, self.COL_INC):
binb = self.get_value(it, self.COL_BINB)
if binb == "User Selected":
name = self.get_value(it, self.COL_NAME)
child_it = self.iter_children(it)
while child_it:
if self.get_value(child_it, self.COL_INC):
binb = self.get_value(child_it, self.COL_BINB)
if binb == "User Selected":
name = self.get_value(child_it, self.COL_NAME)
packagelist.append(name)
child_it = self.iter_next(child_it)
it = self.iter_next(it)
return packagelist
def get_selected_packages(self):
packagelist = []
it = self.get_iter_first()
while it:
child_it = self.iter_children(it)
while child_it:
if self.get_value(child_it, self.COL_INC):
name = self.get_value(child_it, self.COL_NAME)
packagelist.append(name)
child_it = self.iter_next(child_it)
it = self.iter_next(it)
return packagelist
@@ -411,31 +388,16 @@ class PackageListModel(gtk.ListStore):
it = self.get_iter_first()
while it:
if self.get_value(it, self.COL_INC):
name = self.get_value(it, self.COL_NAME)
if name.endswith("-dev") or name.endswith("-dbg"):
packagelist.append(name)
child_it = self.iter_children(it)
while child_it:
name = self.get_value(child_it, self.COL_NAME)
inc = self.get_value(child_it, self.COL_INC)
if inc or name.endswith("-dev") or name.endswith("-dbg"):
packagelist.append(name)
child_it = self.iter_next(child_it)
it = self.iter_next(it)
return list(set(packagelist + self.__toolchain_required_packages__));
"""
Package model may be incomplete, therefore when calling the
set_selected_packages(), some packages will not be set included.
Return the un-set packages list.
"""
def set_selected_packages(self, packagelist, user_selected=False):
left = []
binb = 'User Selected' if user_selected else ''
for pn in packagelist:
if pn in self.pn_path.keys():
path = self.pn_path[pn]
self.include_item(item_path=path, binb=binb)
else:
left.append(pn)
self.selection_change_notification()
return left
"""
Return the selected package size, unit is B.
"""
@@ -443,16 +405,37 @@ class PackageListModel(gtk.ListStore):
packages_size = 0
it = self.get_iter_first()
while it:
if self.get_value(it, self.COL_INC):
str_size = self.get_value(it, self.COL_SIZE)
if not str_size:
continue
child_it = self.iter_children(it)
while child_it:
if self.get_value(child_it, self.COL_INC):
str_size = self.get_value(child_it, self.COL_SIZE)
if not str_size:
continue
packages_size += HobPage._string_to_size(str_size)
packages_size += HobPage._string_to_size(str_size)
child_it = self.iter_next(child_it)
it = self.iter_next(it)
return packages_size
"""
Empty self.contents by setting the include of each entry to None
"""
def reset(self):
self.pkgs_size = 0
it = self.get_iter_first()
while it:
self.set(it, self.COL_INC, False)
child_it = self.iter_children(it)
while child_it:
self.set(child_it,
self.COL_INC, False,
self.COL_BINB, "")
child_it = self.iter_next(child_it)
it = self.iter_next(it)
self.selection_change_notification()
"""
Resync the state of included items to a backup column before performing the fadeout visible effect
"""
@@ -461,6 +444,9 @@ class PackageListModel(gtk.ListStore):
while it:
active = self.get_value(it, self.COL_INC)
self.set(it, self.COL_FADE_INC, active)
if self.iter_has_child(it):
self.resync_fadeout_column(self.iter_children(it))
it = self.iter_next(it)
#
@@ -473,8 +459,7 @@ class RecipeListModel(gtk.ListStore):
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, COL_IMG, COL_INSTALL, COL_PN, COL_FADE_INC, COL_SUMMARY, COL_VERSION,
COL_REVISION, COL_HOMEPAGE, COL_BUGTRACKER) = range(17)
(COL_NAME, COL_DESC, COL_LIC, COL_GROUP, COL_DEPS, COL_BINB, COL_TYPE, COL_INC, COL_IMG, COL_INSTALL, COL_PN, COL_FADE_INC) = range(12)
__custom_image__ = "Create your own image"
@@ -499,13 +484,7 @@ class RecipeListModel(gtk.ListStore):
gobject.TYPE_BOOLEAN,
gobject.TYPE_STRING,
gobject.TYPE_STRING,
gobject.TYPE_BOOLEAN,
gobject.TYPE_STRING,
gobject.TYPE_STRING,
gobject.TYPE_STRING,
gobject.TYPE_STRING,
gobject.TYPE_STRING)
self.sort_column_id, self.sort_order = RecipeListModel.COL_NAME, gtk.SORT_ASCENDING
gobject.TYPE_BOOLEAN)
"""
Find the model path for the item_name
@@ -537,119 +516,39 @@ class RecipeListModel(gtk.ListStore):
return False
for key in filter.keys():
if key == self.COL_NAME:
if filter[key] != 'Search recipes by name' and filter[key] != 'Search package groups by name':
if filter[key] not in name:
return False
else:
if model.get_value(it, key) not in filter[key]:
return False
self.filtered_nb += 1
if model.get_value(it, key) not in filter[key]:
return False
return True
def exclude_item_sort_func(self, model, iter1, iter2, user_data=None):
if user_data:
val1 = model.get_value(iter1, RecipeListModel.COL_NAME)
val2 = model.get_value(iter2, RecipeListModel.COL_NAME)
return self.cmp_vals(val1, val2, user_data)
else:
val1 = model.get_value(iter1, RecipeListModel.COL_FADE_INC)
val2 = model.get_value(iter2, RecipeListModel.COL_INC)
return ((val1 == True) and (val2 == False))
def exclude_item_sort_func(self, model, iter1, iter2):
val1 = model.get_value(iter1, RecipeListModel.COL_FADE_INC)
val2 = model.get_value(iter2, RecipeListModel.COL_INC)
return ((val1 == True) and (val2 == False))
def include_item_sort_func(self, model, iter1, iter2, user_data=None):
if user_data:
val1 = model.get_value(iter1, RecipeListModel.COL_NAME)
val2 = model.get_value(iter2, RecipeListModel.COL_NAME)
return self.cmp_vals(val1, val2, user_data)
else:
val1 = model.get_value(iter1, RecipeListModel.COL_INC)
val2 = model.get_value(iter2, RecipeListModel.COL_INC)
return ((val1 == False) and (val2 == True))
def sort_func(self, model, iter1, iter2, user_data):
val1 = model.get_value(iter1, RecipeListModel.COL_NAME)
val2 = model.get_value(iter2, RecipeListModel.COL_NAME)
return self.cmp_vals(val1, val2, user_data)
def cmp_vals(self, val1, val2, user_data):
if val1.startswith(user_data) and not val2.startswith(user_data):
return -1
elif not val1.startswith(user_data) and val2.startswith(user_data):
return 1
else:
return cmp(val1, val2)
def include_item_sort_func(self, model, iter1, iter2):
val1 = model.get_value(iter1, RecipeListModel.COL_INC)
val2 = model.get_value(iter2, RecipeListModel.COL_INC)
return ((val1 == False) and (val2 == True))
"""
Create, if required, and return a filtered gtk.TreeModelSort
containing only the items specified by filter
containing only the items which are items specified by filter
"""
def tree_model(self, filter, excluded_items_ahead=False, included_items_ahead=False, search_data=None, initial=False):
def tree_model(self, filter, excluded_items_ahead=False, included_items_ahead=True):
model = self.filter_new()
self.filtered_nb = 0
model.set_visible_func(self.tree_model_filter, filter)
sort = gtk.TreeModelSort(model)
sort.connect ('sort-column-changed', self.sort_column_changed_cb)
if initial:
if excluded_items_ahead:
sort.set_default_sort_func(self.exclude_item_sort_func)
elif included_items_ahead:
sort.set_default_sort_func(self.include_item_sort_func)
else:
sort.set_sort_column_id(RecipeListModel.COL_NAME, gtk.SORT_ASCENDING)
sort.set_default_sort_func(None)
elif excluded_items_ahead:
sort.set_default_sort_func(self.exclude_item_sort_func, search_data)
elif included_items_ahead:
sort.set_default_sort_func(self.include_item_sort_func, search_data)
else:
if search_data and search_data!='Search recipes by name' and search_data!='Search package groups by name':
sort.set_default_sort_func(self.sort_func, search_data)
else:
sort.set_sort_column_id(self.sort_column_id, self.sort_order)
sort.set_default_sort_func(None)
sort.set_sort_func(RecipeListModel.COL_INC, self.sort_column, RecipeListModel.COL_INC)
sort.set_sort_func(RecipeListModel.COL_GROUP, self.sort_column, RecipeListModel.COL_GROUP)
sort.set_sort_func(RecipeListModel.COL_BINB, self.sort_binb_column)
sort.set_sort_func(RecipeListModel.COL_LIC, self.sort_column, RecipeListModel.COL_LIC)
return sort
def sort_column_changed_cb (self, data):
self.sort_column_id, self.sort_order = data.get_sort_column_id ()
def sort_column(self, model, row1, row2, col):
value1 = model.get_value(row1, col)
value2 = model.get_value(row2, col)
cmp_res = cmp(value1, value2)
if cmp_res!=0:
if col==RecipeListModel.COL_INC:
return -cmp_res
else:
return cmp_res
else:
name1 = model.get_value(row1, RecipeListModel.COL_NAME)
name2 = model.get_value(row2, RecipeListModel.COL_NAME)
return cmp(name1,name2)
def sort_binb_column(self, model, row1, row2):
value1 = model.get_value(row1, RecipeListModel.COL_BINB)
value2 = model.get_value(row2, RecipeListModel.COL_BINB)
value1_list = value1.split(', ')
value2_list = value2.split(', ')
value1 = value1_list[0]
value2 = value2_list[0]
cmp_res = cmp(value1, value2)
if cmp_res==0:
cmp_size = cmp(len(value1_list), len(value2_list))
if cmp_size==0:
name1 = model.get_value(row1, RecipeListModel.COL_NAME)
name2 = model.get_value(row2, RecipeListModel.COL_NAME)
return cmp(name1,name2)
else:
return cmp_size
else:
return cmp_res
def convert_vpath_to_path(self, view_model, view_path):
filtered_model_path = view_model.convert_path_to_child_path(view_path)
filtered_model = view_model.get_model()
@@ -684,9 +583,7 @@ class RecipeListModel(gtk.ListStore):
self.COL_LIC, "", self.COL_GROUP, "",
self.COL_DEPS, "", self.COL_BINB, "",
self.COL_TYPE, "image", self.COL_INC, False,
self.COL_IMG, False, self.COL_INSTALL, "", self.COL_PN, self.__custom_image__,
self.COL_SUMMARY, "", self.COL_VERSION, "", self.COL_REVISION, "",
self.COL_HOMEPAGE, "", self.COL_BUGTRACKER, "")
self.COL_IMG, False, self.COL_INSTALL, "", self.COL_PN, self.__custom_image__)
for item in event_model["pn"]:
name = item
@@ -694,11 +591,6 @@ class RecipeListModel(gtk.ListStore):
lic = event_model["pn"][item]["license"]
group = event_model["pn"][item]["section"]
inherits = event_model["pn"][item]["inherits"]
summary = event_model["pn"][item]["summary"]
version = event_model["pn"][item]["version"]
revision = event_model["pn"][item]["revision"]
homepage = event_model["pn"][item]["homepage"]
bugtracker = event_model["pn"][item]["bugtracker"]
install = []
depends = event_model["depends"].get(item, []) + event_model["rdepends-pn"].get(item, [])
@@ -720,9 +612,7 @@ class RecipeListModel(gtk.ListStore):
self.COL_LIC, lic, self.COL_GROUP, group,
self.COL_DEPS, " ".join(depends), self.COL_BINB, "",
self.COL_TYPE, atype, self.COL_INC, False,
self.COL_IMG, False, self.COL_INSTALL, " ".join(install), self.COL_PN, item,
self.COL_SUMMARY, summary, self.COL_VERSION, version, self.COL_REVISION, revision,
self.COL_HOMEPAGE, homepage, self.COL_BUGTRACKER, bugtracker)
self.COL_IMG, False, self.COL_INSTALL, " ".join(install), self.COL_PN, item)
self.pn_path = {}
it = self.get_iter_first()
@@ -876,9 +766,3 @@ class RecipeListModel(gtk.ListStore):
binb="User Selected",
image_contents=True)
self.selection_change_notification()
def set_custom_image_version(self, version):
self.custom_image_version = version
def get_custom_image_version(self):
return self.custom_image_version

View File

@@ -44,6 +44,8 @@ class hic:
ICON_PACKAGES_HOVER_FILE = os.path.join(HOB_ICON_BASE_DIR, ('packages/packages_hover.png'))
ICON_LAYERS_DISPLAY_FILE = os.path.join(HOB_ICON_BASE_DIR, ('layers/layers_display.png'))
ICON_LAYERS_HOVER_FILE = os.path.join(HOB_ICON_BASE_DIR, ('layers/layers_hover.png'))
ICON_TEMPLATES_DISPLAY_FILE = os.path.join(HOB_ICON_BASE_DIR, ('templates/templates_display.png'))
ICON_TEMPLATES_HOVER_FILE = os.path.join(HOB_ICON_BASE_DIR, ('templates/templates_hover.png'))
ICON_IMAGES_DISPLAY_FILE = os.path.join(HOB_ICON_BASE_DIR, ('images/images_display.png'))
ICON_IMAGES_HOVER_FILE = os.path.join(HOB_ICON_BASE_DIR, ('images/images_hover.png'))
ICON_SETTINGS_DISPLAY_FILE = os.path.join(HOB_ICON_BASE_DIR, ('settings/settings_display.png'))
@@ -83,29 +85,23 @@ class HobViewTable (gtk.VBox):
gobject.TYPE_PYOBJECT,)),
}
def __init__(self, columns, name):
def __init__(self, columns):
gtk.VBox.__init__(self, False, 6)
self.table_tree = gtk.TreeView()
self.table_tree.set_headers_visible(True)
self.table_tree.set_headers_clickable(True)
self.table_tree.set_enable_search(True)
self.table_tree.set_rules_hint(True)
self.table_tree.set_enable_tree_lines(True)
self.table_tree.get_selection().set_mode(gtk.SELECTION_SINGLE)
self.toggle_columns = []
self.table_tree.connect("row-activated", self.row_activated_cb)
self.top_bar = None
self.tab_name = name
for i, column in enumerate(columns):
col_name = column['col_name']
col = gtk.TreeViewColumn(col_name)
col = gtk.TreeViewColumn(column['col_name'])
col.set_clickable(True)
col.set_resizable(True)
if self.tab_name.startswith('Included'):
if col_name!='Included':
col.set_sort_column_id(column['col_id'])
else:
col.set_sort_column_id(column['col_id'])
col.set_sort_column_id(column['col_id'])
if 'col_min' in column.keys():
col.set_min_width(column['col_min'])
if 'col_max' in column.keys():
@@ -128,7 +124,7 @@ class HobViewTable (gtk.VBox):
self.toggle_id = i
col.pack_end(cell, True)
col.set_attributes(cell, active=column['col_id'])
self.toggle_columns.append(col_name)
self.toggle_columns.append(column['col_name'])
if 'col_group' in column.keys():
col.set_cell_data_func(cell, self.set_group_number_cb)
elif column['col_style'] == 'radio toggle':
@@ -139,7 +135,7 @@ class HobViewTable (gtk.VBox):
self.toggle_id = i
col.pack_end(cell, True)
col.set_attributes(cell, active=column['col_id'])
self.toggle_columns.append(col_name)
self.toggle_columns.append(column['col_name'])
elif column['col_style'] == 'binb':
cell = gtk.CellRendererText()
col.pack_start(cell, True)
@@ -147,42 +143,10 @@ class HobViewTable (gtk.VBox):
if 'col_t_id' in column.keys():
col.add_attribute(cell, 'font', column['col_t_id'])
self.scroll = gtk.ScrolledWindow()
self.scroll.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
self.scroll.add(self.table_tree)
self.pack_end(self.scroll, True, True, 0)
def add_no_result_bar(self, entry):
color = HobColors.KHAKI
self.top_bar = gtk.EventBox()
self.top_bar.set_size_request(-1, 70)
self.top_bar.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(color))
self.top_bar.set_flags(gtk.CAN_DEFAULT)
self.top_bar.grab_default()
no_result_tab = gtk.Table(5, 20, True)
self.top_bar.add(no_result_tab)
label = gtk.Label()
label.set_alignment(0.0, 0.5)
title = "No results matching your search"
label.set_markup("<span size='x-large'><b>%s</b></span>" % title)
no_result_tab.attach(label, 1, 14, 1, 4)
clear_button = HobButton("Clear search")
clear_button.set_tooltip_text("Clear search query")
clear_button.connect('clicked', self.set_search_entry_clear_cb, entry)
no_result_tab.attach(clear_button, 16, 19, 1, 4)
self.pack_start(self.top_bar, False, True, 12)
self.top_bar.show_all()
def set_search_entry_clear_cb(self, button, search):
if search.get_editable() == True:
search.set_text("")
search.set_icon_sensitive(gtk.ENTRY_ICON_SECONDARY, False)
search.grab_focus()
scroll = gtk.ScrolledWindow()
scroll.set_policy(gtk.POLICY_NEVER, gtk.POLICY_ALWAYS)
scroll.add(self.table_tree)
self.pack_start(scroll, True, True, 0)
def display_binb_cb(self, col, cell, model, it, col_id):
binb = model.get_value(it, col_id)
@@ -191,15 +155,9 @@ class HobViewTable (gtk.VBox):
bin = binb.split(', ')
total_no = len(bin)
if total_no > 1 and bin[0] == "User Selected":
if total_no > 2:
present_binb = bin[1] + ' (+' + str(total_no - 1) + ')'
else:
present_binb = bin[1]
present_binb = bin[1] + ' (+' + str(total_no) + ')'
else:
if total_no > 1:
present_binb = bin[0] + ' (+' + str(total_no - 1) + ')'
else:
present_binb = bin[0]
present_binb = bin[0] + ' (+' + str(total_no) + ')'
cell.set_property('text', present_binb)
else:
cell.set_property('text', "")
@@ -208,6 +166,10 @@ class HobViewTable (gtk.VBox):
def set_model(self, tree_model):
self.table_tree.set_model(tree_model)
def set_search_entry(self, search_column_id, entry):
self.table_tree.set_search_column(search_column_id)
self.table_tree.set_search_entry(entry)
def toggle_default(self):
model = self.table_tree.get_model()
if not model:
@@ -379,13 +341,18 @@ class HobInfoButton(gtk.EventBox):
hic.ICON_INFO_DISPLAY_FILE)
self.image.show()
self.add(self.image)
self.tip_markup = tip_markup
self.my_parent = parent
self.set_events(gtk.gdk.BUTTON_RELEASE |
gtk.gdk.ENTER_NOTIFY_MASK |
gtk.gdk.LEAVE_NOTIFY_MASK)
self.ptip = PersistentTooltip(tip_markup)
if parent:
self.ptip.set_parent(parent)
self.ptip.set_transient_for(parent)
self.ptip.set_destroy_with_parent(True)
self.connect("button-release-event", self.button_release_cb)
self.connect("enter-notify-event", self.mouse_in_cb)
self.connect("leave-notify-event", self.mouse_out_cb)
@@ -395,18 +362,7 @@ class HobInfoButton(gtk.EventBox):
PersistentTooltip
"""
def button_release_cb(self, widget, event):
from bb.ui.crumbs.hig.propertydialog import PropertyDialog
self.dialog = PropertyDialog(title = '',
parent = self.my_parent,
information = self.tip_markup,
flags = gtk.DIALOG_DESTROY_WITH_PARENT
| gtk.DIALOG_NO_SEPARATOR)
button = self.dialog.add_button("Close", gtk.RESPONSE_CANCEL)
HobAltButton.style_button(button)
button.connect("clicked", lambda w: self.dialog.destroy())
self.dialog.show_all()
self.dialog.run()
self.ptip.show()
"""
Change to the prelight image when the mouse enters the widget
@@ -487,8 +443,7 @@ class HobNotebook(gtk.Notebook):
self.pages = []
self.search = None
self.search_focus = False
self.page_changed = False
self.search_name = ""
self.connect("switch-page", self.page_changed_cb)
@@ -501,10 +456,6 @@ class HobNotebook(gtk.Notebook):
else:
lbl.set_active(False)
if self.search:
self.page_changed = True
self.reset_entry(self.search, page_num)
def append_page(self, child, tab_label, tab_tooltip=None):
label = HobTabLabel(tab_label)
if tab_tooltip:
@@ -513,22 +464,16 @@ class HobNotebook(gtk.Notebook):
self.pages.append(label)
gtk.Notebook.append_page(self, child, label)
def set_entry(self, names, tips):
def set_entry(self, name="Search:"):
self.search = gtk.Entry()
self.search_names = names
self.search_tips = tips
self.search_name = name
style = self.search.get_style()
style.text[gtk.STATE_NORMAL] = self.get_colormap().alloc_color(HobColors.GRAY, False, False)
self.search.set_style(style)
self.search.set_text(names[0])
self.search.set_tooltip_text(self.search_tips[0])
self.search.props.has_tooltip = True
self.search.set_text(name)
self.search.set_editable(False)
self.search.set_icon_from_stock(gtk.ENTRY_ICON_SECONDARY, gtk.STOCK_CLEAR)
self.search.set_icon_sensitive(gtk.ENTRY_ICON_SECONDARY, False)
self.search.connect("icon-release", self.set_search_entry_clear_cb)
self.search.set_width_chars(30)
self.search.show()
self.search.connect("focus-in-event", self.set_search_entry_editable_cb)
@@ -546,42 +491,31 @@ class HobNotebook(gtk.Notebook):
child.set_count(0)
def set_search_entry_editable_cb(self, search, event):
self.search_focus = True
search.set_editable(True)
text = search.get_text()
if text in self.search_names:
search.set_text("")
search.set_text("")
style = self.search.get_style()
style.text[gtk.STATE_NORMAL] = self.get_colormap().alloc_color(HobColors.BLACK, False, False)
search.set_style(style)
def set_search_entry_reset_cb(self, search, event):
page_num = self.get_current_page()
text = search.get_text()
if not text:
self.reset_entry(search, page_num)
def reset_entry(self, entry, page_num):
def reset_entry(self, entry):
style = entry.get_style()
style.text[gtk.STATE_NORMAL] = self.get_colormap().alloc_color(HobColors.GRAY, False, False)
entry.set_style(style)
entry.set_text(self.search_names[page_num])
entry.set_tooltip_text(self.search_tips[page_num])
entry.set_text(self.search_name)
entry.set_editable(False)
entry.set_icon_sensitive(gtk.ENTRY_ICON_SECONDARY, False)
def set_search_entry_reset_cb(self, search, event):
self.reset_entry(search)
def set_search_entry_clear_cb(self, search, icon_pos, event):
if search.get_editable() == True:
search.set_text("")
search.set_icon_sensitive(gtk.ENTRY_ICON_SECONDARY, False)
search.grab_focus()
def set_page(self, title):
for child in self.pages:
if child.lbl.get_label() == title:
child.grab_focus()
self.set_current_page(self.pages.index(child))
return
self.set_current_page(self.page_num(child))
class HobWarpCellRendererText(gtk.CellRendererText):
def __init__(self, col_number):

View File

@@ -45,8 +45,6 @@ class ImageConfigurationPage (HobPage):
# or by manual. If by manual, all user's recipe selection and package selection are
# cleared.
self.machine_combo_changed_by_manual = True
self.stopping = False
self.warning_shift = 0
self.create_visual_elements()
def create_visual_elements(self):
@@ -55,6 +53,12 @@ class ImageConfigurationPage (HobPage):
self.toolbar.set_orientation(gtk.ORIENTATION_HORIZONTAL)
self.toolbar.set_style(gtk.TOOLBAR_BOTH)
template_button = self.append_toolbar_button(self.toolbar,
"Templates",
hic.ICON_TEMPLATES_DISPLAY_FILE,
hic.ICON_TEMPLATES_HOVER_FILE,
"Load a previously saved template",
self.template_button_clicked_cb)
my_images_button = self.append_toolbar_button(self.toolbar,
"Images",
hic.ICON_IMAGES_DISPLAY_FILE,
@@ -110,10 +114,9 @@ class ImageConfigurationPage (HobPage):
self.show_all()
def update_progress_bar(self, title, fraction, status=None):
if self.stopping == False:
self.progress_bar.update(fraction)
self.progress_bar.set_text(title)
self.progress_bar.set_rcstyle(status)
self.progress_bar.update(fraction)
self.progress_bar.set_title(title)
self.progress_bar.set_rcstyle(status)
def show_info_populating(self):
self._pack_components(pack_config_build_button = False)
@@ -136,42 +139,6 @@ class ImageConfigurationPage (HobPage):
if self.builder.recipe_model.get_selected_image() == self.builder.recipe_model.__custom_image__:
self.just_bake_button.hide()
def add_warnings_bar(self):
#create the warnings bar shown when recipes parsing generates warnings
color = HobColors.KHAKI
warnings_bar = gtk.EventBox()
warnings_bar.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(color))
warnings_bar.set_flags(gtk.CAN_DEFAULT)
warnings_bar.grab_default()
build_stop_tab = gtk.Table(10, 20, True)
warnings_bar.add(build_stop_tab)
icon = gtk.Image()
icon_pix_buffer = gtk.gdk.pixbuf_new_from_file(hic.ICON_INDI_ALERT_FILE)
icon.set_from_pixbuf(icon_pix_buffer)
build_stop_tab.attach(icon, 0, 2, 0, 10)
label = gtk.Label()
label.set_alignment(0.0, 0.5)
warnings_nb = len(self.builder.parsing_warnings)
if warnings_nb == 1:
label.set_markup("<span size='x-large'><b>1 recipe parsing warning</b></span>")
else:
label.set_markup("<span size='x-large'><b>%s recipe parsing warnings</b></span>" % warnings_nb)
build_stop_tab.attach(label, 2, 12, 0, 10)
view_warnings_button = HobButton("View warnings")
view_warnings_button.connect('clicked', self.view_warnings_button_clicked_cb)
build_stop_tab.attach(view_warnings_button, 15, 19, 1, 9)
return warnings_bar
def disable_warnings_bar(self):
if self.builder.parsing_warnings:
self.warnings_bar.hide_all()
self.builder.parsing_warnings = []
def create_config_machine(self):
self.machine_title = gtk.Label()
self.machine_title.set_alignment(0.0, 0.5)
@@ -198,7 +165,8 @@ class ImageConfigurationPage (HobPage):
markup += "For more on layers, check the <a href=\""
markup += "http://www.yoctoproject.org/docs/current/dev-manual/"
markup += "dev-manual.html#understanding-and-using-layers\">reference manual</a>."
self.layer_info_icon = HobInfoButton("<b>Layers</b>" + "*" + markup, self.get_parent())
self.layer_info_icon = HobInfoButton(markup, self.get_parent())
# self.progress_box = gtk.HBox(False, 6)
self.progress_bar = HobProgressBar()
# self.progress_box.pack_start(self.progress_bar, expand=True, fill=True)
@@ -217,12 +185,6 @@ class ImageConfigurationPage (HobPage):
#self.gtable.attach(self.progress_box, 0, 40, 15, 18)
self.gtable.attach(self.progress_bar, 0, 37, 15, 18)
self.gtable.attach(self.stop_button, 37, 40, 15, 18, 0, 0)
if self.builder.parsing_warnings:
self.warnings_bar = self.add_warnings_bar()
self.gtable.attach(self.warnings_bar, 0, 40, 14, 18)
self.warning_shift = 4
else:
self.warning_shift = 0
self.gtable.attach(self.machine_separator, 0, 40, 13, 14)
def create_config_baseimg(self):
@@ -258,12 +220,12 @@ class ImageConfigurationPage (HobPage):
self.image_separator = gtk.HSeparator()
def set_config_baseimg_layout(self):
self.gtable.attach(self.image_title, 0, 40, 15+self.warning_shift, 17+self.warning_shift)
self.gtable.attach(self.image_title_desc, 0, 40, 18+self.warning_shift, 22+self.warning_shift)
self.gtable.attach(self.image_combo, 0, 12, 23+self.warning_shift, 26+self.warning_shift)
self.gtable.attach(self.image_desc, 0, 12, 27+self.warning_shift, 33+self.warning_shift)
self.gtable.attach(self.view_adv_configuration_button, 14, 36, 23+self.warning_shift, 28+self.warning_shift)
self.gtable.attach(self.image_separator, 0, 40, 35+self.warning_shift, 36+self.warning_shift)
self.gtable.attach(self.image_title, 0, 40, 15, 17)
self.gtable.attach(self.image_title_desc, 0, 40, 18, 22)
self.gtable.attach(self.image_combo, 0, 12, 23, 26)
self.gtable.attach(self.image_desc, 0, 12, 27, 33)
self.gtable.attach(self.view_adv_configuration_button, 14, 36, 23, 28)
self.gtable.attach(self.image_separator, 0, 40, 35, 36)
def create_config_build_button(self):
# Create the "Build packages" and "Build image" buttons at the bottom
@@ -286,17 +248,9 @@ class ImageConfigurationPage (HobPage):
return button_box
def stop_button_clicked_cb(self, button):
self.stopping = True
self.progress_bar.set_text("Stopping recipe parsing")
self.progress_bar.set_rcstyle("stop")
self.builder.cancel_parse_sync()
def view_warnings_button_clicked_cb(self, button):
self.builder.show_warning_dialog()
def machine_combo_changed_cb(self, machine_combo):
self.stopping = False
self.builder.parsing_warnings = []
combo_item = machine_combo.get_active_text()
if not combo_item or combo_item == self.__dummy_machine__:
return
@@ -317,7 +271,6 @@ class ImageConfigurationPage (HobPage):
self.builder.populate_recipe_package_info_async()
def update_machine_combo(self):
self.disable_warnings_bar()
all_machines = [self.__dummy_machine__] + self.builder.parameters.all_machines
model = self.machine_combo.get_model()
@@ -327,7 +280,6 @@ class ImageConfigurationPage (HobPage):
self.machine_combo.set_active(0)
def switch_machine_combo(self):
self.disable_warnings_bar()
self.machine_combo_changed_by_manual = False
model = self.machine_combo.get_model()
active = 0
@@ -405,7 +357,7 @@ class ImageConfigurationPage (HobPage):
image_model = recipe_model.tree_model(filter)
image_model.set_sort_column_id(recipe_model.COL_NAME, gtk.SORT_ASCENDING)
active = 0
cnt = 0
cnt = 1
white_pattern = []
if self.builder.parameters.image_white_pattern:
@@ -423,10 +375,7 @@ class ImageConfigurationPage (HobPage):
model = self.image_combo.get_model()
model.clear()
# Set a indicator text to combo store when first open
if not selected_image:
self.image_combo.append_text(self.__dummy_image__)
cnt = cnt + 1
self.image_combo.append_text(self.__dummy_image__)
# append and set active
while it:
path = image_model.get_path(it)
@@ -480,13 +429,18 @@ class ImageConfigurationPage (HobPage):
self.builder.reparse_post_adv_settings()
def just_bake_button_clicked_cb(self, button):
self.builder.parsing_warnings = []
self.builder.just_bake()
def edit_image_button_clicked_cb(self, button):
self.builder.configuration.initial_selected_image = self.builder.configuration.selected_image
self.builder.show_recipes()
def template_button_clicked_cb(self, button):
response, path = self.builder.show_load_template_dialog()
if not response:
return
if path:
self.builder.load_template(path)
def my_images_button_clicked_cb(self, button):
self.builder.show_load_my_images_dialog()

View File

@@ -26,8 +26,7 @@ from bb.ui.crumbs.hobcolor import HobColors
from bb.ui.crumbs.hobwidget import hic, HobViewTable, HobAltButton, HobButton
from bb.ui.crumbs.hobpages import HobPage
import subprocess
from bb.ui.crumbs.hig.crumbsdialog import CrumbsDialog
from bb.ui.crumbs.hig import CrumbsDialog
#
# ImageDetailsPage
#
@@ -197,6 +196,12 @@ class ImageDetailsPage (HobPage):
self.toolbar.set_orientation(gtk.ORIENTATION_HORIZONTAL)
self.toolbar.set_style(gtk.TOOLBAR_BOTH)
template_button = self.append_toolbar_button(self.toolbar,
"Templates",
hic.ICON_TEMPLATES_DISPLAY_FILE,
hic.ICON_TEMPLATES_HOVER_FILE,
"Load a previously saved template",
self.template_button_clicked_cb)
my_images_button = self.append_toolbar_button(self.toolbar,
"Images",
hic.ICON_IMAGES_DISPLAY_FILE,
@@ -259,7 +264,11 @@ class ImageDetailsPage (HobPage):
self.build_result = self.BuildDetailBox(varlist=varlist, vallist=vallist, icon=icon, color=color)
self.box_group_area.pack_start(self.build_result, expand=False, fill=False)
self.buttonlist = ["Build new image", "Run image", "Deploy image"]
# create the buttons at the bottom first because the buttons are used in apply_button_per_image()
if self.build_succeeded:
self.buttonlist = ["Build new image", "Save as template", "Run image", "Deploy image"]
else: # get to this page from "My images"
self.buttonlist = ["Build new image", "Run image", "Deploy image"]
# Name
self.image_store = []
@@ -369,8 +378,6 @@ class ImageDetailsPage (HobPage):
vallist = []
vallist.append(pkg_num)
vallist.append(default_image_size)
self.builder.configuration.image_size = default_image_size
self.builder.configuration.image_packages = self.builder.configuration.selected_packages
if self.build_succeeded:
edit_packages_button = HobAltButton("Edit packages")
edit_packages_button.set_tooltip_text("Edit the packages included in your image")
@@ -397,8 +404,7 @@ class ImageDetailsPage (HobPage):
def open_log_clicked_cb(self, button, log_file):
if log_file:
log_file = "file:///" + log_file
gtk.show_uri(screen=button.get_screen(), uri=log_file, timestamp=0)
os.system("xdg-open /%s" % log_file)
def refresh_package_detail_box(self, image_size):
self.package_detail.update_line_widgets("Total image size: ", image_size)
@@ -574,6 +580,26 @@ class ImageDetailsPage (HobPage):
created = True
is_runnable = True
name = "Save as template"
if name in buttonlist:
if created == True:
# separator
#label = gtk.Label(" or ")
#self.details_bottom_buttons.pack_end(label, expand=False, fill=False)
# create button "Save as template"
save_button = HobAltButton("Save as template")
else:
save_button = HobButton("Save as template")
#save_button.set_size_request(205, 49)
save_button.set_flags(gtk.CAN_DEFAULT)
packed = True
save_button.set_tooltip_text("Save the image configuration for reuse")
button_id = save_button.connect("clicked", self.save_button_clicked_cb)
self.button_ids[button_id] = save_button
self.details_bottom_buttons.pack_end(save_button, expand=False, fill=False)
create = True
name = "Build new image"
if name in buttonlist:
# create button "Build new image"
@@ -590,6 +616,9 @@ class ImageDetailsPage (HobPage):
return is_runnable
def save_button_clicked_cb(self, button):
self.builder.show_save_template_dialog()
def deploy_button_clicked_cb(self, button):
if self.toggled_image:
if self.num_toggled > 1:
@@ -617,6 +646,13 @@ class ImageDetailsPage (HobPage):
def edit_packages_button_clicked_cb(self, button):
self.builder.show_packages(ask=False)
def template_button_clicked_cb(self, button):
response, path = self.builder.show_load_template_dialog()
if not response:
return
if path:
self.builder.load_template(path)
def my_images_button_clicked_cb(self, button):
self.builder.show_load_my_images_dialog()

View File

@@ -34,12 +34,10 @@ class PackageSelectionPage (HobPage):
pages = [
{
'name' : 'Included packages',
'tooltip' : 'The packages currently included for your image',
'filter' : { PackageListModel.COL_INC : [True] },
'search' : 'Search packages by name',
'searchtip' : 'Enter a package name to find it',
'columns' : [{
'name' : 'Included packages',
'tooltip' : 'The packages currently included for your image',
'filter' : { PackageListModel.COL_INC : [True] },
'columns' : [{
'col_name' : 'Package name',
'col_id' : PackageListModel.COL_NAME,
'col_style': 'text',
@@ -54,14 +52,7 @@ class PackageSelectionPage (HobPage):
'col_max' : 300,
'expand' : 'True'
}, {
'col_name' : 'Recipe',
'col_id' : PackageListModel.COL_RCP,
'col_style': 'text',
'col_min' : 100,
'col_max' : 250,
'expand' : 'True'
}, {
'col_name' : 'Brought in by (+others)',
'col_name' : 'Brought in by',
'col_id' : PackageListModel.COL_BINB,
'col_style': 'binb',
'col_min' : 100,
@@ -75,12 +66,10 @@ class PackageSelectionPage (HobPage):
'col_max' : 100
}]
}, {
'name' : 'All packages',
'tooltip' : 'All packages that have been built',
'filter' : {},
'search' : 'Search packages by name',
'searchtip' : 'Enter a package name to find it',
'columns' : [{
'name' : 'All packages',
'tooltip' : 'All packages that have been built',
'filter' : {},
'columns' : [{
'col_name' : 'Package name',
'col_id' : PackageListModel.COL_NAME,
'col_style': 'text',
@@ -94,13 +83,6 @@ class PackageSelectionPage (HobPage):
'col_min' : 100,
'col_max' : 500,
'expand' : 'True'
}, {
'col_name' : 'Recipe',
'col_id' : PackageListModel.COL_RCP,
'col_style': 'text',
'col_min' : 100,
'col_max' : 250,
'expand' : 'True'
}, {
'col_name' : 'Included',
'col_id' : PackageListModel.COL_INC,
@@ -117,7 +99,7 @@ class PackageSelectionPage (HobPage):
def __init__(self, builder):
super(PackageSelectionPage, self).__init__(builder, "Edit packages")
# set invisible members
# set invisiable members
self.recipe_model = self.builder.recipe_model
self.package_model = self.builder.package_model
@@ -136,27 +118,26 @@ class PackageSelectionPage (HobPage):
# set visible members
self.ins = HobNotebook()
self.tables = [] # we need to modify table when the dialog is shown
search_names = []
search_tips = []
# append the tab
for page in self.pages:
columns = page['columns']
name = page['name']
tab = HobViewTable(columns, name)
search_names.append(page['search'])
search_tips.append(page['searchtip'])
tab = HobViewTable(columns)
filter = page['filter']
sort_model = self.package_model.tree_model(filter, initial=True)
tab.set_model(sort_model)
tab.connect("toggled", self.table_toggled_cb, name)
tab.connect("button-release-event", self.button_click_cb)
tab.connect("cell-fadeinout-stopped", self.after_fadeout_checkin_include, filter)
tab.set_model(self.package_model.tree_model(filter))
tab.connect("toggled", self.table_toggled_cb, page['name'])
if page['name'] == "Included packages":
tab.connect("button-release-event", self.button_click_cb)
tab.connect("cell-fadeinout-stopped", self.after_fadeout_checkin_include)
self.ins.append_page(tab, page['name'], page['tooltip'])
self.tables.append(tab)
self.ins.set_entry(search_names, search_tips)
self.ins.search.connect("changed", self.search_entry_changed)
self.ins.set_entry("Search packages:")
# set the search entry for each table
for tab in self.tables:
search_tip = "Enter a package name to find it"
self.ins.search.set_tooltip_text(search_tip)
self.ins.search.props.has_tooltip = True
tab.set_search_entry(0, self.ins.search)
# add all into the dialog
self.box_group_area.pack_start(self.ins, expand=True, fill=True)
@@ -176,54 +157,17 @@ class PackageSelectionPage (HobPage):
self.back_button.connect("clicked", self.back_button_clicked_cb)
self.button_box.pack_end(self.back_button, expand=False, fill=False)
def search_entry_changed(self, entry):
text = entry.get_text()
if self.ins.search_focus:
self.ins.search_focus = False
elif self.ins.page_changed:
self.ins.page_change = False
self.filter_search(entry)
elif text not in self.ins.search_names:
self.filter_search(entry)
def filter_search(self, entry):
text = entry.get_text()
current_tab = self.ins.get_current_page()
filter = self.pages[current_tab]['filter']
filter[PackageListModel.COL_NAME] = text
self.tables[current_tab].set_model(self.package_model.tree_model(filter, search_data=text))
if self.package_model.filtered_nb == 0:
if not self.ins.get_nth_page(current_tab).top_bar:
self.ins.get_nth_page(current_tab).add_no_result_bar(entry)
self.ins.get_nth_page(current_tab).top_bar.set_no_show_all(True)
self.ins.get_nth_page(current_tab).top_bar.show()
self.ins.get_nth_page(current_tab).scroll.hide()
else:
if self.ins.get_nth_page(current_tab).top_bar:
self.ins.get_nth_page(current_tab).top_bar.hide()
self.ins.get_nth_page(current_tab).scroll.show()
if entry.get_text() == '':
entry.set_icon_sensitive(gtk.ENTRY_ICON_SECONDARY, False)
else:
entry.set_icon_sensitive(gtk.ENTRY_ICON_SECONDARY, True)
def button_click_cb(self, widget, event):
path, col = widget.table_tree.get_cursor()
tree_model = widget.table_tree.get_model()
if path and col.get_title() != 'Included': # else activation is likely a removal
properties = {'binb': '' , 'name': '', 'size':'', 'recipe':'', 'files_list':''}
properties['binb'] = tree_model.get_value(tree_model.get_iter(path), PackageListModel.COL_BINB)
properties['name'] = tree_model.get_value(tree_model.get_iter(path), PackageListModel.COL_NAME)
properties['size'] = tree_model.get_value(tree_model.get_iter(path), PackageListModel.COL_SIZE)
properties['recipe'] = tree_model.get_value(tree_model.get_iter(path), PackageListModel.COL_RCP)
properties['files_list'] = tree_model.get_value(tree_model.get_iter(path), PackageListModel.COL_FLIST)
self.builder.show_recipe_property_dialog(properties)
if path: # else activation is likely a removal
binb = tree_model.get_value(tree_model.get_iter(path), PackageListModel.COL_BINB)
if binb:
self.builder.show_binb_dialog(binb)
def open_log_clicked_cb(self, button, log_file):
if log_file:
log_file = "file:///" + log_file
gtk.show_uri(screen=button.get_screen(), uri=log_file, timestamp=0)
os.system("xdg-open /%s" % log_file)
def show_page(self, log_file):
children = self.button_box.get_children() or []
@@ -240,16 +184,8 @@ class PackageSelectionPage (HobPage):
self.show_all()
def build_image_clicked_cb(self, button):
self.builder.parsing_warnings = []
self.builder.build_image()
def refresh_tables(self):
self.ins.reset_entry(self.ins.search, 0)
for tab in self.tables:
index = self.tables.index(tab)
filter = self.pages[index]['filter']
tab.set_model(self.package_model.tree_model(filter, initial=True))
def back_button_clicked_cb(self, button):
if self.builder.previous_step == self.builder.IMAGE_GENERATED:
self.builder.restore_initial_selected_packages()
@@ -257,26 +193,28 @@ class PackageSelectionPage (HobPage):
self.builder.show_image_details()
else:
self.builder.show_configuration()
self.refresh_tables()
def _expand_all(self):
for tab in self.tables:
tab.table_tree.expand_all()
def refresh_selection(self):
self._expand_all()
self.builder.configuration.selected_packages = self.package_model.get_selected_packages()
self.builder.configuration.user_selected_packages = self.package_model.get_user_selected_packages()
selected_packages_num = len(self.builder.configuration.selected_packages)
selected_packages_size = self.package_model.get_packages_size()
selected_packages_size_str = HobPage._size_to_string(selected_packages_size)
if self.builder.configuration.image_packages == self.builder.configuration.selected_packages:
image_total_size_str = self.builder.configuration.image_size
else:
image_overhead_factor = self.builder.configuration.image_overhead_factor
image_rootfs_size = self.builder.configuration.image_rootfs_size / 1024 # image_rootfs_size is KB
image_extra_size = self.builder.configuration.image_extra_size / 1024 # image_extra_size is KB
base_size = image_overhead_factor * selected_packages_size
image_total_size = max(base_size, image_rootfs_size) + image_extra_size
if "zypper" in self.builder.configuration.selected_packages:
image_total_size += (51200 * 1024)
image_total_size_str = HobPage._size_to_string(image_total_size)
image_overhead_factor = self.builder.configuration.image_overhead_factor
image_rootfs_size = self.builder.configuration.image_rootfs_size * 1024 # image_rootfs_size is KB
image_extra_size = self.builder.configuration.image_extra_size * 1024 # image_extra_size is KB
base_size = image_overhead_factor * selected_packages_size
image_total_size = max(base_size, image_rootfs_size) + image_extra_size
if "zypper" in self.builder.configuration.selected_packages:
image_total_size += (51200 * 1024)
image_total_size_str = HobPage._size_to_string(image_total_size)
self.label.set_label("Packages included: %s\nSelected packages size: %s\nTotal image size: %s" %
(selected_packages_num, selected_packages_size_str, image_total_size_str))
@@ -286,21 +224,20 @@ class PackageSelectionPage (HobPage):
if not self.package_model.path_included(path):
self.package_model.include_item(item_path=path, binb="User Selected")
else:
self.pre_fadeout_checkout_include(view_tree)
self.package_model.exclude_item(item_path=path)
self.render_fadeout(view_tree, cell)
if pagename == "Included packages":
self.pre_fadeout_checkout_include(view_tree)
self.package_model.exclude_item(item_path=path)
self.render_fadeout(view_tree, cell)
else:
self.package_model.exclude_item(item_path=path)
self.refresh_selection()
if not self.builder.customized:
self.builder.customized = True
self.builder.configuration.initial_selected_image = self.builder.configuration.selected_image
self.builder.configuration.selected_image = self.recipe_model.__custom_image__
self.builder.rcppkglist_populated()
self.builder.window_sensitive(True)
view_model = view_tree.get_model()
vpath = self.package_model.convert_path_to_vpath(view_model, path)
view_tree.set_cursor(vpath)
def table_toggled_cb(self, table, cell, view_path, toggled_columnid, view_tree, pagename):
# Click to include a package
@@ -310,15 +247,11 @@ class PackageSelectionPage (HobPage):
glib.idle_add(self.toggle_item_idle_cb, path, view_tree, cell, pagename)
def pre_fadeout_checkout_include(self, tree):
#after the fadeout the table will be sorted as before
self.sort_column_id = self.package_model.sort_column_id
self.sort_order = self.package_model.sort_order
self.package_model.resync_fadeout_column(self.package_model.get_iter_first())
# Check out a model which base on the column COL_FADE_INC,
# it's save the prev state of column COL_INC before do exclude_item
filter = { PackageListModel.COL_FADE_INC : [True]}
new_model = self.package_model.tree_model(filter, excluded_items_ahead=True)
new_model = self.package_model.tree_model(filter)
tree.set_model(new_model)
tree.expand_all()
@@ -344,10 +277,8 @@ class PackageSelectionPage (HobPage):
cell.fadeout(tree, 1000, to_render_cells)
def after_fadeout_checkin_include(self, table, ctrl, cell, tree, filter):
self.package_model.sort_column_id = self.sort_column_id
self.package_model.sort_order = self.sort_order
tree.set_model(self.package_model.tree_model(filter))
def after_fadeout_checkin_include(self, table, ctrl, cell, tree):
tree.set_model(self.package_model.tree_model(self.pages[0]['filter']))
tree.expand_all()
def set_packages_curr_tab(self, curr_page):

View File

@@ -43,11 +43,6 @@ class HobProgressBar (gtk.ProgressBar):
text += " %.0f%%" % self.percentage
self.set_text(text)
def set_stop_title(self, text=None):
if not text:
text = ""
self.set_text(text)
def reset(self):
self.set_fraction(0)
self.set_text("")

View File

@@ -33,13 +33,11 @@ from bb.ui.crumbs.hobpages import HobPage
class RecipeSelectionPage (HobPage):
pages = [
{
'name' : 'Included recipes',
'tooltip' : 'The recipes currently included for your image',
'filter' : { RecipeListModel.COL_INC : [True],
'name' : 'Included recipes',
'tooltip' : 'The recipes currently included for your image',
'filter' : { RecipeListModel.COL_INC : [True],
RecipeListModel.COL_TYPE : ['recipe', 'packagegroup'] },
'search' : 'Search recipes by name',
'searchtip' : 'Enter a recipe name to find it',
'columns' : [{
'columns' : [{
'col_name' : 'Recipe name',
'col_id' : RecipeListModel.COL_NAME,
'col_style': 'text',
@@ -54,7 +52,7 @@ class RecipeSelectionPage (HobPage):
'col_max' : 300,
'expand' : 'True'
}, {
'col_name' : 'Brought in by (+others)',
'col_name' : 'Brought in by',
'col_id' : RecipeListModel.COL_BINB,
'col_style': 'binb',
'col_min' : 100,
@@ -68,12 +66,10 @@ class RecipeSelectionPage (HobPage):
'col_max' : 100
}]
}, {
'name' : 'All recipes',
'tooltip' : 'All recipes in your configured layers',
'filter' : { RecipeListModel.COL_TYPE : ['recipe'] },
'search' : 'Search recipes by name',
'searchtip' : 'Enter a recipe name to find it',
'columns' : [{
'name' : 'All recipes',
'tooltip' : 'All recipes in your configured layers',
'filter' : { RecipeListModel.COL_TYPE : ['recipe'] },
'columns' : [{
'col_name' : 'Recipe name',
'col_id' : RecipeListModel.COL_NAME,
'col_style': 'text',
@@ -102,12 +98,10 @@ class RecipeSelectionPage (HobPage):
'col_max' : 100
}]
}, {
'name' : 'Package Groups',
'tooltip' : 'All package groups in your configured layers',
'filter' : { RecipeListModel.COL_TYPE : ['packagegroup'] },
'search' : 'Search package groups by name',
'searchtip' : 'Enter a package group name to find it',
'columns' : [{
'name' : 'Package Groups',
'tooltip' : 'All package groups in your configured layers',
'filter' : { RecipeListModel.COL_TYPE : ['packagegroup'] },
'columns' : [{
'col_name' : 'Package group name',
'col_id' : RecipeListModel.COL_NAME,
'col_style': 'text',
@@ -148,27 +142,26 @@ class RecipeSelectionPage (HobPage):
# set visible members
self.ins = HobNotebook()
self.tables = [] # we need modify table when the dialog is shown
search_names = []
search_tips = []
# append the tabs in order
for page in self.pages:
columns = page['columns']
name = page['name']
tab = HobViewTable(columns, name)
search_names.append(page['search'])
search_tips.append(page['searchtip'])
tab = HobViewTable(columns)
filter = page['filter']
sort_model = self.recipe_model.tree_model(filter, initial=True)
tab.set_model(sort_model)
tab.connect("toggled", self.table_toggled_cb, name)
tab.connect("button-release-event", self.button_click_cb)
tab.connect("cell-fadeinout-stopped", self.after_fadeout_checkin_include, filter)
tab.set_model(self.recipe_model.tree_model(filter))
tab.connect("toggled", self.table_toggled_cb, page['name'])
if page['name'] == "Included recipes":
tab.connect("button-release-event", self.button_click_cb)
tab.connect("cell-fadeinout-stopped", self.after_fadeout_checkin_include)
self.ins.append_page(tab, page['name'], page['tooltip'])
self.tables.append(tab)
self.ins.set_entry(search_names, search_tips)
self.ins.search.connect("changed", self.search_entry_changed)
self.ins.set_entry("Search recipes:")
# set the search entry for each table
for tab in self.tables:
search_tip = "Enter a recipe's or task's name to find it"
self.ins.search.set_tooltip_text(search_tip)
self.ins.search.props.has_tooltip = True
tab.set_search_entry(0, self.ins.search)
# add all into the window
self.box_group_area.pack_start(self.ins, expand=True, fill=True)
@@ -188,71 +181,19 @@ class RecipeSelectionPage (HobPage):
self.back_button.connect("clicked", self.back_button_clicked_cb)
button_box.pack_end(self.back_button, expand=False, fill=False)
def search_entry_changed(self, entry):
text = entry.get_text()
if self.ins.search_focus:
self.ins.search_focus = False
elif self.ins.page_changed:
self.ins.page_change = False
self.filter_search(entry)
elif text not in self.ins.search_names:
self.filter_search(entry)
def filter_search(self, entry):
text = entry.get_text()
current_tab = self.ins.get_current_page()
filter = self.pages[current_tab]['filter']
filter[RecipeListModel.COL_NAME] = text
self.tables[current_tab].set_model(self.recipe_model.tree_model(filter, search_data=text))
if self.recipe_model.filtered_nb == 0:
if not self.ins.get_nth_page(current_tab).top_bar:
self.ins.get_nth_page(current_tab).add_no_result_bar(entry)
self.ins.get_nth_page(current_tab).top_bar.set_no_show_all(True)
self.ins.get_nth_page(current_tab).top_bar.show()
self.ins.get_nth_page(current_tab).scroll.hide()
else:
if self.ins.get_nth_page(current_tab).top_bar:
self.ins.get_nth_page(current_tab).top_bar.hide()
self.ins.get_nth_page(current_tab).scroll.show()
if entry.get_text() == '':
entry.set_icon_sensitive(gtk.ENTRY_ICON_SECONDARY, False)
else:
entry.set_icon_sensitive(gtk.ENTRY_ICON_SECONDARY, True)
def button_click_cb(self, widget, event):
path, col = widget.table_tree.get_cursor()
tree_model = widget.table_tree.get_model()
if path and col.get_title() != 'Included': # else activation is likely a removal
properties = {'summary': '', 'name': '', 'version': '', 'revision': '', 'binb': '', 'group': '', 'license': '', 'homepage': '', 'bugtracker': '', 'description': ''}
properties['summary'] = tree_model.get_value(tree_model.get_iter(path), RecipeListModel.COL_SUMMARY)
properties['name'] = tree_model.get_value(tree_model.get_iter(path), RecipeListModel.COL_NAME)
properties['version'] = tree_model.get_value(tree_model.get_iter(path), RecipeListModel.COL_VERSION)
properties['revision'] = tree_model.get_value(tree_model.get_iter(path), RecipeListModel.COL_REVISION)
properties['binb'] = tree_model.get_value(tree_model.get_iter(path), RecipeListModel.COL_BINB)
properties['group'] = tree_model.get_value(tree_model.get_iter(path), RecipeListModel.COL_GROUP)
properties['license'] = tree_model.get_value(tree_model.get_iter(path), RecipeListModel.COL_LIC)
properties['homepage'] = tree_model.get_value(tree_model.get_iter(path), RecipeListModel.COL_HOMEPAGE)
properties['bugtracker'] = tree_model.get_value(tree_model.get_iter(path), RecipeListModel.COL_BUGTRACKER)
properties['description'] = tree_model.get_value(tree_model.get_iter(path), RecipeListModel.COL_DESC)
self.builder.show_recipe_property_dialog(properties)
if path: # else activation is likely a removal
binb = tree_model.get_value(tree_model.get_iter(path), RecipeListModel.COL_BINB)
if binb:
self.builder.show_binb_dialog(binb)
def build_packages_clicked_cb(self, button):
self.refresh_tables()
self.builder.build_packages()
def refresh_tables(self):
self.ins.reset_entry(self.ins.search, 0)
for tab in self.tables:
index = self.tables.index(tab)
filter = self.pages[index]['filter']
tab.set_model(self.recipe_model.tree_model(filter, search_data="", initial=True))
def back_button_clicked_cb(self, button):
self.builder.recipe_model.set_selected_image(self.builder.configuration.initial_selected_image)
self.builder.image_configuration_page.update_image_combo(self.builder.recipe_model, self.builder.configuration.initial_selected_image)
self.builder.image_configuration_page.update_image_desc()
self.builder.show_configuration()
self.refresh_tables()
def refresh_selection(self):
self.builder.configuration.selected_image = self.recipe_model.get_selected_image()
@@ -263,9 +204,12 @@ class RecipeSelectionPage (HobPage):
if not self.recipe_model.path_included(path):
self.recipe_model.include_item(item_path=path, binb="User Selected", image_contents=False)
else:
self.pre_fadeout_checkout_include(view_tree, pagename)
self.recipe_model.exclude_item(item_path=path)
self.render_fadeout(view_tree, cell)
if pagename == "Included recipes":
self.pre_fadeout_checkout_include(view_tree)
self.recipe_model.exclude_item(item_path=path)
self.render_fadeout(view_tree, cell)
else:
self.recipe_model.exclude_item(item_path=path)
self.refresh_selection()
if not self.builder.customized:
@@ -275,10 +219,6 @@ class RecipeSelectionPage (HobPage):
self.builder.window_sensitive(True)
view_model = view_tree.get_model()
vpath = self.recipe_model.convert_path_to_vpath(view_model, path)
view_tree.set_cursor(vpath)
def table_toggled_cb(self, table, cell, view_path, toggled_columnid, view_tree, pagename):
# Click to include a recipe
self.builder.window_sensitive(False)
@@ -286,11 +226,7 @@ class RecipeSelectionPage (HobPage):
path = self.recipe_model.convert_vpath_to_path(view_model, view_path)
glib.idle_add(self.toggle_item_idle_cb, path, view_tree, cell, pagename)
def pre_fadeout_checkout_include(self, tree, pagename):
#after the fadeout the table will be sorted as before
self.sort_column_id = self.recipe_model.sort_column_id
self.sort_order = self.recipe_model.sort_order
def pre_fadeout_checkout_include(self, tree):
#resync the included items to a backup fade include column
it = self.recipe_model.get_iter_first()
while it:
@@ -299,14 +235,8 @@ class RecipeSelectionPage (HobPage):
it = self.recipe_model.iter_next(it)
# Check out a model which base on the column COL_FADE_INC,
# it's save the prev state of column COL_INC before do exclude_item
filter = { RecipeListModel.COL_FADE_INC:[True] }
if pagename == "Included recipes":
filter[RecipeListModel.COL_TYPE] = ['recipe', 'packagegroup']
elif pagename == "All recipes":
filter[RecipeListModel.COL_TYPE] = ['recipe']
else:
filter[RecipeListModel.COL_TYPE] = ['packagegroup']
filter = { RecipeListModel.COL_FADE_INC : [True],
RecipeListModel.COL_TYPE : ['recipe', 'packagegroup'] }
new_model = self.recipe_model.tree_model(filter, excluded_items_ahead=True)
tree.set_model(new_model)
@@ -326,10 +256,8 @@ class RecipeSelectionPage (HobPage):
cell.fadeout(tree, 1000, to_render_cells)
def after_fadeout_checkin_include(self, table, ctrl, cell, tree, filter):
self.recipe_model.sort_column_id = self.sort_column_id
self.recipe_model.sort_order = self.sort_order
tree.set_model(self.recipe_model.tree_model(filter))
def after_fadeout_checkin_include(self, table, ctrl, cell, tree):
tree.set_model(self.recipe_model.tree_model(self.pages[0]['filter']))
def set_recipe_curr_tab(self, curr_page):
self.ins.set_current_page(curr_page)

View File

@@ -46,7 +46,7 @@ class RunningBuildModel (gtk.TreeStore):
color = model.get(it, self.COL_COLOR)[0]
if not color:
return False
if color == HobColors.ERROR or color == HobColors.WARNING:
if color == HobColors.ERROR:
return True
return False
@@ -76,7 +76,7 @@ class RunningBuild (gobject.GObject):
'build-complete' : (gobject.SIGNAL_RUN_LAST,
gobject.TYPE_NONE,
()),
'build-aborted' : (gobject.SIGNAL_RUN_LAST,
'build-aborted' : (gobject.SIGNAL_RUN_LAST,
gobject.TYPE_NONE,
()),
'task-started' : (gobject.SIGNAL_RUN_LAST,
@@ -85,12 +85,6 @@ class RunningBuild (gobject.GObject):
'log-error' : (gobject.SIGNAL_RUN_LAST,
gobject.TYPE_NONE,
()),
'log-warning' : (gobject.SIGNAL_RUN_LAST,
gobject.TYPE_NONE,
()),
'disk-full' : (gobject.SIGNAL_RUN_LAST,
gobject.TYPE_NONE,
()),
'no-provider' : (gobject.SIGNAL_RUN_LAST,
gobject.TYPE_NONE,
(gobject.TYPE_PYOBJECT,)),
@@ -154,7 +148,6 @@ class RunningBuild (gobject.GObject):
elif event.levelno >= logging.WARNING:
icon = "dialog-warning"
color = HobColors.WARNING
self.emit("log-warning")
else:
icon = None
color = HobColors.OK
@@ -293,7 +286,6 @@ class RunningBuild (gobject.GObject):
# Emit the appropriate signal depending on the number of failures
if self.buildaborted:
self.emit ("build-aborted")
self.buildaborted = False
elif (failures >= 1):
self.emit ("build-failed")
else:
@@ -308,7 +300,6 @@ class RunningBuild (gobject.GObject):
elif isinstance(event, bb.event.DiskFull):
self.buildaborted = True
self.emit("disk-full")
elif isinstance(event, bb.command.CommandFailed):
self.emit("log", "error", "Command execution failed: %s" % (event.error))

View File

@@ -137,6 +137,8 @@ class RecipeFile(ConfigFile):
class TemplateMgr(gobject.GObject):
__gLocalVars__ = ["MACHINE", "PACKAGE_CLASSES", "DISTRO", "DL_DIR", "SSTATE_DIR", "SSTATE_MIRRORS", "PARALLEL_MAKE", "BB_NUMBER_THREADS", "CONF_VERSION"]
__gBBLayersVars__ = ["BBLAYERS", "LCONF_VERSION"]
__gRecipeVars__ = ["DEPENDS", "IMAGE_INSTALL"]
def __init__(self):
@@ -150,21 +152,37 @@ class TemplateMgr(gobject.GObject):
def convert_to_template_pathfilename(cls, filename, path):
return "%s/%s%s%s" % (path, "template-", filename, ".hob")
@classmethod
def convert_to_bblayers_pathfilename(cls, filename, path):
return "%s/%s%s%s" % (path, "bblayers-", filename, ".conf")
@classmethod
def convert_to_local_pathfilename(cls, filename, path):
return "%s/%s%s%s" % (path, "local-", filename, ".conf")
@classmethod
def convert_to_image_pathfilename(cls, filename, path):
return "%s/%s%s%s" % (path, "hob-image-", filename, ".bb")
def open(self, filename, path):
self.template_hob = HobTemplateFile(TemplateMgr.convert_to_template_pathfilename(filename, path))
self.bblayers_conf = ConfigFile(TemplateMgr.convert_to_bblayers_pathfilename(filename, path))
self.local_conf = ConfigFile(TemplateMgr.convert_to_local_pathfilename(filename, path))
self.image_bb = RecipeFile(TemplateMgr.convert_to_image_pathfilename(filename, path))
def setVar(self, var, val):
if var in TemplateMgr.__gLocalVars__:
self.local_conf.setVar(var, val)
if var in TemplateMgr.__gBBLayersVars__:
self.bblayers_conf.setVar(var, val)
if var in TemplateMgr.__gRecipeVars__:
self.image_bb.setVar(var, val)
self.template_hob.setVar(var, val)
def save(self):
self.local_conf.save()
self.bblayers_conf.save()
self.image_bb.save()
self.template_hob.save()
@@ -182,6 +200,12 @@ class TemplateMgr(gobject.GObject):
if self.template_hob:
del self.template_hob
template_hob = None
if self.bblayers_conf:
del self.bblayers_conf
self.bblayers_conf = None
if self.local_conf:
del self.local_conf
self.local_conf = None
if self.image_bb:
del self.image_bb
self.image_bb = None

View File

@@ -196,27 +196,19 @@ class gtkthread(threading.Thread):
gtkthread.quit.set()
def main(server, eventHandler, params):
def main(server, eventHandler):
try:
params.updateFromServer(server)
cmdline = params.parseActions()
if not cmdline:
print("Nothing to do. Use 'bitbake world' to build everything, or run 'bitbake --help' for usage information.")
return 1
if 'msg' in cmdline and cmdline['msg']:
logger.error(cmdline['msg'])
return 1
cmdline = cmdline['action']
if not cmdline or cmdline[0] != "generateDotGraph":
cmdline = server.runCommand(["getCmdLineAction"])
if cmdline and not cmdline['action']:
print(cmdline['msg'])
return
elif not cmdline or (cmdline['action'] and cmdline['action'][0] != "generateDotGraph"):
print("This UI is only compatible with the -g option")
return 1
ret, error = server.runCommand(["generateDepTreeEvent", cmdline[1], cmdline[2]])
if error:
print("Error running command '%s': %s" % (cmdline, error))
return 1
elif ret != True:
print("Error running command '%s': returned %s" % (cmdline, ret))
return 1
return
ret = server.runCommand(["generateDepTreeEvent", cmdline['action'][1], cmdline['action'][2]])
if ret != True:
print("Couldn't run command! %s" % ret)
return
except xmlrpclib.Fault as x:
print("XMLRPC Fault getting commandline:\n %s" % x)
return
@@ -242,9 +234,7 @@ def main(server, eventHandler, params):
try:
event = eventHandler.waitEvent(0.25)
if gtkthread.quit.isSet():
_, error = server.runCommand(["stateStop"])
if error:
print('Unable to cleanly stop: %s' % error)
server.runCommand(["stateStop"])
break
if event is None:
@@ -320,13 +310,9 @@ def main(server, eventHandler, params):
break
if shutdown == 1:
print("\nSecond Keyboard Interrupt, stopping...\n")
_, error = server.runCommand(["stateStop"])
if error:
print('Unable to cleanly stop: %s' % error)
server.runCommand(["stateStop"])
if shutdown == 0:
print("\nKeyboard Interrupt, closing down...\n")
_, error = server.runCommand(["stateShutdown"])
if error:
print('Unable to cleanly shutdown: %s' % error)
server.runCommand(["stateShutdown"])
shutdown = shutdown + 1
pass

View File

@@ -63,7 +63,7 @@ class MainWindow (gtk.Window):
scrolled_window.add (self.cur_build_tv)
def main (server, eventHandler, params):
def main (server, eventHandler):
gobject.threads_init()
gtk.gdk.threads_init()
@@ -80,21 +80,16 @@ def main (server, eventHandler, params):
running_build.connect ("build-failed", running_build_failed_cb)
try:
params.updateFromServer(server)
cmdline = params.parseActions()
cmdline = server.runCommand(["getCmdLineAction"])
if not cmdline:
print("Nothing to do. Use 'bitbake world' to build everything, or run 'bitbake --help' for usage information.")
return 1
if 'msg' in cmdline and cmdline['msg']:
logger.error(cmdline['msg'])
elif not cmdline['action']:
print(cmdline['msg'])
return 1
cmdline = cmdline['action']
ret, error = server.runCommand(cmdline)
if error:
print("Error running command '%s': %s" % (cmdline, error))
return 1
elif ret != True:
print("Error running command '%s': returned %s" % (cmdline, ret))
ret = server.runCommand(cmdline['action'])
if ret != True:
print("Couldn't get default commandline! %s" % ret)
return 1
except xmlrpclib.Fault as x:
print("XMLRPC Fault getting commandline:\n %s" % x)

View File

@@ -22,7 +22,7 @@
import sys
import os
requirements = "FATAL: Hob requires Gtk+ 2.20.0 or higher, PyGtk 2.21.0 or higher"
requirements = "FATAL: Gtk+, PyGtk and PyGobject are required to use Hob"
try:
import gobject
import gtk
@@ -58,8 +58,7 @@ def event_handle_idle_func(eventHandler, hobHandler):
event = eventHandler.getEvent()
return True
def main (server, eventHandler, params):
params.updateFromServer(server)
def main (server = None, eventHandler = None):
gobject.threads_init()
# That indicates whether the Hob and the bitbake server are

View File

@@ -146,7 +146,7 @@ class TerminalFilter(object):
import curses
except ImportError:
sys.exit("FATAL: The knotty ui could not load the required curses python module.")
import termios
self.curses = curses
self.termios = termios
@@ -157,8 +157,6 @@ class TerminalFilter(object):
new[3] = new[3] & ~termios.ECHO
termios.tcsetattr(fd, termios.TCSADRAIN, new)
curses.setupterm()
if curses.tigetnum("colors") > 2:
format.enable_color()
self.ed = curses.tigetstr("ed")
if self.ed:
self.cuu = curses.tigetstr("cuu")
@@ -189,7 +187,7 @@ class TerminalFilter(object):
return
if self.footer_present:
self.clearFooter()
if (not self.helper.tasknumber_total or self.helper.tasknumber_current == self.helper.tasknumber_total) and not len(activetasks):
if not self.helper.tasknumber_total or self.helper.tasknumber_current == self.helper.tasknumber_total:
return
tasks = []
for t in runningpids:
@@ -201,11 +199,11 @@ class TerminalFilter(object):
content = "No currently running tasks (%s of %s)" % (self.helper.tasknumber_current, self.helper.tasknumber_total)
else:
content = "Currently %s running tasks (%s of %s):" % (len(activetasks), self.helper.tasknumber_current, self.helper.tasknumber_total)
print(content)
print content
lines = 1 + int(len(content) / (self.columns + 1))
for tasknum, task in enumerate(tasks):
content = "%s: %s" % (tasknum, task)
print(content)
print content
lines = lines + 1 + int(len(content) / (self.columns + 1))
self.footer_present = lines
self.lastpids = runningpids[:]
@@ -216,22 +214,12 @@ class TerminalFilter(object):
fd = sys.stdin.fileno()
self.termios.tcsetattr(fd, self.termios.TCSADRAIN, self.stdinbackup)
def main(server, eventHandler, params, tf = TerminalFilter):
def main(server, eventHandler, tf = TerminalFilter):
# Get values of variables which control our output
includelogs, error = server.runCommand(["getVariable", "BBINCLUDELOGS"])
if error:
logger.error("Unable to get the value of BBINCLUDELOGS variable: %s" % error)
return 1
loglines, error = server.runCommand(["getVariable", "BBINCLUDELOGS_LINES"])
if error:
logger.error("Unable to get the value of BBINCLUDELOGS_LINES variable: %s" % error)
return 1
consolelogfile, error = server.runCommand(["getVariable", "BB_CONSOLELOG"])
if error:
logger.error("Unable to get the value of BB_CONSOLELOG variable: %s" % error)
return 1
includelogs = server.runCommand(["getVariable", "BBINCLUDELOGS"])
loglines = server.runCommand(["getVariable", "BBINCLUDELOGS_LINES"])
consolelogfile = server.runCommand(["getVariable", "BB_CONSOLELOG"])
if sys.stdin.isatty() and sys.stdout.isatty():
log_exec_tty = True
else:
@@ -240,39 +228,31 @@ def main(server, eventHandler, params, tf = TerminalFilter):
helper = uihelper.BBUIHelper()
console = logging.StreamHandler(sys.stdout)
format_str = "%(levelname)s: %(message)s"
format = bb.msg.BBLogFormatter(format_str)
format = bb.msg.BBLogFormatter("%(levelname)s: %(message)s")
bb.msg.addDefaultlogFilter(console)
console.setFormatter(format)
logger.addHandler(console)
if consolelogfile and not params.options.show_environment:
if consolelogfile:
bb.utils.mkdirhier(os.path.dirname(consolelogfile))
conlogformat = bb.msg.BBLogFormatter(format_str)
consolelog = logging.FileHandler(consolelogfile)
bb.msg.addDefaultlogFilter(consolelog)
consolelog.setFormatter(conlogformat)
consolelog.setFormatter(format)
logger.addHandler(consolelog)
try:
params.updateFromServer(server)
cmdline = params.parseActions()
cmdline = server.runCommand(["getCmdLineAction"])
if not cmdline:
print("Nothing to do. Use 'bitbake world' to build everything, or run 'bitbake --help' for usage information.")
return 1
if 'msg' in cmdline and cmdline['msg']:
logger.error(cmdline['msg'])
elif not cmdline['action']:
print(cmdline['msg'])
return 1
ret, error = server.runCommand(cmdline['action'])
if error:
logger.error("Command '%s' failed: %s" % (cmdline, error))
return 1
elif ret != True:
logger.error("Command '%s' failed: returned %s" % (cmdline, ret))
ret = server.runCommand(cmdline['action'])
if ret != True:
print("Couldn't get default commandline! %s" % ret)
return 1
except xmlrpclib.Fault as x:
logger.error("XMLRPC Fault getting commandline:\n %s" % x)
print("XMLRPC Fault getting commandline:\n %s" % x)
return 1
parseprogress = None
@@ -303,7 +283,7 @@ def main(server, eventHandler, params, tf = TerminalFilter):
if log_exec_tty:
tries = event.retries
while tries:
print("Trying to run: %s" % event.prog)
print "Trying to run: %s" % event.prog
if os.system(event.prog) == 0:
break
time.sleep(event.sleep_delay)
@@ -332,7 +312,7 @@ def main(server, eventHandler, params, tf = TerminalFilter):
logfile = event.logfile
if logfile and os.path.exists(logfile):
termfilter.clearFooter()
bb.error("Logfile of failure stored in: %s" % logfile)
print("ERROR: Logfile of failure stored in: %s" % logfile)
if includelogs and not event.errprinted:
print("Log data follows:")
f = open(logfile, "r")
@@ -456,8 +436,7 @@ def main(server, eventHandler, params, tf = TerminalFilter):
bb.runqueue.runQueueExitWait,
bb.event.OperationStarted,
bb.event.OperationCompleted,
bb.event.OperationProgress,
bb.event.DiskFull)):
bb.event.OperationProgress)):
continue
logger.error("Unknown event: %s", event)
@@ -471,15 +450,11 @@ def main(server, eventHandler, params, tf = TerminalFilter):
termfilter.clearFooter()
if main.shutdown == 1:
print("\nSecond Keyboard Interrupt, stopping...\n")
_, error = server.runCommand(["stateStop"])
if error:
logger.error("Unable to cleanly stop: %s" % error)
server.runCommand(["stateStop"])
if main.shutdown == 0:
print("\nKeyboard Interrupt, closing down...\n")
interrupted = True
_, error = server.runCommand(["stateShutdown"])
if error:
logger.error("Unable to cleanly shutdown: %s" % error)
print("\nKeyboard Interrupt, closing down...\n")
server.runCommand(["stateShutdown"])
main.shutdown = main.shutdown + 1
pass

View File

@@ -196,7 +196,7 @@ class NCursesUI:
# t.start()
#-------------------------------------------------------------------------#
def main(self, stdscr, server, eventHandler, params):
def main(self, stdscr, server, eventHandler):
#-------------------------------------------------------------------------#
height, width = stdscr.getmaxyx()
@@ -236,20 +236,15 @@ class NCursesUI:
shutdown = 0
try:
params.updateFromServer(server)
cmdline = params.parseActions()
cmdline = server.runCommand(["getCmdLineAction"])
if not cmdline:
print("Nothing to do. Use 'bitbake world' to build everything, or run 'bitbake --help' for usage information.")
return 1
if 'msg' in cmdline and cmdline['msg']:
logger.error(cmdline['msg'])
return 1
cmdline = cmdline['action']
ret, error = server.runCommand(cmdline)
if error:
print("Error running command '%s': %s" % (cmdline, error))
return
elif ret != True:
elif not cmdline['action']:
print(cmdline['msg'])
return
ret = server.runCommand(cmdline['action'])
if ret != True:
print("Couldn't get default commandlind! %s" % ret)
return
except xmlrpclib.Fault as x:
@@ -350,14 +345,10 @@ class NCursesUI:
exitflag = True
if shutdown == 1:
mw.appendText("Second Keyboard Interrupt, stopping...\n")
_, error = server.runCommand(["stateStop"])
if error:
print("Unable to cleanly stop: %s" % error)
server.runCommand(["stateStop"])
if shutdown == 0:
mw.appendText("Keyboard Interrupt, closing down...\n")
_, error = server.runCommand(["stateShutdown"])
if error:
print("Unable to cleanly shutdown: %s" % error)
server.runCommand(["stateShutdown"])
shutdown = shutdown + 1
pass

View File

@@ -37,17 +37,6 @@ class BBUIEventQueue:
self.BBServer = BBServer
self.clientinfo = clientinfo
server = UIXMLRPCServer(self.clientinfo)
self.host, self.port = server.socket.getsockname()
server.register_function( self.system_quit, "event.quit" )
server.register_function( self.send_event, "event.sendpickle" )
server.socket.settimeout(1)
self.EventHandle = self.BBServer.registerEventHandler(self.host, self.port)
self.server = server
self.t = threading.Thread()
self.t.setDaemon(True)
self.t.run = self.startCallbackHandler
@@ -84,9 +73,19 @@ class BBUIEventQueue:
def startCallbackHandler(self):
while not self.server.quit:
self.server.handle_request()
self.server.server_close()
server = UIXMLRPCServer(self.clientinfo)
self.host, self.port = server.socket.getsockname()
server.register_function( self.system_quit, "event.quit" )
server.register_function( self.send_event, "event.sendpickle" )
server.socket.settimeout(1)
self.EventHandle = self.BBServer.registerEventHandler(self.host, self.port)
self.server = server
while not server.quit:
server.handle_request()
server.server_close()
def system_quit( self ):
"""

View File

@@ -51,7 +51,6 @@ class BBUIHelper:
if isinstance(event, bb.runqueue.runQueueTaskStarted) or isinstance(event, bb.runqueue.sceneQueueTaskStarted):
self.tasknumber_current = event.stats.completed + event.stats.active + event.stats.failed + 1
self.tasknumber_total = event.stats.total
self.needUpdate = True
def getTasks(self):
self.needUpdate = False

View File

@@ -27,31 +27,17 @@ import bb
import bb.msg
import multiprocessing
import fcntl
import subprocess
import glob
import traceback
import errno
from commands import getstatusoutput
from contextlib import contextmanager
logger = logging.getLogger("BitBake.Util")
def clean_context():
return {
"os": os,
"bb": bb,
"time": time,
}
def get_context():
return _context
def set_context(ctx):
_context = ctx
# Context used in better_exec, eval
_context = clean_context()
_context = {
"os": os,
"bb": bb,
"time": time,
}
def explode_version(s):
r = []
@@ -250,16 +236,14 @@ def _print_trace(body, line):
"""
Print the Environment of a Text Body
"""
error = []
# print the environment of the method
min_line = max(1, line-4)
max_line = min(line + 4, len(body))
for i in range(min_line, max_line + 1):
for i in xrange(min_line, max_line + 1):
if line == i:
error.append(' *** %.4d:%s' % (i, body[i-1].rstrip()))
logger.error(' *** %.4d:%s', i, body[i-1])
else:
error.append(' %.4d:%s' % (i, body[i-1].rstrip()))
return error
logger.error(' %.4d:%s', i, body[i-1])
def better_compile(text, file, realfile, mode = "exec"):
"""
@@ -269,78 +253,22 @@ def better_compile(text, file, realfile, mode = "exec"):
try:
return compile(text, file, mode)
except Exception as e:
error = []
# split the text into lines again
body = text.split('\n')
error.append("Error in compiling python function in %s:\n" % realfile)
logger.error("Error in compiling python function in %s", realfile)
logger.error(str(e))
if e.lineno:
error.append("The code lines resulting in this error were:")
error.extend(_print_trace(body, e.lineno))
logger.error("The lines leading to this error were:")
logger.error("\t%d:%s:'%s'", e.lineno, e.__class__.__name__, body[e.lineno-1])
_print_trace(body, e.lineno)
else:
error.append("The function causing this error was:")
logger.error("The function causing this error was:")
for line in body:
error.append(line)
error.append("%s: %s" % (e.__class__.__name__, str(e)))
logger.error("\n".join(error))
logger.error(line)
e = bb.BBHandledException(e)
raise e
def _print_exception(t, value, tb, realfile, text, context):
error = []
try:
exception = traceback.format_exception_only(t, value)
error.append('Error executing a python function in %s:\n' % realfile)
# Strip 'us' from the stack (better_exec call)
tb = tb.tb_next
textarray = text.split('\n')
linefailed = tb.tb_lineno
tbextract = traceback.extract_tb(tb)
tbformat = traceback.format_list(tbextract)
error.append("The stack trace of python calls that resulted in this exception/failure was:")
error.append("File: '%s', lineno: %s, function: %s" % (tbextract[0][0], tbextract[0][1], tbextract[0][2]))
error.extend(_print_trace(textarray, linefailed))
# 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 and (level+1) < len(tbextract):
error.append("File: '%s', lineno: %s, function: %s" % (tbextract[level+1][0], tbextract[level+1][1], tbextract[level+1][2]))
if tbextract[level][0] == tbextract[level+1][0] and tbextract[level+1][2] == tbextract[level][0]:
# The code was possibly in the string we compiled ourselves
error.extend(_print_trace(textarray, tbextract[level+1][1]))
elif tbextract[level+1][0].startswith("/"):
# The code looks like it might be in a file, try and load it
try:
with open(tbextract[level+1][0], "r") as f:
text = f.readlines()
error.extend(_print_trace(text, tbextract[level+1][1]))
except:
error.append(tbformat[level+1])
elif "d" in context and tbextract[level+1][2]:
# Try and find the code in the datastore based on the functionname
d = context["d"]
functionname = tbextract[level+1][2]
text = d.getVar(functionname, True)
if text:
error.extend(_print_trace(text.split('\n'), tbextract[level+1][1]))
else:
error.append(tbformat[level+1])
else:
error.append(tbformat[level+1])
nexttb = tb.tb_next
level = level + 1
error.append("Exception: %s" % ''.join(exception))
finally:
logger.error("\n".join(error))
def better_exec(code, context, text = None, realfile = "<code>"):
"""
Similiar to better_compile, better_exec will
@@ -353,25 +281,64 @@ def better_exec(code, context, text = None, realfile = "<code>"):
if not hasattr(code, "co_filename"):
code = better_compile(code, realfile, realfile)
try:
exec(code, get_context(), context)
exec(code, _context, context)
except Exception as e:
(t, value, tb) = sys.exc_info()
if t in [bb.parse.SkipPackage, bb.build.FuncFailed]:
raise
try:
_print_exception(t, value, tb, realfile, text, context)
except Exception as e:
logger.error("Exception handler error: %s" % str(e))
import traceback
exception = traceback.format_exception_only(t, value)
logger.error('Error executing a python function in %s:\n%s',
realfile, ''.join(exception))
# Strip 'us' from the stack (better_exec call)
tb = tb.tb_next
textarray = text.split('\n')
linefailed = traceback.tb_lineno(tb)
tbextract = traceback.extract_tb(tb)
tbformat = "\n".join(traceback.format_list(tbextract))
logger.error("The stack trace of python calls that resulted in this exception/failure was:")
for line in tbformat.split('\n'):
logger.error(line)
logger.error("The code that was being executed was:")
_print_trace(textarray, linefailed)
logger.error("[From file: '%s', lineno: %s, function: %s]", tbextract[0][0], tbextract[0][1], tbextract[0][2])
# 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 and (level+1) < len(tbextract):
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("[From file: '%s', lineno: %s, function: %s]", tbextract[level+1][0], tbextract[level+1][1], tbextract[level+1][2])
elif "d" in context and tbextract[level+1][2]:
d = context["d"]
functionname = tbextract[level+1][2]
text = d.getVar(functionname, True)
if text:
_print_trace(text.split('\n'), tbextract[level+1][1])
logger.error("[From file: '%s', lineno: %s, function: %s]", tbextract[level+1][0], tbextract[level+1][1], tbextract[level+1][2])
else:
break
else:
break
nexttb = tb.tb_next
level = level + 1
e = bb.BBHandledException(e)
raise e
def simple_exec(code, context):
exec(code, get_context(), context)
exec(code, _context, context)
def better_eval(source, locals):
return eval(source, get_context(), locals)
return eval(source, _context, locals)
@contextmanager
def fileslocked(files):
@@ -427,10 +394,6 @@ def lockfile(name, shared=False, retry=True):
return lf
lf.close()
except Exception:
try:
lf.close()
except Exception:
pass
pass
if not retry:
return None
@@ -460,9 +423,8 @@ def md5_file(filename):
import md5
m = md5.new()
with open(filename, "rb") as f:
for line in f:
m.update(line)
for line in open(filename):
m.update(line)
return m.hexdigest()
def sha256_file(filename):
@@ -478,9 +440,8 @@ def sha256_file(filename):
return None
s = hashlib.sha256()
with open(filename, "rb") as f:
for line in f:
s.update(line)
for line in open(filename):
s.update(line)
return s.hexdigest()
def preserved_envvars_exported():
@@ -497,6 +458,27 @@ def preserved_envvars_exported():
'USER',
]
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',
'DBUS_SESSION_BUS_ADDRESS',
'DESKTOP_SESSION',
'DESKTOP_STARTUP_ID',
'DISPLAY',
'GNOME_KEYRING_PID',
'GNOME_KEYRING_SOCKET',
'GPG_AGENT_INFO',
'GTK_RC_FILES',
'SESSION_MANAGER',
'KRB5CCNAME',
'SSH_AUTH_SOCK',
'XAUTHORITY',
'XDG_DATA_DIRS',
'XDG_SESSION_COOKIE',
]
def preserved_envvars():
"""Variables which are taken from the environment and placed in the metadata"""
v = [
@@ -505,7 +487,7 @@ def preserved_envvars():
'BB_ENV_WHITELIST',
'BB_ENV_EXTRAWHITE',
]
return v + preserved_envvars_exported()
return v + preserved_envvars_exported() + preserved_envvars_exported_interactive()
def filter_environment(good_vars):
"""
@@ -513,20 +495,24 @@ def filter_environment(good_vars):
are not known and may influence the build in a negative way.
"""
removed_vars = {}
removed_vars = []
for key in os.environ.keys():
if key in good_vars:
continue
removed_vars[key] = os.environ[key]
removed_vars.append(key)
os.unsetenv(key)
del os.environ[key]
if len(removed_vars):
logger.debug(1, "Removed the following variables from the environment: %s", ", ".join(removed_vars.keys()))
logger.debug(1, "Removed the following variables from the environment: %s", ", ".join(removed_vars))
return removed_vars
def create_interactive_env(d):
for k in preserved_envvars_exported_interactive():
os.setenv(k, d.getVar(k, True))
def approved_variables():
"""
Determine and return the list of whitelisted variables which are approved
@@ -535,13 +521,10 @@ def approved_variables():
approved = []
if 'BB_ENV_WHITELIST' in os.environ:
approved = os.environ['BB_ENV_WHITELIST'].split()
approved.extend(['BB_ENV_WHITELIST'])
else:
approved = preserved_envvars()
if 'BB_ENV_EXTRAWHITE' in os.environ:
approved.extend(os.environ['BB_ENV_EXTRAWHITE'].split())
if 'BB_ENV_EXTRAWHITE' not in approved:
approved.extend(['BB_ENV_EXTRAWHITE'])
return approved
def clean_environment():
@@ -551,9 +534,7 @@ def clean_environment():
"""
if 'BB_PRESERVE_ENV' not in os.environ:
good_vars = approved_variables()
return filter_environment(good_vars)
return {}
filter_environment(good_vars)
def empty_environment():
"""
@@ -577,15 +558,14 @@ def remove(path, recurse=False):
"""Equivalent to rm -f or rm -rf"""
if not path:
return
if recurse:
# shutil.rmtree(name) would be ideal but its too slow
subprocess.call(['rm', '-rf'] + glob.glob(path))
return
import os, errno, shutil, glob
for name in glob.glob(path):
try:
os.unlink(name)
except OSError as exc:
if exc.errno != errno.ENOENT:
if recurse and exc.errno == errno.EISDIR:
shutil.rmtree(name)
elif exc.errno != errno.ENOENT:
raise
def prunedir(topdir):
@@ -840,31 +820,3 @@ def cpu_count():
def nonblockingfd(fd):
fcntl.fcntl(fd, fcntl.F_SETFL, fcntl.fcntl(fd, fcntl.F_GETFL) | os.O_NONBLOCK)
def process_profilelog(fn):
# Redirect stdout to capture profile information
pout = open(fn + '.processed', 'w')
so = sys.stdout.fileno()
orig_so = os.dup(sys.stdout.fileno())
os.dup2(pout.fileno(), so)
import pstats
p = pstats.Stats(fn)
p.sort_stats('time')
p.print_stats()
p.print_callers()
p.sort_stats('cumulative')
p.print_stats()
os.dup2(orig_so, so)
pout.flush()
pout.close()
#
# Work around multiprocessing pool bugs in python < 2.7.3
#
def multiprocessingpool(*args, **kwargs):
if sys.version_info < (2, 7, 3):
return bb.compat.Pool(*args, **kwargs)
else:
return multiprocessing.pool.Pool(*args, **kwargs)

View File

@@ -10,5 +10,5 @@ def init_logger(logfile, loglevel):
FORMAT = '%(asctime)-15s %(message)s'
logging.basicConfig(level=numeric_level, filename=logfile, format=FORMAT)
class NotFoundError(Exception):
class NotFoundError(StandardError):
pass

View File

@@ -86,8 +86,7 @@ class PRServer(SimpleXMLRPCServer):
def work_forever(self,):
self.quit = False
self.timeout = 0.5
logger.info("Started PRServer with DBfile: %s, IP: %s, PORT: %s, PID: %s" %
logger.info("PRServer: started! DBfile: %s, IP: %s, PORT: %s, PID: %s" %
(self.dbfile, self.host, self.port, str(os.getpid())))
while not self.quit:
@@ -98,10 +97,16 @@ class PRServer(SimpleXMLRPCServer):
return
def start(self):
pid = self.daemonize()
# Ensure both the parent sees this and the child from the work_forever log entry above
logger.info("Started PRServer with DBfile: %s, IP: %s, PORT: %s, PID: %s" %
(self.dbfile, self.host, self.port, str(pid)))
if self.daemon is True:
logger.info("PRServer: try to start daemon...")
self.daemonize()
else:
atexit.register(self.delpid)
pid = str(os.getpid())
pf = file(self.pidfile, 'w+')
pf.write("%s\n" % pid)
pf.close()
self.work_forever()
def delpid(self):
os.remove(self.pidfile)
@@ -113,9 +118,8 @@ class PRServer(SimpleXMLRPCServer):
try:
pid = os.fork()
if pid > 0:
os.waitpid(pid, 0)
#parent return instead of exit to give control
return pid
return
except OSError as e:
raise Exception("%s [%d]" % (e.strerror, e.errno))
@@ -127,7 +131,7 @@ class PRServer(SimpleXMLRPCServer):
try:
pid = os.fork()
if pid > 0: #parent
os._exit(0)
sys.exit(0)
except OSError as e:
raise Exception("%s [%d]" % (e.strerror, e.errno))
@@ -143,22 +147,15 @@ class PRServer(SimpleXMLRPCServer):
os.dup2(so.fileno(),sys.stdout.fileno())
os.dup2(se.fileno(),sys.stderr.fileno())
# Ensure logging makes it to the logfile
streamhandler = logging.StreamHandler()
streamhandler.setLevel(logging.DEBUG)
formatter = bb.msg.BBLogFormatter("%(levelname)s: %(message)s")
streamhandler.setFormatter(formatter)
logger.addHandler(streamhandler)
# write pidfile
atexit.register(self.delpid)
pid = str(os.getpid())
pf = file(self.pidfile, 'w')
pf.write("%s\n" % pid)
pf.close()
self.work_forever()
self.delpid
os._exit(0)
sys.exit(0)
class PRServSingleton():
def __init__(self, dbfile, logfile, interface):
@@ -167,14 +164,21 @@ class PRServSingleton():
self.interface = interface
self.host = None
self.port = None
self.event = threading.Event()
def start(self):
self.prserv = PRServer(self.dbfile, self.logfile, self.interface)
self.prserv.start()
def _work(self):
self.prserv = PRServer(self.dbfile, self.logfile, self.interface, False)
self.host, self.port = self.prserv.getinfo()
self.event.set()
self.prserv.work_forever()
del self.prserv.db
def start(self):
self.working_thread = threading.Thread(target=self._work)
self.working_thread.start()
def getinfo(self):
self.event.wait()
return (self.host, self.port)
class PRServerConnection():
@@ -183,14 +187,13 @@ class PRServerConnection():
host, port = singleton.getinfo()
self.host = host
self.port = port
self.connection, self.transport = bb.server.xmlrpc._create_server(self.host, self.port)
self.connection = bb.server.xmlrpc._create_server(self.host, self.port)
def terminate(self):
# Don't wait for server indefinitely
import socket
socket.setdefaulttimeout(2)
try:
logger.info("Terminating PRServer...")
self.connection.quit()
except Exception as exc:
sys.stderr.write("%s\n" % str(exc))
@@ -263,27 +266,17 @@ def is_local_special(host, port):
else:
return False
class PRServiceConfigError(Exception):
pass
def auto_start(d):
global singleton
host_params = filter(None, (d.getVar('PRSERV_HOST', True) or '').split(':'))
if not host_params:
if (not d.getVar('PRSERV_HOST', True)) or (not d.getVar('PRSERV_PORT', True)):
return True
if len(host_params) != 2:
logger.critical('\n'.join(['PRSERV_HOST: incorrect format',
'Usage: PRSERV_HOST = "<hostname>:<port>"']))
raise PRServiceConfigError
if is_local_special(host_params[0], int(host_params[1])) and not singleton:
if is_local_special(d.getVar('PRSERV_HOST', True), int(d.getVar('PRSERV_PORT', True))) and not singleton:
import bb.utils
cachedir = (d.getVar("PERSISTENT_DIR", True) or d.getVar("CACHE", True))
if not cachedir:
logger.critical("Please set the 'PERSISTENT_DIR' or 'CACHE' variable")
raise PRServiceConfigError
sys.exit(1)
bb.utils.mkdirhier(cachedir)
dbfile = os.path.join(cachedir, "prserv.sqlite3")
logfile = os.path.join(cachedir, "prserv.log")
@@ -292,14 +285,14 @@ def auto_start(d):
if singleton:
host, port = singleton.getinfo()
else:
host = host_params[0]
port = int(host_params[1])
host = d.getVar('PRSERV_HOST', True)
port = int(d.getVar('PRSERV_PORT', True))
try:
return PRServerConnection(host,port).ping()
except Exception:
logger.critical("PRservice %s:%d not available" % (host, port))
raise PRServiceConfigError
return False
def auto_shutdown(d=None):
global singleton

View File

@@ -1,93 +1,98 @@
# This is a single Makefile to handle all generated Yocto Project documents.
# The Makefile needs to live in the documents directory and all figures used
# in any manuals must be .PNG files and live in the individual book's figures
# directory as well as in the figures directory for the mega-manual.
# directory as well as in the figures directory for the mega-manual.
# Note that the figures for the Yocto Project Development Manual
# differ depending on the BRANCH being built.
#
# The Makefile has these targets:
#
# pdf: generates a PDF version of a manual. Not valid for the Quick Start
# or the mega-manual (single, large HTML file comprised of all
# or the mega-manual (single, large HTML file comprised of all
# Yocto Project manuals).
# html: generates an HTML version of a manual.
# eclipse: generates an HTML version of a manual that can be used as
# eclipse help (including necessary metadata files).
# tarball: creates a tarball for the doc files.
# validate: validates
# validate: validates
# publish: pushes generated files to the Yocto Project website
# clean: removes files
#
# The Makefile generates an HTML and PDF version of every document except the
# Yocto Project Quick Start and the single, HTML mega-manual, which is comprised
# of all the individual Yocto Project manuals. These two manuals are in HTML
# form only. The variable DOC indicates the folder name for a given manual. The
# variable VER represents the distro version of the Yocto Release for which the
# manuals are being generated. The variable BRANCH is used to indicate the
# branch (edison or denzil) and is used only when DOC=dev-manual or
# DOC=mega-manual. If you do not specify a BRANCH, the default branch used
# will be for the latest Yocto Project release. If you build for either
# of all the individual Yocto Project manuals. These two manuals are in HTML
# form only. The variable DOC indicates the folder name for a given manual. The
# variable VER represents the distro version of the Yocto Release for which the
# manuals are being generated. The variable BRANCH is used to indicate the
# branch (edison or denzil) and is used only when DOC=dev-manual or
# DOC=mega-manual. If you do not specify a BRANCH, the default branch used
# will be for the latest Yocto Project release. If you build for either
# edison or denzil, you must use BRANCH. You do not need to use BRANCH for
# any release beyond denzil.
# any release beyond denzil.
#
# To build a manual, you must invoke Makefile with the DOC argument. If you
# are going to publish the manual, then you must invoke Makefile with both the
# To build a manual, you must invoke Makefile with the DOC argument. If you
# are going to publish the manual, then you must invoke Makefile with both the
# DOC and the VER argument. Furthermore, if you are building or publishing
# the edison or denzil versions of the Yocto Poject Development Manual or
# the mega-manual, you must also use the BRANCH argument.
# the edison or denzil versions of the Yocto Poject Development Manual or
# the mega-manual, you must also use the BRANCH argument.
#
# Examples:
#
# make DOC=bsp-guide
# make DOC=yocto-project-qs
# make pdf DOC=ref-manual
# make pdf DOC=poky-ref-manual
# make DOC=dev-manual BRANCH=edison
# make DOC=mega-manual BRANCH=denzil
#
# The first example generates the HTML and PDF versions of the BSP Guide.
# The second example generates the HTML version only of the Quick Start. Note that
# the Quick Start only has an HTML version available. The third example generates
# both the PDF and HTML versions of the Yocto Project Reference Manual. The
# fourth example generates both the PDF and HTML 'edison' versions of the YP
# Development Manual. The last exmample generates the HTML version of the
# mega-manual and uses the 'denzil' branch when choosing figures for the
# tarball of figures. Any example that does not use the BRANCH argument
# The second example generates the HTML version only of the Quick Start. Note that
# the Quick Start only has an HTML version available. The third example generates
# both the PDF and HTML versions of the Yocto Project Reference Manual. The
# fourth example generates both the PDF and HTML 'edison' versions of the YP
# Development Manual. The last exmample generates the HTML version of the
# mega-manual and uses the 'denzil' branch when choosing figures for the
# tarball of figures. Any example that does not use the BRANCH argument
# builds the current version of the manual set.
#
# Use the publish target to push the generated manuals to the Yocto Project
# website. All files needed for the manual's HTML form are pushed as well as the
# PDF version (if applicable).
# Use the publish target to push the generated manuals to the Yocto Project
# website. All files needed for the manual's HTML form are pushed as well as the
# PDF version (if applicable).
# Examples:
#
# make publish DOC=bsp-guide VER=1.3
# make publish DOC=adt-manual VER=1.3
# make publish DOC=dev-manual VER=1.1.1 BRANCH=edison
# make publish DOC=dev-manual VER=1.2 BRANCH=denzil
# make publish DOC=dev-manual VER=1.2 BRANCH=denzil
#
# The first example publishes the 1.3 version of both the PDF and HTML versions of
# the BSP Guide. The second example publishes the 1.3 version of both the PDF and
# The first example publishes the 1.3 version of both the PDF and HTML versions of
# the BSP Guide. The second example publishes the 1.3 version of both the PDF and
# HTML versions of the ADT Manual. The third example publishes the PDF and HTML
# 'edison' versions of the YP Development Manual. The fourth example publishes
# the PDF and HTML 'denzil' versions of the YP Development Manual.
#
ifeq ($(DOC),bsp-guide)
XSLTOPTS = --xinclude
ALLPREQ = html pdf eclipse tarball
TARFILES = bsp-style.css bsp-guide.html bsp-guide.pdf figures/bsp-title.png \
eclipse
MANUALS = $(DOC)/$(DOC).html $(DOC)/$(DOC).pdf $(DOC)/eclipse
XSLTOPTS = --stringparam html.stylesheet bsp-style.css \
--stringparam chapter.autolabel 1 \
--stringparam section.autolabel 1 \
--stringparam section.label.includes.component.label 1 \
--xinclude
ALLPREQ = html pdf tarball
TARFILES = bsp-style.css bsp-guide.html bsp-guide.pdf figures/bsp-title.png
MANUALS = $(DOC)/$(DOC).html $(DOC)/$(DOC).pdf
FIGURES = figures
STYLESHEET = $(DOC)/*.css
endif
ifeq ($(DOC),dev-manual)
XSLTOPTS = --xinclude
ALLPREQ = html pdf eclipse tarball
XSLTOPTS = --stringparam html.stylesheet dev-style.css \
--stringparam chapter.autolabel 1 \
--stringparam section.autolabel 1 \
--stringparam section.label.includes.component.label 1 \
--xinclude
ALLPREQ = html pdf tarball
#
# Note that the tarfile might produce the "Cannot stat: No such file or directory" error
# message for .PNG files that are not present when building a particular branch. The
# message for .PNG files that are not present when building a particular branch. The
# list of files is all-inclusive for all branches. Note, if you don't provide a BRANCH
# option, it defaults to the latest stuff. This would be appropriate for "master" branch.
#
@@ -115,24 +120,21 @@ TARFILES = dev-style.css dev-manual.html dev-manual.pdf \
figures/app-dev-flow.png figures/bsp-dev-flow.png figures/dev-title.png \
figures/git-workflow.png figures/index-downloads.png figures/kernel-dev-flow.png \
figures/kernel-overview-1.png figures/kernel-overview-2-generic.png \
figures/source-repos.png figures/yp-download.png \
eclipse
figures/source-repos.png figures/yp-download.png
endif
MANUALS = $(DOC)/$(DOC).html $(DOC)/$(DOC).pdf $(DOC)/eclipse
MANUALS = $(DOC)/$(DOC).html $(DOC)/$(DOC).pdf
FIGURES = figures
STYLESHEET = $(DOC)/*.css
endif
ifeq ($(DOC),yocto-project-qs)
XSLTOPTS = --xinclude
ALLPREQ = html eclipse tarball
TARFILES = yocto-project-qs.html qs-style.css figures/yocto-environment.png \
figures/building-an-image.png figures/using-a-pre-built-image.png \
figures/yocto-project-transp.png \
eclipse
MANUALS = $(DOC)/$(DOC).html $(DOC)/eclipse
XSLTOPTS = --stringparam html.stylesheet qs-style.css \
--xinclude
ALLPREQ = html tarball
TARFILES = yocto-project-qs.html qs-style.css figures/yocto-environment.png figures/building-an-image.png figures/using-a-pre-built-image.png figures/yocto-project-transp.png
MANUALS = $(DOC)/$(DOC).html
FIGURES = figures
STYLESHEET = $(DOC)/*.css
endif
@@ -174,29 +176,13 @@ TARFILES = mega-manual.html mega-style.css figures/yocto-environment.png figures
else
TARFILES = mega-manual.html mega-style.css figures/yocto-environment.png figures/building-an-image.png \
figures/using-a-pre-built-image.png \
figures/poky-title.png figures/buildhistory.png figures/buildhistory-web.png \
figures/poky-title.png \
figures/adt-title.png figures/bsp-title.png \
figures/kernel-dev-title.png figures/kernel-architecture-overview.png \
figures/kernel-title.png figures/kernel-architecture-overview.png \
figures/app-dev-flow.png figures/bsp-dev-flow.png figures/dev-title.png \
figures/git-workflow.png figures/index-downloads.png figures/kernel-dev-flow.png \
figures/kernel-overview-1.png figures/kernel-overview-2-generic.png \
figures/source-repos.png figures/yp-download.png \
figures/profile-title.png figures/kernelshark-all.png \
figures/kernelshark-choose-events.png figures/kernelshark-i915-display.png \
figures/kernelshark-output-display.png figures/lttngmain0.png \
figures/oprofileui-busybox.png figures/oprofileui-copy-to-user.png \
figures/oprofileui-downloading.png figures/oprofileui-processes.png \
figures/perf-probe-do_fork-profile.png figures/perf-report-cycles-u.png \
figures/perf-systemwide.png figures/perf-systemwide-libc.png \
figures/perf-wget-busybox-annotate-menu.png figures/perf-wget-busybox-annotate-udhcpc.png \
figures/perf-wget-busybox-debuginfo.png figures/perf-wget-busybox-dso-zoom.png \
figures/perf-wget-busybox-dso-zoom-menu.png figures/perf-wget-busybox-expanded-stripped.png \
figures/perf-wget-flat-stripped.png figures/perf-wget-g-copy-from-user-expanded-stripped.png \
figures/perf-wget-g-copy-to-user-expanded-debuginfo.png figures/perf-wget-g-copy-to-user-expanded-stripped.png \
figures/perf-wget-g-copy-to-user-expanded-stripped-unresolved-hidden.png figures/pybootchartgui-linux-yocto.png \
figures/pychart-linux-yocto-rpm.png figures/pychart-linux-yocto-rpm-nostrip.png \
figures/sched-wakeup-profile.png figures/sysprof-callers.png \
figures/sysprof-copy-from-user.png figures/sysprof-copy-to-user.png
figures/source-repos.png figures/yp-download.png
endif
MANUALS = $(DOC)/$(DOC).html
@@ -205,60 +191,45 @@ STYLESHEET = $(DOC)/*.css
endif
ifeq ($(DOC),ref-manual)
XSLTOPTS = --xinclude
ALLPREQ = html pdf eclipse tarball
TARFILES = ref-manual.html ref-style.css figures/poky-title.png \
figures/buildhistory.png figures/buildhistory-web.png eclipse
MANUALS = $(DOC)/$(DOC).html $(DOC)/$(DOC).pdf $(DOC)/eclipse
ifeq ($(DOC),poky-ref-manual)
XSLTOPTS = --stringparam html.stylesheet ref-style.css \
--stringparam chapter.autolabel 1 \
--stringparam appendix.autolabel A \
--stringparam section.autolabel 1 \
--stringparam section.label.includes.component.label 1 \
--xinclude
ALLPREQ = html pdf tarball
TARFILES = poky-ref-manual.html ref-style.css figures/poky-title.png
MANUALS = $(DOC)/$(DOC).html $(DOC)/$(DOC).pdf
FIGURES = figures
STYLESHEET = $(DOC)/*.css
endif
ifeq ($(DOC),adt-manual)
XSLTOPTS = --xinclude
ALLPREQ = html pdf eclipse tarball
TARFILES = adt-manual.html adt-manual.pdf adt-style.css figures/adt-title.png \
eclipse
MANUALS = $(DOC)/$(DOC).html $(DOC)/$(DOC).pdf $(DOC)/eclipse
XSLTOPTS = --stringparam html.stylesheet adt-style.css \
--stringparam chapter.autolabel 1 \
--stringparam appendix.autolabel A \
--stringparam section.autolabel 1 \
--stringparam section.label.includes.component.label 1 \
--xinclude
ALLPREQ = html pdf tarball
TARFILES = adt-manual.html adt-manual.pdf adt-style.css figures/adt-title.png
MANUALS = $(DOC)/$(DOC).html $(DOC)/$(DOC).pdf
FIGURES = figures
STYLESHEET = $(DOC)/*.css
endif
ifeq ($(DOC),profile-manual)
XSLTOPTS = --xinclude
ALLPREQ = html pdf eclipse tarball
TARFILES = profile-manual.html profile-manual.pdf profile-manual-style.css \
figures/profile-title.png figures/kernelshark-all.png \
figures/kernelshark-choose-events.png figures/kernelshark-i915-display.png \
figures/kernelshark-output-display.png figures/lttngmain0.png \
figures/oprofileui-busybox.png figures/oprofileui-copy-to-user.png \
figures/oprofileui-downloading.png figures/oprofileui-processes.png \
figures/perf-probe-do_fork-profile.png figures/perf-report-cycles-u.png \
figures/perf-systemwide.png figures/perf-systemwide-libc.png \
figures/perf-wget-busybox-annotate-menu.png figures/perf-wget-busybox-annotate-udhcpc.png \
figures/perf-wget-busybox-debuginfo.png figures/perf-wget-busybox-dso-zoom.png \
figures/perf-wget-busybox-dso-zoom-menu.png figures/perf-wget-busybox-expanded-stripped.png \
figures/perf-wget-flat-stripped.png figures/perf-wget-g-copy-from-user-expanded-stripped.png \
figures/perf-wget-g-copy-to-user-expanded-debuginfo.png figures/perf-wget-g-copy-to-user-expanded-stripped.png \
figures/perf-wget-g-copy-to-user-expanded-stripped-unresolved-hidden.png figures/pybootchartgui-linux-yocto.png \
figures/pychart-linux-yocto-rpm.png figures/pychart-linux-yocto-rpm-nostrip.png \
figures/sched-wakeup-profile.png figures/sysprof-callers.png \
figures/sysprof-copy-from-user.png figures/sysprof-copy-to-user.png \
eclipse
MANUALS = $(DOC)/$(DOC).html $(DOC)/$(DOC).pdf $(DOC)/eclipse
FIGURES = figures
STYLESHEET = $(DOC)/*.css
endif
ifeq ($(DOC),kernel-dev)
XSLTOPTS = --xinclude
ALLPREQ = html pdf eclipse tarball
TARFILES = kernel-dev.html kernel-dev.pdf kernel-dev-style.css figures/kernel-dev-title.png \
figures/kernel-architecture-overview.png \
eclipse
MANUALS = $(DOC)/$(DOC).html $(DOC)/$(DOC).pdf $(DOC)/eclipse
ifeq ($(DOC),kernel-manual)
XSLTOPTS = --stringparam html.stylesheet kernel-style.css \
--stringparam chapter.autolabel 1 \
--stringparam appendix.autolabel A \
--stringparam section.autolabel 1 \
--stringparam section.label.includes.component.label 1 \
--xinclude
ALLPREQ = html pdf tarball
TARFILES = kernel-manual.html kernel-manual.pdf kernel-style.css figures/kernel-title.png figures/kernel-architecture-overview.png
MANUALS = $(DOC)/$(DOC).html $(DOC)/$(DOC).pdf
FIGURES = figures
STYLESHEET = $(DOC)/*.css
endif
@@ -287,10 +258,10 @@ else
cd $(DOC); ../tools/poky-docbook-to-pdf $(DOC).xml ../template; cd ..
endif
html:
ifeq ($(DOC),mega-manual)
# See http://www.sagehill.net/docbookxsl/HtmlOutput.html
# See http://www.sagehill.net/docbookxsl/HtmlOutput.html
@echo " "
@echo "******** Building "$(DOC)
@echo " "
@@ -304,7 +275,7 @@ ifeq ($(DOC),mega-manual)
@echo " "
cd $(DOC); rm mega-manual.html; mv mega-output.html mega-manual.html; cd ..
else
# See http://www.sagehill.net/docbookxsl/HtmlOutput.html
# See http://www.sagehill.net/docbookxsl/HtmlOutput.html
@echo " "
@echo "******** Building "$(DOC)
@echo " "
@@ -312,49 +283,6 @@ else
endif
eclipse: BASE_DIR = html/$(DOC)/
eclipse: eclipse-generate eclipse-resolve-links
.PHONY : eclipse-generate eclipse-resolve-links
eclipse-generate:
ifeq ($(filter $(DOC), adt-manual bsp-guide dev-manual kernel-dev profile-manual ref-manual yocto-project-qs),)
@echo " "
@echo "ERROR: You can only create eclipse documentation"
@echo " of the following documentation parts:"
@echo " - adt-manual"
@echo " - bsp-guide"
@echo " - dev-manual"
@echo " - kernel-dev"
@echo " - profile-manual"
@echo " - ref-manual"
@echo " - yocto-project-qs"
@echo " "
else
@echo " "
@echo "******** Building eclipse help of "$(DOC)
@echo " "
cd $(DOC) && \
xsltproc $(XSLTOPTS) \
--stringparam base.dir '$(BASE_DIR)' \
-o eclipse/$(DOC).html \
$(DOC)-eclipse-customization.xsl $(DOC).xml && \
mv eclipse/toc.xml eclipse/$(DOC)-toc.xml && \
cp -rf $(FIGURES) eclipse/$(BASE_DIR) && \
cd ..;
$(call modify-eclipse)
endif
eclipse-resolve-links:
@echo " "
@echo "******** Using eclipse-help.sed to process external links"
@echo " "
$(foreach FILE, \
$(wildcard $(DOC)/eclipse/html/$(DOC)/*.html), \
$(shell sed -i -f tools/eclipse-help.sed $(FILE)))
tarball: html
@echo " "
@echo "******** Creating Tarball of document files"
@@ -380,4 +308,4 @@ publish:
fi
clean:
rm -rf $(MANUALS); rm $(DOC)/$(DOC).tgz;
rm -f $(MANUALS)

View File

@@ -6,22 +6,22 @@
<title>Using the Command Line</title>
<para>
Recall that earlier the manual discussed how to use an existing toolchain
tarball that had been installed into the default installation
directory, <filename>/opt/poky</filename>, which is outside of the
Recall that earlier the manual discussed how to use an existing toolchain
tarball that had been installed into <filename>/opt/poky</filename>,
which is outside of the
<ulink url='&YOCTO_DOCS_DEV_URL;#build-directory'>Build Directory</ulink>
(see the section "<link linkend='using-an-existing-toolchain-tarball'>Using a Cross-Toolchain Tarball)</link>".
And, that sourcing your architecture-specific environment setup script
initializes a suitable cross-toolchain development environment.
During the setup, locations for the compiler, QEMU scripts, QEMU binary,
a special version of <filename>pkgconfig</filename> and other useful
(see the section "<link linkend='using-an-existing-toolchain-tarball'>Using a Cross-Toolchain Tarball)</link>".
And, that sourcing your architecture-specific environment setup script
initializes a suitable cross-toolchain development environment.
During the setup, locations for the compiler, QEMU scripts, QEMU binary,
a special version of <filename>pkgconfig</filename> and other useful
utilities are added to the <filename>PATH</filename> variable.
Variables to assist <filename>pkgconfig</filename> and <filename>autotools</filename>
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
OpenEmbedded build environment on both autotools-based projects and
Variables to assist <filename>pkgconfig</filename> and <filename>autotools</filename>
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
OpenEmbedded build environment on both autotools-based projects and
Makefile-based projects.
</para>
@@ -29,176 +29,47 @@
<title>Autotools-Based Projects</title>
<para>
Once you have a suitable cross-toolchain installed, it is very easy to
develop a project outside of the OpenEmbedded build system.
This section presents a simple "Helloworld" example that shows how
to set up, compile, and run the project.
</para>
<section id='creating-and-running-a-project-based-on-gnu-autotools'>
<title>Creating and Running a Project Based on GNU Autotools</title>
<para>
Follow these steps to create a simple autotools-based project:
<orderedlist>
<listitem><para><emphasis>Create your directory:</emphasis>
Create a clean directory for your project and then make
that directory your working location:
<literallayout class='monospaced'>
$ mkdir $HOME/helloworld
$ cd $HOME/helloworld
</literallayout></para></listitem>
<listitem><para><emphasis>Populate the directory:</emphasis>
Create <filename>hello.c</filename>, <filename>Makefile.am</filename>,
and <filename>configure.in</filename> files as follows:
<itemizedlist>
<listitem><para>For <filename>hello.c</filename>, include
these lines:
<literallayout class='monospaced'>
#include &lt;stdio.h&gt;
main()
{
printf("Hello World!\n");
}
</literallayout></para></listitem>
<listitem><para>For <filename>Makefile.am</filename>,
include these lines:
<literallayout class='monospaced'>
bin_PROGRAMS = hello
hello_SOURCES = hello.c
</literallayout></para></listitem>
<listitem><para>For <filename>configure.in</filename>,
include these lines:
<literallayout class='monospaced'>
AC_INIT(hello.c)
AM_INIT_AUTOMAKE(hello,0.1)
AC_PROG_CC
AC_PROG_INSTALL
AC_OUTPUT(Makefile)
</literallayout></para></listitem>
</itemizedlist></para></listitem>
<listitem><para><emphasis>Source the cross-toolchain
environment setup file:</emphasis>
Installation of the cross-toolchain creates a cross-toolchain
environment setup script in the directory that the ADT
was installed.
Before you can use the tools to develop your project, you must
source this setup script.
The script begins with the string "environment-setup" and contains
the machine architecture, which is followed by the string
"poky-linux".
Here is an example that sources a script from the
default ADT installation directory that uses the
32-bit Intel x86 Architecture and using the
&DISTRO_NAME; Yocto Project release:
<literallayout class='monospaced'>
$ source /opt/poky/&DISTRO;/environment-setup-i586-poky-linux
</literallayout></para></listitem>
<listitem><para><emphasis>Generate the local aclocal.m4
files and create the configure script:</emphasis>
The following GNU Autotools generate the local
<filename>aclocal.m4</filename> files and create the
configure script:
<literallayout class='monospaced'>
$ aclocal
$ autoconf
</literallayout></para></listitem>
<listitem><para><emphasis>Generate files needed by GNU
coding standards:</emphasis>
GNU coding standards require certain files in order for the
project to be compliant.
This command creates those files:
<literallayout class='monospaced'>
$ touch NEWS README AUTHORS ChangeLog
</literallayout></para></listitem>
<listitem><para><emphasis>Generate the configure
file:</emphasis>
This command generates the <filename>configure</filename>:
<literallayout class='monospaced'>
$ automake -a
</literallayout></para></listitem>
<listitem><para><emphasis>Cross-compile the project:</emphasis>
This command compiles the project using the cross-compiler:
<literallayout class='monospaced'>
$ ./configure ${CONFIGURE_FLAGS}
</literallayout></para></listitem>
<listitem><para><emphasis>Make and install the project:</emphasis>
These two commands generate and install the project into the
destination directory:
<literallayout class='monospaced'>
$ make
$ make install DESTDIR=./tmp
</literallayout></para></listitem>
<listitem><para><emphasis>Verify the installation:</emphasis>
This command is a simple way to verify the installation
of your project.
Running the command prints the architecture on which
the binary file can run.
This architecture should be the same architecture that
the installed cross-toolchain supports.
<literallayout class='monospaced'>
$ file ./tmp/usr/local/bin/hello
</literallayout></para></listitem>
<listitem><para><emphasis>Execute your project:</emphasis>
To execute the project in the shell, simply enter the name.
You could also copy the binary to the actual target hardware
and run the project there as well:
<literallayout class='monospaced'>
$ ./hello
</literallayout>
As expected, the project displays the "Hello World!" message.
</para></listitem>
</orderedlist>
</para>
</section>
<section id='passing-host-options'>
<title>Passing Host Options</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 found in the directory in which you installed the cross-toolchain.
For example, the host option for an ARM-based target that uses the GNU EABI
is <filename>armv5te-poky-linux-gnueabi</filename>.
You will notice 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 \
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 installation of 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=&lt;sysroot-dir&gt;
</literallayout>
</para>
<para>
This single command updates your project and rebuilds it using the appropriate
cross-toolchain tools.
<note>
If <filename>configure</filename> script results in problems recognizing the
<filename>--with-libtool-sysroot=&lt;sysroot-dir&gt;</filename> option,
regenerate the script to enable the support by doing the following and then
re-running the script:
<literallayout class='monospaced'>
</literallayout>
</para>
<para>
This single command updates your project and rebuilds it using the appropriate
cross-toolchain tools.
</para>
<note>
If <filename>configure</filename> script results in problems recognizing the
<filename>--with-libtool-sysroot=&lt;sysroot-dir&gt;</filename> option,
regenerate the script to enable the support by doing the following and then
re-running the script:
<literallayout class='monospaced'>
$ libtoolize --automake
$ aclocal -I ${OECORE_NATIVE_SYSROOT}/usr/share/aclocal \
[-I &lt;dir_containing_your_project-specific_m4_macros&gt;]
$ autoconf
$ autoheader
$ automake -a
</literallayout>
</note>
</para>
</section>
</literallayout>
</note>
</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.
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

View File

@@ -6,70 +6,59 @@
<title>Introduction</title>
<para>
Welcome to the Yocto Project Application Developer's Guide.
This manual provides information that lets you begin developing applications
Welcome to the Yocto Project Application Developer's Guide.
This manual provides information that lets you begin developing applications
using the Yocto Project.
</para>
<para>
The Yocto Project provides an application development environment based on
The Yocto Project provides an application development environment based on
an Application Development Toolkit (ADT) and the availability of stand-alone
cross-development toolchains and other tools.
This manual describes the ADT and how you can configure and install it,
how to access and use the cross-development toolchains, how to
how to access and use the cross-development toolchains, how to
customize the development packages installation,
how to use command line development for both Autotools-based and Makefile-based projects,
and an introduction to the <trademark class='trade'>Eclipse</trademark> IDE
Yocto Plug-in.
<note>
The ADT is distribution-neutral and does not require the Yocto
Project reference distribution, which is called Poky.
This manual, however, uses examples that use the Poky distribution.
</note>
how to use command line development for both Autotools-based and Makefile-based projects,
and an introduction to the Eclipse Yocto Plug-in.
</para>
<section id='adt-intro-section'>
<title>The Application Development Toolkit (ADT)</title>
<para>
Part of the Yocto Project development solution is an Application Development
Part of the Yocto Project development solution is an Application Development
Toolkit (ADT).
The ADT provides you with a custom-built, cross-development
The ADT provides you with a custom-built, cross-development
platform suited for developing a user-targeted product application.
</para>
<para>
Fundamentally, the ADT consists of the following:
<itemizedlist>
<listitem><para>An architecture-specific cross-toolchain and matching
sysroot both built by the OpenEmbedded build system.
The toolchain and sysroot are based on a
<ulink url='&YOCTO_DOCS_DEV_URL;#metadata'>Metadata</ulink>
configuration and extensions,
<listitem><para>An architecture-specific cross-toolchain and matching
sysroot both built by the OpenEmbedded build system, which uses Poky.
The toolchain and sysroot are based on a metadata configuration and extensions,
which allows you to cross-develop on the host machine for the target hardware.
</para></listitem>
<listitem><para>The Eclipse IDE Yocto Plug-in.</para></listitem>
<listitem><para>The Quick EMUlator (QEMU), which lets you simulate target hardware.
</para></listitem>
<listitem><para>Various user-space tools that greatly enhance your application
<listitem><para>Various user-space tools that greatly enhance your application
development experience.</para></listitem>
</itemizedlist>
</para>
<section id='the-cross-development-toolchain'>
<title>The Cross-Development Toolchain</title>
<section id='the-cross-toolchain'>
<title>The Cross-Toolchain</title>
<para>
The
<ulink url='&YOCTO_DOCS_DEV_URL;#cross-development-toolchain'>Cross-Development Toolchain</ulink>
consists of a cross-compiler, cross-linker, and cross-debugger
that are used to develop user-space applications for targeted
hardware.
This toolchain is created either by running the ADT Installer
script, a toolchain installer script, or through a
<ulink url='&YOCTO_DOCS_DEV_URL;#build-directory'>Build Directory</ulink>
that is based on your Metadata configuration or extension for
your targeted device.
The cross-toolchain consists of a cross-compiler, cross-linker, and cross-debugger
that are used to develop user-space applications for targeted hardware.
This toolchain is created either by running the ADT Installer script, a toolchain installer
script, or through a
<ulink url='&YOCTO_DOCS_DEV_URL;#build-directory'>Build Directory</ulink> that
is based on your metadata
configuration or extension for your targeted device.
The cross-toolchain works with a matching target sysroot.
</para>
</section>
@@ -78,10 +67,10 @@
<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
the OpenEmbedded build system and uses the same Metadata configuration
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
the OpenEmbedded build system Poky and uses the same metadata configuration
used to build the cross-toolchain.
</para>
</section>
@@ -90,24 +79,24 @@
<title>Eclipse Yocto Plug-in</title>
<para>
The Eclipse IDE is a popular development environment and it fully supports
development using the Yocto Project.
When you install and configure the Eclipse Yocto Project Plug-in into
the Eclipse IDE, you maximize your Yocto Project 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, deployment, and execution of
your output into a QEMU emulation session.
You can also perform cross-debugging and profiling.
The environment also supports a suite of tools that allows you to perform
remote profiling, tracing, collection of power data, collection of
The Eclipse IDE is a popular development environment and it fully supports
development using the Yocto Project.
When you install and configure the Eclipse Yocto Project Plug-in into
the Eclipse IDE, you maximize your Yocto Project 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, deployment, and execution of
your output into a QEMU emulation session.
You can also perform cross-debugging and profiling.
The environment also supports 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>
For information about the application development workflow that uses the Eclipse
IDE and for a detailed example of how to install and configure the Eclipse
Yocto Project Plug-in, see the
Yocto Project Plug-in, see the
"<ulink url='&YOCTO_DOCS_DEV_URL;#adt-eclipse'>Working Within Eclipse</ulink>" section
of the Yocto Project Development Manual.
</para>
@@ -117,20 +106,20 @@
<title>The QEMU Emulator</title>
<para>
The QEMU emulator allows you to simulate your hardware while running your
The QEMU emulator allows you to simulate your hardware while running your
application or image.
QEMU is made available a number of ways:
<itemizedlist>
<listitem><para>If you use the ADT Installer script to install ADT, you can
<listitem><para>If you use the ADT Installer script to install ADT, you can
specify whether or not to install QEMU.</para></listitem>
<listitem><para>If you have downloaded a Yocto Project release and unpacked
it to create a
<ulink url='&YOCTO_DOCS_DEV_URL;#source-directory'>Source Directory</ulink> and
you have sourced
the environment setup script, QEMU is installed and automatically
<listitem><para>If you have downloaded a Yocto Project release and unpacked
it to create a
<ulink url='&YOCTO_DOCS_DEV_URL;#source-directory'>Source Directory</ulink> and
you have sourced
the environment setup script, QEMU is installed and automatically
available.</para></listitem>
<listitem><para>If you have installed the cross-toolchain
tarball and you have sourced the toolchain's setup environment script, QEMU
<listitem><para>If you have installed the cross-toolchain
tarball and you have sourcing the toolchain's setup environment script, QEMU
is also installed and automatically available.</para></listitem>
</itemizedlist>
</para>
@@ -140,49 +129,38 @@
<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.
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
<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='https://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
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='https://01.org/powertop/'></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>.
For examples on how to setup and use this tool, see the
"<ulink url='&YOCTO_DOCS_PROF_URL;#profile-manual-oprofile'>OProfile</ulink>"
section in the Yocto Project Profiling and Tracing Manual.
</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/'></ulink> and click
on “Perf tools.”
For examples on how to setup and use this tool, see the
"<ulink url='&YOCTO_DOCS_PROF_URL;#profile-manual-perf'>perf</ulink>"
section in the Yocto Project Profiling and Tracing Manual.
</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 Eclipse IDE Yocto Plug-in.
See <ulink url='http://sourceware.org/systemtap'></ulink> for more information
on SystemTap.
For examples on how to setup and use this tool, see the
"<ulink url='&YOCTO_DOCS_PROF_URL;#profile-manual-systemtap'>SystemTap</ulink>"
section in the Yocto Project Profiling and Tracing Manual.</para></listitem>
<listitem><para><emphasis>Lttng-ust:</emphasis> A User-space Tracer designed to
provide detailed information on user-space activity.
<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/'></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 Eclipse IDE Yocto 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>

View File

@@ -3,9 +3,6 @@
<xsl:import href="http://docbook.sourceforge.net/release/xsl/current/xhtml/docbook.xsl" />
<xsl:param name="html.stylesheet" select="'adt-style.css'" />
<xsl:param name="chapter.autolabel" select="1" />
<xsl:param name="appendix.autolabel" select="1" />
<xsl:param name="section.autolabel" select="1" />
<xsl:param name="section.label.includes.component.label" select="1" />
<!-- <xsl:param name="generate.toc" select="'article nop'"></xsl:param> -->
</xsl:stylesheet>

View File

@@ -1,27 +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/eclipse/eclipse3.xsl" />
<xsl:param name="chunker.output.indent" select="'yes'"/>
<xsl:param name="chunk.quietly" select="1"/>
<xsl:param name="chunk.first.sections" select="1"/>
<xsl:param name="chunk.section.depth" select="10"/>
<xsl:param name="use.id.as.filename" select="1"/>
<xsl:param name="ulink.target" select="'_self'" />
<xsl:param name="base.dir" select="'html/adt-manual/'"/>
<xsl:param name="html.stylesheet" select="'../book.css'"/>
<xsl:param name="eclipse.manifest" select="0"/>
<xsl:param name="create.plugin.xml" select="0"/>
<xsl:param name="suppress.navigation" select="1"/>
<xsl:param name="generate.index" select="0"/>
<xsl:param name="chapter.autolabel" select="1" />
<xsl:param name="appendix.autolabel" select="1" />
<xsl:param name="section.autolabel" select="1" />
<xsl:param name="section.label.includes.component.label" select="1" />
</xsl:stylesheet>

View File

@@ -2,7 +2,7 @@
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"
[<!ENTITY % poky SYSTEM "../poky.ent"> %poky; ] >
<book id='adt-manual' lang='en'
<book id='adt-manual' lang='en'
xmlns:xi="http://www.w3.org/2003/XInclude"
xmlns="http://docbook.org/ns/docbook"
>
@@ -10,15 +10,13 @@
<mediaobject>
<imageobject>
<imagedata fileref='figures/adt-title.png'
format='SVG'
<imagedata fileref='figures/adt-title.png'
format='SVG'
align='left' scalefit='1' width='100%'/>
</imageobject>
</imageobject>
</mediaobject>
<title>
Yocto Project Application Developer's Guide
</title>
<title></title>
<authorgroup>
<author>
@@ -56,17 +54,7 @@
<date>October 2012</date>
<revremark>Released with the Yocto Project 1.3 Release.</revremark>
</revision>
<revision>
<revnumber>1.4</revnumber>
<date>April 2013</date>
<revremark>Released with the Yocto Project 1.4 Release.</revremark>
</revision>
<revision>
<revnumber>1.5</revnumber>
<date>Sometime in 2013</date>
<revremark>Released with the Yocto Project 1.5 Release.</revremark>
</revision>
</revhistory>
</revhistory>
<copyright>
<year>&COPYRIGHT_YEAR;</year>
@@ -75,12 +63,12 @@
<legalnotice>
<para>
Permission is granted to copy, distribute and/or modify this document under
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 &amp; Wales</ulink> as published by Creative Commons.
</para>
<note>
Due to production processes, there could be differences between the Yocto Project
documentation bundled in the release tarball and the
documentation bundled in the release tarball and the
<ulink url='&YOCTO_DOCS_ADT_URL;'>Yocto Project Application Developer's Guide</ulink> on
the <ulink url='&YOCTO_HOME_URL;'>Yocto Project</ulink> website.
For the latest version of this manual, see the manual on the website.
@@ -104,6 +92,6 @@
-->
</book>
<!--
vim: expandtab tw=80 ts=4
<!--
vim: expandtab tw=80 ts=4
-->

View File

@@ -6,10 +6,10 @@
<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).
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 target sysroot.
</para>
@@ -17,24 +17,24 @@
<title>Package Management Systems</title>
<para>
The OpenEmbedded build system supports the generation of sysroot files using
The OpenEmbedded build system supports the generation of sysroot 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.
<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
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.
<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 build system currently installs through this PMS by default.
The build system 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 <filename>dpkg</filename> forms the base of the Debian PMS.
For information on dpkg see
<listitem><para><emphasis>Debian:</emphasis> The PMS for Debian-based systems
is built on many PMS tools.
The lower-level PMS tool <filename>dpkg</filename> 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>
@@ -44,31 +44,31 @@
<title>Configuring the PMS</title>
<para>
Whichever PMS you are using, you need to be sure that the
Whichever PMS you are using, you need to be sure that the
<ulink url='&YOCTO_DOCS_REF_URL;#var-PACKAGE_CLASSES'><filename>PACKAGE_CLASSES</filename></ulink>
variable in the <filename>conf/local.conf</filename>
file is set to reflect that system.
file is set to reflect that system.
The first value you choose for the variable specifies the package file format for the root
filesystem at sysroot.
Additional values specify additional formats for convenience or testing.
Additional values specify additional formats for convenience or testing.
See the configuration file for details.
</para>
<note>
For build performance information related to the PMS, see the
"<ulink url='&YOCTO_DOCS_REF_URL;#ref-classes-package'>Packaging - <filename>package*.bbclass</filename></ulink>"
section in the Yocto Project Reference Manual.
For build performance information related to the PMS, see
<ulink url='&YOCTO_DOCS_REF_URL;#ref-classes-package'>Packaging - <filename>package*.bbclass</filename></ulink>
in the Yocto Project Reference Manual.
</note>
<para>
As an example, consider a scenario where you are using OPKG and you want to add
As an example, consider a scenario where you are using OPKG and you want to add
the <filename>libglade</filename> package to the target sysroot.
</para>
<para>
First, you should generate the <filename>ipk</filename> file for the
<filename>libglade</filename> package and add it
into a working <filename>opkg</filename> repository.
First, you should generate the <filename>ipk</filename> file for the
<filename>libglade</filename> package and add it
into a working <filename>opkg</filename> repository.
Use these commands:
<literallayout class='monospaced'>
$ bitbake libglade
@@ -77,12 +77,12 @@
</para>
<para>
Next, source the environment setup script found in the
<ulink url='&YOCTO_DOCS_DEV_URL;#source-directory'>Source Directory</ulink>.
Follow that by setting up the installation destination to point to your
sysroot as <filename>&lt;sysroot_dir&gt;</filename>.
Next, source the environment setup script found in the
<ulink url='&YOCTO_DOCS_DEV_URL;#source-directory'>Source Directory</ulink>.
Follow that by setting up the installation destination to point to your
sysroot as <filename>&lt;sysroot_dir&gt;</filename>.
Finally, have an OPKG configuration file <filename>&lt;conf_file&gt;</filename>
that corresponds to the <filename>opkg</filename> repository you have just created.
that corresponds to the <filename>opkg</filename> repository you have just created.
The following command forms should now work:
<literallayout class='monospaced'>
$ opkg-cl f &lt;conf_file&gt; -o &lt;sysroot_dir&gt; update

View File

@@ -8,7 +8,7 @@
<para>
In order to develop applications, you need set up your host development system.
Several ways exist that allow you to install cross-development tools, QEMU, the
Several ways exist that allow you to install cross-development tools, QEMU, the
Eclipse Yocto Plug-in, and other tools.
This chapter describes how to prepare for application development.
</para>
@@ -18,43 +18,43 @@
<para>
The following list describes installation methods that set up varying degrees of tool
availability on your system.
availabiltiy on your system.
Regardless of the installation method you choose,
you must <filename>source</filename> the cross-toolchain
environment setup script before you use a toolchain.
See the "<link linkend='setting-up-the-cross-development-environment'>Setting Up the
See the "<link linkend='setting-up-the-cross-development-environment'>Setting Up the
Cross-Development Environment</link>" section for more information.
</para>
<note>
<para>Avoid mixing installation methods when installing toolchains for different architectures.
For example, avoid using the ADT Installer to install some toolchains and then hand-installing
cross-development toolchains by running the toolchain installer for different architectures.
cross-development toolchains by running the toolchain installer for different architectures.
Mixing installation methods can result in situations where the ADT Installer becomes
unreliable and might not install the toolchain.</para>
<para>If you must mix installation methods, you might avoid problems by deleting
<filename>/var/lib/opkg</filename>, thus purging the <filename>opkg</filename> package
<para>If you must mix installation methods, you might avoid problems by deleting
<filename>/var/lib/opkg</filename>, thus purging the <filename>opkg</filename> package
metadata</para>
</note>
<para>
<itemizedlist>
<listitem><para><emphasis>Use the ADT installer script:</emphasis>
<listitem><para><emphasis>Use the ADT Installer Script:</emphasis>
This method is the recommended way to install the ADT because it
automates much of the process for you.
For example, you can configure the installation to install the QEMU emulator
and the user-space NFS, specify which root filesystem profiles to download,
and the user-space NFS, specify which root filesystem profiles to download,
and define the target sysroot location.</para></listitem>
<listitem><para><emphasis>Use an existing toolchain:</emphasis>
<listitem><para><emphasis>Use an Existing Toolchain:</emphasis>
Using this method, you select and download an architecture-specific
toolchain installer and then run the script to hand-install the toolchain.
If you use this method, you just get the cross-toolchain and QEMU - you do not
If you use this method, you just get the cross-toolchain and QEMU - you do not
get any of the other mentioned benefits had you run the ADT Installer script.</para></listitem>
<listitem><para><emphasis>Use the toolchain from within the Build Directory:</emphasis>
If you already have a
<ulink url='&YOCTO_DOCS_DEV_URL;#build-directory'>Build Directory</ulink>,
<listitem><para><emphasis>Use the Toolchain from within the Build Directory:</emphasis>
If you already have a
<ulink url='&YOCTO_DOCS_DEV_URL;#build-directory'>Build Directory</ulink>,
you can build the cross-toolchain within the directory.
However, like the previous method mentioned, you only get the cross-toolchain and QEMU - you
However, like the previous method mentioned, you only get the cross-toolchain and QEMU - you
do not get any of the other benefits without taking separate steps.</para></listitem>
</itemizedlist>
</para>
@@ -63,16 +63,8 @@
<title>Using the ADT Installer</title>
<para>
To run the ADT Installer, you need to get the ADT Installer tarball, be sure
you have the necessary host development packages that support the ADT Installer,
and then run the ADT Installer Script.
</para>
<para>
For a list of the host packages needed to support ADT installation and use, see the
"ADT Installer Extras" lists in the
"<ulink url='&YOCTO_DOCS_REF_URL;#required-packages-for-the-host-development-system'>Required Packages for the Host Development System</ulink>" section
of the Yocto Project Reference Manual.
To run the ADT Installer, you need to first get the ADT Installer tarball and then run the ADT
Installer Script.
</para>
<section id='getting-the-adt-installer-tarball'>
@@ -80,27 +72,27 @@
<para>
The ADT Installer is contained in the ADT Installer tarball.
You can download the tarball into any directory from the
You can download the tarball into any directory from the
<ulink url='&YOCTO_DL_URL;/releases'>Index of Releases</ulink>, specifically
at
at
<ulink url='&YOCTO_ADTINSTALLER_DL_URL;'></ulink>.
Or, you can use BitBake to generate the tarball inside the existing
Or, you can use BitBake to generate the tarball inside the existing
<ulink url='&YOCTO_DOCS_DEV_URL;#build-directory'>Build Directory</ulink>.
</para>
<para>
If you use BitBake to generate the ADT Installer tarball, you must
<filename>source</filename> the environment setup script
(<ulink url='&YOCTO_DOCS_REF_URL;#structure-core-script'><filename>&OE_INIT_FILE;</filename></ulink>)
located in the Source Directory before running the
BitBake command that creates the tarball.
If you use BitBake to generate the ADT Installer tarball, you must
<filename>source</filename> the environment setup script
(<filename>&OE_INIT_FILE;</filename>) located
in the Source Directory before running the <filename>bitbake</filename>
command that creates the tarball.
</para>
<para>
The following example commands download the Poky tarball, set up the
<ulink url='&YOCTO_DOCS_DEV_URL;#source-directory'>Source Directory</ulink>,
set up the environment while also creating the default Build Directory,
and run the BitBake command that results in the tarball
The following example commands download the Poky tarball, set up the
<ulink url='&YOCTO_DOCS_DEV_URL;#source-directory'>Source Directory</ulink>,
set up the environment while also creating the default Build Directory,
and run the <filename>bitbake</filename> command that results in the tarball
<filename>~/yocto-project/build/tmp/deploy/sdk/adt_installer.tar.bz2</filename>:
<literallayout class='monospaced'>
$ cd ~
@@ -120,107 +112,112 @@
<para>
Before running the ADT Installer script, you need to unpack the tarball.
You can unpack the tarball in any directory you wish.
For example, this command copies the ADT Installer tarball from where
it was built into the home directory and then unpacks the tarball into
For example, this command copies the ADT Installer tarball from where
it was built into the home directory and then unpacks the tarball into
a top-level directory named <filename>adt-installer</filename>:
<literallayout class='monospaced'>
$ cd ~
$ cp ~/poky/build/tmp/deploy/sdk/adt_installer.tar.bz2 $HOME
$ tar -xjf adt_installer.tar.bz2
</literallayout>
Unpacking it creates the directory <filename>adt-installer</filename>,
Unpacking it creates the directory <filename>adt-installer</filename>,
which contains the ADT Installer script (<filename>adt_installer</filename>)
and its configuration file (<filename>adt_installer.conf</filename>).
</para>
<para>
Before you run the script, however, you should examine the ADT Installer configuration
file and be sure you are going to get what you want.
Before you run the script, however, you should examine the ADT Installer configuration
file and be sure you are going to get what you want.
Your configurations determine which kernel and filesystem image are downloaded.
</para>
<para>
The following list describes the configurations you can define for the ADT Installer.
For configuration values and restrictions, see the comments in
<para>
The following list describes the configurations 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_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_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>.
<listitem><para><filename>YOCTOADT_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_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
<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
<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 Eclipse IDE Yocto plug-in against QEMU,
<listitem><para><filename>YOCTOADT_NFS_UTIL</filename>: Indicates whether
or not to install user-mode NFS.
If you plan to use the Eclipse IDE Yocto plug-in against QEMU,
you should install NFS.
<note>To boot QEMU images using our userspace NFS server, you need
to be running <filename>portmap</filename> or <filename>rpcbind</filename>.
If you are running <filename>rpcbind</filename>, you will also need to add the
<filename>-i</filename> option when <filename>rpcbind</filename> starts up.
Please make sure you understand the security implications of doing this.
You might also have to modify your firewall settings to allow
<note>To boot QEMU images using our userspace NFS server, you need
to be running <filename>portmap</filename> or <filename>rpcbind</filename>.
If you are running <filename>rpcbind</filename>, you will also need to add the
<filename>-i</filename> option when <filename>rpcbind</filename> starts up.
Please make sure you understand the security implications of doing this.
You might also have to modify your firewall settings to allow
NFS booting to work.</note></para></listitem>
<listitem><para><filename>YOCTOADT_ROOTFS_&lt;arch&gt;</filename>: The root
filesystem images you want to download from the
<listitem><para><filename>YOCTOADT_ROOTFS_&lt;arch&gt;</filename>: The root
filesystem images you want to download from the
<filename>YOCTOADT_IPKG_REPO</filename> repository.</para></listitem>
<listitem><para><filename>YOCTOADT_TARGET_SYSROOT_IMAGE_&lt;arch&gt;</filename>: The
<listitem><para><filename>YOCTOADT_TARGET_SYSROOT_IMAGE_&lt;arch&gt;</filename>: The
particular root filesystem used to extract and create the target sysroot.
The value of this variable must have been specified with
The value of this variable must have been specified with
<filename>YOCTOADT_ROOTFS_&lt;arch&gt;</filename>.
For example, if you downloaded both <filename>minimal</filename> and
<filename>sato-sdk</filename> images by setting
For example, if you downloaded both <filename>minimal</filename> and
<filename>sato-sdk</filename> images by setting
<filename>YOCTOADT_ROOTFS_&lt;arch&gt;</filename>
to "minimal sato-sdk", then <filename>YOCTOADT_ROOTFS_&lt;arch&gt;</filename>
must be set to either <filename>minimal</filename> or
must be set to either <filename>minimal</filename> or
<filename>sato-sdk</filename>.</para></listitem>
<listitem><para><filename>YOCTOADT_TARGET_SYSROOT_LOC_&lt;arch&gt;</filename>: The
<listitem><para><filename>YOCTOADT_TARGET_SYSROOT_LOC_&lt;arch&gt;</filename>: The
location on the development host where the target sysroot is created.
</para></listitem>
</itemizedlist>
</para>
<para>
After you have configured the <filename>adt_installer.conf</filename> file,
After you have configured the <filename>adt_installer.conf</filename> file,
run the installer using the following command.
Be sure that you are not trying to use cross-compilation tools.
When you run the installer, the environment must use a
Be sure that you are not trying to use cross-compilation tools.
When you run the installer, the environment must use a
host <filename>gcc</filename>:
<literallayout class='monospaced'>
$ cd ~/adt-installer
$ ./adt_installer
</literallayout>
Once the installer begins to run, you are asked to enter the
location for cross-toolchain installation.
The default location is
<filename>/opt/poky/&lt;release&gt;</filename>.
After either accepting the default location or selecting your
own location, you are prompted to run the installation script
interactively or in silent mode.
If you want to closely monitor the installation,
choose “I” for interactive mode rather than “S” for silent mode.
</para>
<note>
The ADT Installer requires the <filename>libtool</filename> package to complete.
If you install the recommended packages as described in
"<ulink url='&YOCTO_DOCS_QS_URL;#packages'>The Packages</ulink>"
section of the Yocto Project Quick Start, then you will have libtool installed.
</note>
<para>
Once the installer begins to run, you are asked to enter the location for
cross-toolchain installation.
The default location is <filename>/opt/poky/&lt;release&gt;</filename>.
After selecting the location, you are prompted to run in
interactive or silent mode.
If you want to closely monitor the installation, 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 ADT, which includes the
cross-toolchain, is installed in the selected installation
directory.
You will notice environment setup files for the cross-toolchain
in the installation directory, and image tarballs in the
<filename>adt-installer</filename> directory according to your
installer configurations, and the target sysroot located
according to the
<filename>YOCTOADT_TARGET_SYSROOT_LOC_&lt;arch&gt;</filename>
variable also in your configuration file.
Once the installation completes, the ADT, which includes the cross-toolchain, is installed.
You will notice environment setup files for the cross-toolchain in
<filename>&YOCTO_ADTPATH_DIR;</filename>,
and image tarballs in the <filename>adt-installer</filename>
directory according to your installer configurations, and the target sysroot located
according to the <filename>YOCTOADT_TARGET_SYSROOT_LOC_&lt;arch&gt;</filename> variable
also in your configuration file.
</para>
</section>
</section>
@@ -229,87 +226,57 @@
<title>Using a Cross-Toolchain Tarball</title>
<para>
If you want to simply install the cross-toolchain by hand, you can
do so by running the toolchain installer.
If you use this method to install the cross-toolchain and you
might still need to install the target sysroot by installing and
extracting it separately.
For information on how to install the sysroot, see the
If you want to simply install the cross-toolchain by hand, you can do so by running the
toolchain installer.
If you use this method to install the cross-toolchain and you still need to install the target
sysroot, you will have to extract and install sysroot separately.
For information on how to do this, see the
"<link linkend='extracting-the-root-filesystem'>Extracting the Root Filesystem</link>" section.
</para>
<para>
Follow these steps:
<orderedlist>
<listitem><para>Go to
<ulink url='&YOCTO_TOOLCHAIN_DL_URL;'></ulink>
and find the folder that matches your host development system
(i.e. <filename>i686</filename> for 32-bit machines or
<listitem><para>Go to
<ulink url='&YOCTO_TOOLCHAIN_DL_URL;'></ulink>
and find the folder that matches your host development system
(i.e. <filename>i686</filename> for 32-bit machines or
<filename>x86-64</filename> for 64-bit machines).</para></listitem>
<listitem><para>Go into that folder and download the toolchain installer whose name
<listitem><para>Go into that folder and download the toolchain installer whose name
includes the appropriate target architecture.
For example, if your host development system is an Intel-based 64-bit system and
you are going to use your cross-toolchain for an Intel-based 32-bit target, go into the
For example, if your host development system is an Intel-based 64-bit system and
you are going to use your cross-toolchain for an Intel-based 32-bit target, go into the
<filename>x86_64</filename> folder and download the following installer:
<literallayout class='monospaced'>
poky-eglibc-x86_64-i586-toolchain-gmae-&DISTRO;.sh
</literallayout>
<note><para>As an alternative to steps one and two, you can
build the toolchain installer if you have a
<ulink url='&YOCTO_DOCS_DEV_URL;#build-directory'>Build Directory</ulink>.
If you need GMAE, you should use the
<filename>bitbake meta-toolchain-gmae</filename>
command.
Running the resulting installation script will support
such development.
If you are not concerned with GMAE, you can generate
the toolchain installer using
<filename>bitbake meta-toolchain</filename>.
Either of these methods requires you to still
install the target sysroot by installing and
extracting it separately.
For information on how to install the sysroot, see the
"<link linkend='extracting-the-root-filesystem'>Extracting the Root Filesystem</link>" section.
</para>
<para>A final method of building the toolchain installer
exists that has significant advantages over the previous
two methods.
This method results in a toolchain installer that
contains the sysroot that matches your target root
filesystem.
To build this installer, use the
<filename>bitbake image -c populate_sdk</filename>
command.</para>
<para>Remember, before using any
<filename>bitbake</filename> command, you must source
the <filename>&OE_INIT_PATH;</filename> script
located in the Source Directory and you must make sure
your <filename>conf/local.conf</filename> variables are
correct.
In particular, you need to be sure the
<ulink url='&YOCTO_DOCS_REF_URL;#var-MACHINE'><filename>MACHINE</filename></ulink>
variable matches the architecture for which you are
building and that the <filename>SDKMACHINE</filename>
variable is correctly set if you are building
a toolchain for an architecture that differs from your
current development host machine.</para>
<para>When the BitBake command
completes, the toolchain installer will be in
<filename>tmp/deploy/sdk</filename> in the Build
Directory.</para>
</note></para></listitem>
<note><para>As an alternative to steps one and two, you can build the toolchain installer
if you have a <ulink url='&YOCTO_DOCS_DEV_URL;#build-directory'>Build Directory</ulink>.
If you need GMAE, you should use the <filename>bitbake meta-toolchain-gmae</filename>
command.
The resulting installation script when run will support such development.
However, if you are not concerned with GMAE,
you can generate the toolchain installer using
<filename>bitbake meta-toolchain</filename>.</para>
<para>Use the appropriate <filename>bitbake</filename> command only after you have
sourced the <filename>&OE_INIT_PATH;</filename> script located in the Source
Directory.
When the <filename>bitbake</filename> command completes, the toolchain installer will
be in <filename>tmp/deploy/sdk</filename> in the Build Directory.
</para></note>
</para></listitem>
<listitem><para>Once you have the installer, run it to install the toolchain.
You must change the permissions on the toolchain installer
You must change the permissions on the toolchain installer
script so that it is executable.</para>
<para>The following command shows how to run the installer given a toolchain tarball
<para>The following command shows how to run the installer given a toolchain tarball
for a 64-bit development host system and a 32-bit target architecture.
The example assumes the toolchain installer is located in <filename>~/Downloads/</filename>.
<literallayout class='monospaced'>
$ ~/Downloads/poky-eglibc-x86_64-i586-toolchain-gmae-&DISTRO;.sh
</literallayout>
<note>
If you do not have write permissions for the directory into which you are installing
the toolchain, the toolchain installer notifies you and exits.
If you do not have write permissions for the directory into which you are installing
the toolchain, the toolchain installer notifies you and exits.
Be sure you have write permissions in the directory and run the installer again.
</note>
Once the tarball is expanded, the cross-toolchain is installed.
@@ -323,50 +290,50 @@
<title>Using BitBake and the Build Directory</title>
<para>
A final way of making the cross-toolchain available is to use BitBake
to generate the toolchain within an existing
A final way of making the cross-toolchain available is to use BitBake
to generate the toolchain within an existing
<ulink url='&YOCTO_DOCS_DEV_URL;#build-directory'>Build Directory</ulink>.
This method does not install the toolchain into the default
This method does not install the toolchain into the
<filename>/opt</filename> directory.
As with the previous method, if you need to install the target sysroot, you must
As with the previous method, if you need to install the target sysroot, you must
do that separately as well.
</para>
<para>
Follow these steps to generate the toolchain into the Build Directory:
<orderedlist>
<listitem><para>Source the environment setup script
<filename>&OE_INIT_FILE;</filename> located in the
<listitem><para>Source the environment setup script
<filename>&OE_INIT_FILE;</filename> located in the
<ulink url='&YOCTO_DOCS_DEV_URL;#source-directory'>Source Directory</ulink>.
</para></listitem>
<listitem><para>At this point, you should be sure that the
<ulink url='&YOCTO_DOCS_REF_URL;#var-MACHINE'><filename>MACHINE</filename></ulink> variable
in the <filename>local.conf</filename> file found in the
</para></listitem>
<listitem><para>At this point, you should be sure that the
<ulink url='&YOCTO_DOCS_REF_URL;#var-MACHINE'><filename>MACHINE</filename></ulink> variable
in the <filename>local.conf</filename> file found in the
<filename>conf</filename> directory of the Build Directory
is set for the target architecture.
Comments within the <filename>local.conf</filename> file list the values you
can use for the <filename>MACHINE</filename> variable.
<note>You can populate the Build Directory with the cross-toolchains for more
than a single architecture.
You just need to edit the <filename>MACHINE</filename> variable in the
<filename>local.conf</filename> file and re-run the BitBake
Comments within the <filename>local.conf</filename> file list the values you
can use for the <filename>MACHINE</filename> variable.
<note>You can populate the Build Directory with the cross-toolchains for more
than a single architecture.
You just need to edit the <filename>MACHINE</filename> variable in the
<filename>local.conf</filename> file and re-run the BitBake
command.</note></para></listitem>
<listitem><para>Run <filename>bitbake meta-ide-support</filename> to complete the
<listitem><para>Run <filename>bitbake meta-ide-support</filename> to complete the
cross-toolchain generation.
<note>If you change out of your working directory after you
<note>If you change out of your working directory after you
<filename>source</filename> the environment setup script and before you run
the BitBake command, the command might not work.
Be sure to run the BitBake command immediately
after checking or editing the <filename>local.conf</filename> but without
the <filename>bitbake</filename> command, the command might not work.
Be sure to run the <filename>bitbake</filename> command immediately
after checking or editing the <filename>local.conf</filename> but without
changing out of your working directory.</note>
Once the BitBake command finishes,
Once the <filename>bitbake</filename> command finishes,
the cross-toolchain is generated and populated within the Build Directory.
You will notice environment setup files for the cross-toolchain in the
You will notice environment setup files for the cross-toolchain in the
Build Directory in the <filename>tmp</filename> directory.
Setup script filenames contain the strings <filename>environment-setup</filename>.</para>
<para>Be aware that when you use this method to install the toolchain you still need
to separately extract and install the sysroot filesystem.
For information on how to do this, see the
For information on how to do this, see the
"<link linkend='extracting-the-root-filesystem'>Extracting the Root Filesystem</link>" section.
</para></listitem>
</orderedlist>
@@ -378,26 +345,24 @@
<title>Setting Up the Cross-Development Environment</title>
<para>
Before you can develop using the cross-toolchain, you need to set up the
cross-development environment by sourcing the toolchain's environment setup script.
Before you can develop using the cross-toolchain, you need to set up the
cross-development environment by sourcing the toolchain's environment setup script.
If you used the ADT Installer or hand-installed cross-toolchain,
then you can find this script in the directory you chose for installation.
The default installation directory is the <filename>&YOCTO_ADTPATH_DIR;</filename>
directory.
If you installed the toolchain in the
<ulink url='&YOCTO_DOCS_DEV_URL;#build-directory'>Build Directory</ulink>,
you can find the environment setup
then you can find this script in the <filename>&YOCTO_ADTPATH_DIR;</filename>
directory.
If you installed the toolchain in the
<ulink url='&YOCTO_DOCS_DEV_URL;#build-directory'>Build Directory</ulink>,
you can find the environment setup
script for the toolchain in the Build Directory's <filename>tmp</filename> directory.
</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 "<filename>environment-setup</filename>"
and include as part of their name the architecture.
For example, the toolchain environment setup script for a 64-bit
IA-based architecture installed in the default installation directory
would be the following:
<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 <filename>environment-setup</filename>
and include as part of their name the architecture.
For example, the toolchain environment setup script for a 64-bit IA-based architecture would
be the following:
<literallayout class='monospaced'>
&YOCTO_ADTPATH_DIR;/environment-setup-x86_64-poky-linux
</literallayout>
@@ -408,7 +373,7 @@
<title>Securing Kernel and Filesystem Images</title>
<para>
You will need to have a kernel and filesystem image to boot using your
You will need to have a kernel and filesystem image to boot using your
hardware or the QEMU emulator.
Furthermore, if you plan on booting your image using NFS or you want to use the root filesystem
as the target sysroot, you need to extract the root filesystem.
@@ -420,62 +385,62 @@
<para>
To get the kernel and filesystem images, you either have to build them or download
pre-built versions.
You can find examples for both these situations in the
"<ulink url='&YOCTO_DOCS_QS_URL;#test-run'>A Quick Test Run</ulink>" section of
You can find examples for both these situations in the
"<ulink url='&YOCTO_DOCS_QS_URL;#test-run'>A Quick Test Run</ulink>" section of
the Yocto Project Quick Start.
</para>
<para>
The Yocto Project ships basic kernel and filesystem images for several
architectures (<filename>x86</filename>, <filename>x86-64</filename>,
<filename>mips</filename>, <filename>powerpc</filename>, and <filename>arm</filename>)
that you can use unaltered in the QEMU emulator.
These kernel images reside in the release
<para>
The Yocto Project ships basic kernel and filesystem images for several
architectures (<filename>x86</filename>, <filename>x86-64</filename>,
<filename>mips</filename>, <filename>powerpc</filename>, and <filename>arm</filename>)
that you can use unaltered in the QEMU emulator.
These kernel images reside in the release
area - <ulink url='&YOCTO_MACHINES_DL_URL;'></ulink>
and are ideal for experimentation using Yocto Project.
For information on the image types you can build using the OpenEmbedded build system,
For information on the image types you can build using the OpenEmbedded build system,
see the
"<ulink url='&YOCTO_DOCS_REF_URL;#ref-images'>Images</ulink>" chapter in
"<ulink url='&YOCTO_DOCS_REF_URL;#ref-images'>Images</ulink>" chapter in
the Yocto Project Reference Manual.
</para>
<para>
If you are planning on developing against your image and you are not
building or using one of the Yocto Project development images
(e.g. <filename>core-image-*-dev</filename>), you must be sure to
include the development packages as part of your image recipe.
</para>
building or using one of the Yocto Project development images
(e.g. core-image-*-dev), you must be sure to include the development
packages as part of your image recipe.
</para>
<para>
Furthermore, if you plan on remotely deploying and debugging your
application from within the
Furthermore, if you plan on remotely deploying and debugging your
application from within the
Eclipse IDE, you must have an image that contains the Yocto Target Communication
Framework (TCF) agent (<filename>tcf-agent</filename>).
By default, the Yocto Project provides only one type pre-built image that contains the
Framework (TCF) agent (<filename>tcf-agent</filename>).
By default, the Yocto Project provides only one type pre-built image that contains the
<filename>tcf-agent</filename>.
And, those images are SDK (e.g.<filename>core-image-sato-sdk</filename>).
</para>
<para>
If you want to use a different image type that contains the <filename>tcf-agent</filename>,
If you want to use a different image type that contains the <filename>tcf-agent</filename>,
you can do so one of two ways:
<itemizedlist>
<listitem><para>Modify the <filename>conf/local.conf</filename> configuration in
<listitem><para>Modify the <filename>conf/local.conf</filename> configuration in
the <ulink url='&YOCTO_DOCS_DEV_URL;#build-directory'>Build Directory</ulink>
and then rebuild the image.
With this method, you need to modify the
With this method, you need to modify the
<ulink url='&YOCTO_DOCS_REF_URL;#var-EXTRA_IMAGE_FEATURES'><filename>EXTRA_IMAGE_FEATURES</filename></ulink>
variable to have the value of "tools-debug" before rebuilding the image.
variable to have the value of "tools-debug" before rebuilding the image.
Once the image is rebuilt, the <filename>tcf-agent</filename> will be included
in the image and is launched automatically after the boot.</para></listitem>
<listitem><para>Manually build the <filename>tcf-agent</filename>.
To build the agent, follow these steps:
<orderedlist>
<listitem><para>Be sure the ADT is installed as described in the
<listitem><para>Be sure the ADT is installed as described in the
"<link linkend='installing-the-adt'>Installing the ADT and Toolchains</link>" section.
</para></listitem>
<listitem><para>Set up the cross-development environment as described in the
"<link linkend='setting-up-the-cross-development-environment'>Setting
<listitem><para>Set up the cross-development environment as described in the
"<link linkend='setting-up-the-cross-development-environment'>Setting
Up the Cross-Development Environment</link>" section.</para></listitem>
<listitem><para>Get the <filename>tcf-agent</filename> source code using
the following commands:
@@ -484,17 +449,17 @@
$ cd agent
</literallayout></para></listitem>
<listitem><para>Modify the <filename>Makefile.inc</filename> file
for the cross-compilation environment by setting the
<filename>OPSYS</filename> and
for the cross-compilation environment by setting the
<filename>OPSYS</filename> and
<ulink url='&YOCTO_DOCS_REF_URL;#var-MACHINE'><filename>MACHINE</filename></ulink>
variables according to your target.</para></listitem>
<listitem><para>Use the cross-development tools to build the
<filename>tcf-agent</filename>.
<listitem><para>Use the cross-development tools to build the
<filename>tcf-agent</filename>.
Before you "Make" the file, be sure your cross-tools are set up first.
See the "<link linkend='makefile-based-projects'>Makefile-Based Projects</link>"
section for information on how to make sure the cross-tools are set up
correctly.</para>
<para>If the build is successful, the <filename>tcf-agent</filename> output will
<para>If the build is successful, the <filename>tcf-agent</filename> output will
be <filename>obj/$(OPSYS)/$(MACHINE)/Debug/agent</filename>.</para></listitem>
<listitem><para>Deploy the agent into the image's root filesystem.</para></listitem>
</orderedlist>
@@ -509,29 +474,29 @@
<para>
You must extract the root filesystem if you want to boot the image using NFS
or you want to use the root filesystem as the target sysroot.
For example, the Eclipse IDE environment with the Eclipse Yocto Plug-in installed allows you
For example, the Eclipse IDE environment with the Eclipse Yocto Plug-in installed allows you
to use QEMU to boot under NFS.
Another example is if you want to develop your target application using the
root filesystem as the target sysroot.
root filesystem as the target sysroot.
</para>
<para>
<para>
To extract the root filesystem, first <filename>source</filename>
the cross-development environment setup script and then
use the <filename>runqemu-extract-sdk</filename> command on the
filesystem image.
the cross-development environment setup script and then
use the <filename>runqemu-extract-sdk</filename> command on the
filesystem image.
For example, the following commands set up the environment and then extract
the root filesystem from a previously built filesystem image tarball named
the root filesystem from a previously built filesystem image tarball named
<filename>core-image-sato-sdk-qemux86-2011091411831.rootfs.tar.bz2</filename>.
The example extracts the root filesystem into the <filename>$HOME/qemux86-sato</filename>
directory:
<literallayout class='monospaced'>
$ source $HOME/toolchain_dir/environment-setup-i586-poky-linux
$ source $HOME/poky/build/tmp/environment-setup-i586-poky-linux
$ runqemu-extract-sdk \
~Downloads/core-image-sato-sdk-qemux86-2011091411831.rootfs.tar.bz2 \
tmp/deploy/images/core-image-sato-sdk-qemux86-2011091411831.rootfs.tar.bz2 \
$HOME/qemux86-sato
</literallayout>
In this case, you could now point to the target sysroot at
In this case, you could now point to the target sysroot at
<filename>$HOME/qemux86-sato</filename>.
</para>
</section>

View File

@@ -3,8 +3,4 @@
<xsl:import href="http://docbook.sourceforge.net/release/xsl/current/xhtml/docbook.xsl" />
<xsl:param name="html.stylesheet" select="'bsp-style.css'" />
<xsl:param name="chapter.autolabel" select="1" />
<xsl:param name="section.autolabel" select="1" />
<xsl:param name="section.label.includes.component.label" select="1" />
</xsl:stylesheet>

View File

@@ -1,27 +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/eclipse/eclipse3.xsl" />
<xsl:param name="chunker.output.indent" select="'yes'"/>
<xsl:param name="chunk.quietly" select="1"/>
<xsl:param name="chunk.first.sections" select="1"/>
<xsl:param name="chunk.section.depth" select="10"/>
<xsl:param name="use.id.as.filename" select="1"/>
<xsl:param name="ulink.target" select="'_self'" />
<xsl:param name="base.dir" select="'html/bsp-guide/'"/>
<xsl:param name="html.stylesheet" select="'../book.css'"/>
<xsl:param name="eclipse.manifest" select="0"/>
<xsl:param name="create.plugin.xml" select="0"/>
<xsl:param name="suppress.navigation" select="1"/>
<xsl:param name="generate.index" select="0"/>
<xsl:param name="chapter.autolabel" select="1" />
<xsl:param name="appendix.autolabel" select="1" />
<xsl:param name="section.autolabel" select="1" />
<xsl:param name="section.label.includes.component.label" select="1" />
</xsl:stylesheet>

View File

@@ -2,7 +2,7 @@
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"
[<!ENTITY % poky SYSTEM "../poky.ent"> %poky; ] >
<book id='bsp-guide' lang='en'
<book id='bsp-guide' lang='en'
xmlns:xi="http://www.w3.org/2003/XInclude"
xmlns="http://docbook.org/ns/docbook"
>
@@ -10,15 +10,13 @@
<mediaobject>
<imageobject>
<imagedata fileref='figures/bsp-title.png'
format='SVG'
<imagedata fileref='figures/bsp-title.png'
format='SVG'
align='center' scalefit='1' width='100%'/>
</imageobject>
</imageobject>
</mediaobject>
<title>
Yocto Project Board Support Package Developer's Guide
</title>
<title></title>
<authorgroup>
<author>
@@ -68,16 +66,6 @@
<date>October 2012</date>
<revremark>Released with the Yocto Project 1.3 Release.</revremark>
</revision>
<revision>
<revnumber>1.4</revnumber>
<date>April 2013</date>
<revremark>Released with the Yocto Project 1.4 Release.</revremark>
</revision>
<revision>
<revnumber>1.5</revnumber>
<date>Sometime in 2013</date>
<revremark>Released with the Yocto Project 1.5 Release.</revremark>
</revision>
</revhistory>
<copyright>
@@ -87,12 +75,12 @@
<legalnotice>
<para>
Permission is granted to copy, distribute and/or modify this document under
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-nc-sa/2.0/uk/">Creative Commons Attribution-Non-Commercial-Share Alike 2.0 UK: England &amp; Wales</ulink> as published by Creative Commons.
</para>
<note>
Due to production processes, there could be differences between the Yocto Project
documentation bundled in the release tarball and the
documentation bundled in the release tarball and the
<ulink url='&YOCTO_DOCS_BSP_URL;'>Yocto Project Board Support Package (BSP) Developer's Guide</ulink> on
the <ulink url='&YOCTO_HOME_URL;'>Yocto Project</ulink> website.
For the latest version of this manual, see the manual on the website.
@@ -109,6 +97,6 @@
-->
</book>
<!--
vim: expandtab tw=80 ts=4
<!--
vim: expandtab tw=80 ts=4
-->

Some files were not shown because too many files have changed in this diff Show More