mirror of
https://git.yoctoproject.org/poky
synced 2026-02-15 13:13:02 +01:00
Compare commits
137 Commits
warrior-21
...
yocto-2.4.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c2b641c8a0 | ||
|
|
ab4310e7b8 | ||
|
|
551d18e4b8 | ||
|
|
7030d5b4f9 | ||
|
|
f88c841a2d | ||
|
|
1c61ba0a3f | ||
|
|
babf923312 | ||
|
|
a1bff37c3f | ||
|
|
738fc234fa | ||
|
|
f79c0d45fa | ||
|
|
a5e95c2a85 | ||
|
|
4b2d0192b2 | ||
|
|
fd93e26f0d | ||
|
|
15542ff2b3 | ||
|
|
b472addc93 | ||
|
|
2f07e71a9e | ||
|
|
66a0b5b550 | ||
|
|
adaefc1880 | ||
|
|
1a2fb23f56 | ||
|
|
937beb5d94 | ||
|
|
45139bd079 | ||
|
|
8c56b0b2f4 | ||
|
|
f04d6842d3 | ||
|
|
c889bffda2 | ||
|
|
1655dfeffc | ||
|
|
ebf2523922 | ||
|
|
7de56ebc2a | ||
|
|
d0640da88e | ||
|
|
776fb31844 | ||
|
|
80ed9207a7 | ||
|
|
1e4d4762b1 | ||
|
|
968145b24e | ||
|
|
3c28d31fed | ||
|
|
65d09a7d1e | ||
|
|
311245d89f | ||
|
|
0845fa12b8 | ||
|
|
2d9aecf044 | ||
|
|
c32f44ebf5 | ||
|
|
c6d473f460 | ||
|
|
7104d48590 | ||
|
|
d164445477 | ||
|
|
7e0b00fd12 | ||
|
|
25c0d7d891 | ||
|
|
7df22af792 | ||
|
|
351192c314 | ||
|
|
fe51ddba06 | ||
|
|
c8730962a4 | ||
|
|
1e944f79b4 | ||
|
|
994e3674a8 | ||
|
|
69490b4280 | ||
|
|
e27fd333df | ||
|
|
216a839e1b | ||
|
|
bd884dd998 | ||
|
|
e36cf9e621 | ||
|
|
611e4b43d8 | ||
|
|
d4e3893e2d | ||
|
|
99c18e36e2 | ||
|
|
fbddd3917f | ||
|
|
5481891748 | ||
|
|
18b51a13af | ||
|
|
e46fa69897 | ||
|
|
7d934ff315 | ||
|
|
2f6cffd605 | ||
|
|
ed4708db31 | ||
|
|
8d53ceebaf | ||
|
|
f97450203f | ||
|
|
572b9c54a1 | ||
|
|
3f6fbed1e1 | ||
|
|
292c2ae888 | ||
|
|
539a852504 | ||
|
|
10d0ace274 | ||
|
|
852c71956b | ||
|
|
254013ce5f | ||
|
|
de78322f16 | ||
|
|
61f319db67 | ||
|
|
88d92fb301 | ||
|
|
ef6babd638 | ||
|
|
f8c7eff81d | ||
|
|
8d3edc9821 | ||
|
|
8d706de096 | ||
|
|
59cbf69299 | ||
|
|
02f64e5db8 | ||
|
|
c76a25b6ac | ||
|
|
1002359e5e | ||
|
|
3eca58ca70 | ||
|
|
aa6e825bf0 | ||
|
|
2ef0fd2364 | ||
|
|
ee7f665f0a | ||
|
|
ab31d76bc8 | ||
|
|
dd03b7399b | ||
|
|
55d21c7fb6 | ||
|
|
4e28c8d6b7 | ||
|
|
18941419c8 | ||
|
|
da8f32a3bb | ||
|
|
e6fe54ce38 | ||
|
|
23ee931b9d | ||
|
|
e4f256000f | ||
|
|
fbc12e0794 | ||
|
|
c45bdab6b9 | ||
|
|
a97fecb3bd | ||
|
|
87577b8a53 | ||
|
|
5599639b65 | ||
|
|
c388d72c60 | ||
|
|
d40531211c | ||
|
|
8eeed4220e | ||
|
|
0fbaee9077 | ||
|
|
33a48469bd | ||
|
|
e52027eef7 | ||
|
|
9d5296bba5 | ||
|
|
8754f4779c | ||
|
|
e0bfc22475 | ||
|
|
f165c52e57 | ||
|
|
e6c74f7ac9 | ||
|
|
ce3bbc6972 | ||
|
|
f483bdf9c4 | ||
|
|
24c9708492 | ||
|
|
221c4877f1 | ||
|
|
e303b3cadc | ||
|
|
500ce8d139 | ||
|
|
f7e10b532c | ||
|
|
0fc114ba76 | ||
|
|
b21f8e361b | ||
|
|
f515778225 | ||
|
|
40ed9adb53 | ||
|
|
96d525dc03 | ||
|
|
d61b65f35c | ||
|
|
3190ba0b38 | ||
|
|
a027091807 | ||
|
|
9779fc2bdd | ||
|
|
cb258fef83 | ||
|
|
0d84cdfaac | ||
|
|
f609c3f755 | ||
|
|
9217de77b9 | ||
|
|
87f8aafd53 | ||
|
|
6709452171 | ||
|
|
f7b90ab3ea | ||
|
|
7226a1c600 |
11
.gitignore
vendored
11
.gitignore
vendored
@@ -1,7 +1,6 @@
|
||||
*.pyc
|
||||
*.pyo
|
||||
/*.patch
|
||||
/.repo/
|
||||
/build*/
|
||||
pyshtables.py
|
||||
pstage/
|
||||
@@ -19,13 +18,9 @@ hob-image-*.bb
|
||||
!meta-yocto
|
||||
!meta-yocto-bsp
|
||||
!meta-yocto-imported
|
||||
/documentation/*/eclipse/
|
||||
/documentation/*/*.html
|
||||
/documentation/*/*.pdf
|
||||
/documentation/*/*.tgz
|
||||
/bitbake/doc/bitbake-user-manual/bitbake-user-manual.html
|
||||
/bitbake/doc/bitbake-user-manual/bitbake-user-manual.pdf
|
||||
/bitbake/doc/bitbake-user-manual/bitbake-user-manual.tgz
|
||||
documentation/user-manual/user-manual.html
|
||||
documentation/user-manual/user-manual.pdf
|
||||
documentation/user-manual/user-manual.tgz
|
||||
pull-*/
|
||||
bitbake/lib/toaster/contrib/tts/backlog.txt
|
||||
bitbake/lib/toaster/contrib/tts/log/*
|
||||
|
||||
24
LICENSE
24
LICENSE
@@ -1,20 +1,14 @@
|
||||
Different components of OpenEmbedded are under different licenses (a mix
|
||||
of MIT and GPLv2). See LICENSE.GPL-2.0-only and LICENSE.MIT for further
|
||||
details of the individual licenses.
|
||||
of MIT and GPLv2). Please see:
|
||||
|
||||
meta/COPYING.GPLv2 (GPLv2)
|
||||
meta/COPYING.MIT (MIT)
|
||||
meta-selftest/COPYING.MIT (MIT)
|
||||
meta-skeleton/COPYING.MIT (MIT)
|
||||
|
||||
All metadata is MIT licensed unless otherwise stated. Source code
|
||||
included in tree for individual recipes (e.g. patches) are under
|
||||
the LICENSE stated in the associated recipe (.bb file) unless
|
||||
otherwise stated.
|
||||
included in tree for individual recipes is under the LICENSE stated in
|
||||
the associated recipe (.bb file) unless otherwise stated.
|
||||
|
||||
License information for any other files is either explicitly stated
|
||||
or defaults to GPL version 2 only.
|
||||
|
||||
Individual files contain the following style tags instead of the full license
|
||||
text to identify their license:
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-only
|
||||
SPDX-License-Identifier: MIT
|
||||
|
||||
This enables machine processing of license information based on the SPDX
|
||||
License Identifiers that are here available: http://spdx.org/licenses/
|
||||
or defaults to GPL version 2.
|
||||
|
||||
@@ -1,288 +0,0 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
Note:
|
||||
Individual files contain the following tag instead of the full license text.
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
This enables machine processing of license information based on the SPDX
|
||||
License Identifiers that are here available: http://spdx.org/licenses/
|
||||
25
LICENSE.MIT
25
LICENSE.MIT
@@ -1,25 +0,0 @@
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
Note:
|
||||
Individual files contain the following tag instead of the full license text.
|
||||
|
||||
SPDX-License-Identifier: MIT
|
||||
|
||||
This enables machine processing of license information based on the SPDX
|
||||
License Identifiers that are here available: http://spdx.org/licenses/
|
||||
@@ -23,4 +23,3 @@ therefore provides compatibility with the following caveats:
|
||||
* libpng 1.2 isn't provided; oe-core includes the latest release of libpng
|
||||
instead.
|
||||
|
||||
* pax (POSIX standard archive) tool is not provided.
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
OpenEmbedded-Core
|
||||
=================
|
||||
|
||||
OpenEmbedded-Core is a layer containing the core metadata for current versions
|
||||
of OpenEmbedded. It is distro-less (can build a functional image with
|
||||
DISTRO = "nodistro") and contains only emulated machine support.
|
||||
|
||||
For information about OpenEmbedded, see the OpenEmbedded website:
|
||||
http://www.openembedded.org/
|
||||
|
||||
The Yocto Project has extensive documentation about OE including a reference manual
|
||||
which can be found at:
|
||||
http://yoctoproject.org/documentation
|
||||
|
||||
|
||||
Contributing
|
||||
------------
|
||||
|
||||
Please refer to
|
||||
http://www.openembedded.org/wiki/How_to_submit_a_patch_to_OpenEmbedded
|
||||
for guidelines on how to submit patches.
|
||||
|
||||
Mailing list:
|
||||
|
||||
http://lists.openembedded.org/mailman/listinfo/openembedded-core
|
||||
|
||||
Source code:
|
||||
|
||||
http://git.openembedded.org/openembedded-core/
|
||||
2
bitbake/.gitattributes
vendored
2
bitbake/.gitattributes
vendored
@@ -1,2 +0,0 @@
|
||||
*min.js binary
|
||||
*min.css binary
|
||||
339
bitbake/COPYING
Normal file
339
bitbake/COPYING
Normal file
@@ -0,0 +1,339 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
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.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
||||
@@ -4,5 +4,16 @@
|
||||
# <one line to give the program's name and a brief idea of what it does.>
|
||||
# Copyright (C) <year> <name of author>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# 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.
|
||||
|
||||
|
||||
@@ -1,13 +1,4 @@
|
||||
BitBake is licensed under the GNU General Public License version 2.0. See
|
||||
LICENSE.GPL-2.0-only for further details.
|
||||
|
||||
Individual files contain the following style tags instead of the full license text:
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
This enables machine processing of license information based on the SPDX
|
||||
License Identifiers that are here available: http://spdx.org/licenses/
|
||||
|
||||
BitBake is licensed under the GNU General Public License version 2.0. See COPYING for further details.
|
||||
|
||||
The following external components are distributed with this software:
|
||||
|
||||
@@ -26,4 +17,3 @@ Foundation and individual contributors.
|
||||
* Font Awesome fonts redistributed under the SIL Open Font License 1.1
|
||||
|
||||
* simplediff is distributed under the zlib license.
|
||||
|
||||
|
||||
@@ -1,288 +0,0 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
Note:
|
||||
Individual files contain the following tag instead of the full license text.
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
This enables machine processing of license information based on the SPDX
|
||||
License Identifiers that are here available: http://spdx.org/licenses/
|
||||
@@ -1,25 +0,0 @@
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
Note:
|
||||
Individual files contain the following tag instead of the full license text.
|
||||
|
||||
SPDX-License-Identifier: MIT
|
||||
|
||||
This enables machine processing of license information based on the SPDX
|
||||
License Identifiers that are here available: http://spdx.org/licenses/
|
||||
@@ -9,8 +9,18 @@
|
||||
# Copyright (C) 2005 ROAD GmbH
|
||||
# Copyright (C) 2006 Richard Purdie
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License version 2 as
|
||||
# published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
import os
|
||||
import sys
|
||||
@@ -28,7 +38,7 @@ from bb.main import bitbake_main, BitBakeConfigParameters, BBMainException
|
||||
if sys.getfilesystemencoding() != "utf-8":
|
||||
sys.exit("Please use a locale setting which supports UTF-8 (such as LANG=en_US.UTF-8).\nPython can't change the filesystem locale after loading so we need a UTF-8 when Python starts or things won't work.")
|
||||
|
||||
__version__ = "1.42.0"
|
||||
__version__ = "1.36.0"
|
||||
|
||||
if __name__ == "__main__":
|
||||
if __version__ != bb.__version__:
|
||||
|
||||
@@ -1,16 +1,27 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# bitbake-diffsigs / bitbake-dumpsig
|
||||
# BitBake task signature data dump and comparison utility
|
||||
# bitbake-diffsigs
|
||||
# BitBake task signature data comparison utility
|
||||
#
|
||||
# Copyright (C) 2012-2013, 2017 Intel Corporation
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License version 2 as
|
||||
# published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
import os
|
||||
import sys
|
||||
import warnings
|
||||
import fnmatch
|
||||
import argparse
|
||||
import logging
|
||||
import pickle
|
||||
@@ -21,10 +32,7 @@ import bb.tinfoil
|
||||
import bb.siggen
|
||||
import bb.msg
|
||||
|
||||
myname = os.path.basename(sys.argv[0])
|
||||
logger = bb.msg.logger_create(myname)
|
||||
|
||||
is_dump = myname == 'bitbake-dumpsig'
|
||||
logger = bb.msg.logger_create('bitbake-diffsigs')
|
||||
|
||||
def find_siginfo(tinfoil, pn, taskname, sigs=None):
|
||||
result = None
|
||||
@@ -51,8 +59,8 @@ def find_siginfo(tinfoil, pn, taskname, sigs=None):
|
||||
sys.exit(2)
|
||||
return result
|
||||
|
||||
def find_siginfo_task(bbhandler, pn, taskname, sig1=None, sig2=None):
|
||||
""" Find the most recent signature files for the specified PN/task """
|
||||
def find_compare_task(bbhandler, pn, taskname, sig1=None, sig2=None, color=False):
|
||||
""" Find the most recent signature files for the specified PN/task and compare them """
|
||||
|
||||
if not taskname.startswith('do_'):
|
||||
taskname = 'do_%s' % taskname
|
||||
@@ -71,81 +79,73 @@ def find_siginfo_task(bbhandler, pn, taskname, sig1=None, sig2=None):
|
||||
latestfiles = [sigfiles[sig1], sigfiles[sig2]]
|
||||
else:
|
||||
filedates = find_siginfo(bbhandler, pn, taskname)
|
||||
latestfiles = sorted(filedates.keys(), key=lambda f: filedates[f])[-2:]
|
||||
latestfiles = sorted(filedates.keys(), key=lambda f: filedates[f])[-3:]
|
||||
if not latestfiles:
|
||||
logger.error('No sigdata files found matching %s %s' % (pn, taskname))
|
||||
sys.exit(1)
|
||||
elif len(latestfiles) < 2:
|
||||
logger.error('Only one matching sigdata file found for the specified task (%s %s)' % (pn, taskname))
|
||||
sys.exit(1)
|
||||
|
||||
return latestfiles
|
||||
# Define recursion callback
|
||||
def recursecb(key, hash1, hash2):
|
||||
hashes = [hash1, hash2]
|
||||
hashfiles = find_siginfo(bbhandler, key, None, hashes)
|
||||
|
||||
recout = []
|
||||
if len(hashfiles) == 0:
|
||||
recout.append("Unable to find matching sigdata for %s with hashes %s or %s" % (key, hash1, hash2))
|
||||
elif not hash1 in hashfiles:
|
||||
recout.append("Unable to find matching sigdata for %s with hash %s" % (key, hash1))
|
||||
elif not hash2 in hashfiles:
|
||||
recout.append("Unable to find matching sigdata for %s with hash %s" % (key, hash2))
|
||||
else:
|
||||
out2 = bb.siggen.compare_sigfiles(hashfiles[hash1], hashfiles[hash2], recursecb, color=color)
|
||||
for change in out2:
|
||||
for line in change.splitlines():
|
||||
recout.append(' ' + line)
|
||||
|
||||
# Define recursion callback
|
||||
def recursecb(key, hash1, hash2):
|
||||
hashes = [hash1, hash2]
|
||||
hashfiles = find_siginfo(tinfoil, key, None, hashes)
|
||||
return recout
|
||||
|
||||
recout = []
|
||||
if len(hashfiles) == 0:
|
||||
recout.append("Unable to find matching sigdata for %s with hashes %s or %s" % (key, hash1, hash2))
|
||||
elif not hash1 in hashfiles:
|
||||
recout.append("Unable to find matching sigdata for %s with hash %s" % (key, hash1))
|
||||
elif not hash2 in hashfiles:
|
||||
recout.append("Unable to find matching sigdata for %s with hash %s" % (key, hash2))
|
||||
else:
|
||||
out2 = bb.siggen.compare_sigfiles(hashfiles[hash1], hashfiles[hash2], recursecb, color=color)
|
||||
for change in out2:
|
||||
for line in change.splitlines():
|
||||
recout.append(' ' + line)
|
||||
# Recurse into signature comparison
|
||||
logger.debug("Signature file (previous): %s" % latestfiles[-2])
|
||||
logger.debug("Signature file (latest): %s" % latestfiles[-1])
|
||||
output = bb.siggen.compare_sigfiles(latestfiles[-2], latestfiles[-1], recursecb, color=color)
|
||||
if output:
|
||||
print('\n'.join(output))
|
||||
sys.exit(0)
|
||||
|
||||
return recout
|
||||
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description=("Dumps" if is_dump else "Compares") + " siginfo/sigdata files written out by BitBake")
|
||||
description="Compares siginfo/sigdata files written out by BitBake")
|
||||
|
||||
parser.add_argument('-D', '--debug',
|
||||
parser.add_argument('-d', '--debug',
|
||||
help='Enable debug output',
|
||||
action='store_true')
|
||||
|
||||
if is_dump:
|
||||
parser.add_argument("-t", "--task",
|
||||
help="find the signature data file for the last run of the specified task",
|
||||
action="store", dest="taskargs", nargs=2, metavar=('recipename', 'taskname'))
|
||||
parser.add_argument('--color',
|
||||
help='Colorize output (where %(metavar)s is %(choices)s)',
|
||||
choices=['auto', 'always', 'never'], default='auto', metavar='color')
|
||||
|
||||
parser.add_argument("sigdatafile1",
|
||||
help="Signature file to dump. Not used when using -t/--task.",
|
||||
action="store", nargs='?', metavar="sigdatafile")
|
||||
else:
|
||||
parser.add_argument('-c', '--color',
|
||||
help='Colorize the output (where %(metavar)s is %(choices)s)',
|
||||
choices=['auto', 'always', 'never'], default='auto', metavar='color')
|
||||
parser.add_argument("-t", "--task",
|
||||
help="find the signature data files for last two runs of the specified task and compare them",
|
||||
action="store", dest="taskargs", nargs=2, metavar=('recipename', 'taskname'))
|
||||
|
||||
parser.add_argument('-d', '--dump',
|
||||
help='Dump the last signature data instead of comparing (equivalent to using bitbake-dumpsig)',
|
||||
action='store_true')
|
||||
parser.add_argument("-s", "--signature",
|
||||
help="With -t/--task, specify the signatures to look for instead of taking the last two",
|
||||
action="store", dest="sigargs", nargs=2, metavar=('fromsig', 'tosig'))
|
||||
|
||||
parser.add_argument("-t", "--task",
|
||||
help="find the signature data files for the last two runs of the specified task and compare them",
|
||||
action="store", dest="taskargs", nargs=2, metavar=('recipename', 'taskname'))
|
||||
parser.add_argument("sigdatafile1",
|
||||
help="First signature file to compare (or signature file to dump, if second not specified). Not used when using -t/--task.",
|
||||
action="store", nargs='?')
|
||||
|
||||
parser.add_argument("-s", "--signature",
|
||||
help="With -t/--task, specify the signatures to look for instead of taking the last two",
|
||||
action="store", dest="sigargs", nargs=2, metavar=('fromsig', 'tosig'))
|
||||
parser.add_argument("sigdatafile2",
|
||||
help="Second signature file to compare",
|
||||
action="store", nargs='?')
|
||||
|
||||
parser.add_argument("sigdatafile1",
|
||||
help="First signature file to compare (or signature file to dump, if second not specified). Not used when using -t/--task.",
|
||||
action="store", nargs='?')
|
||||
|
||||
parser.add_argument("sigdatafile2",
|
||||
help="Second signature file to compare",
|
||||
action="store", nargs='?')
|
||||
|
||||
options = parser.parse_args()
|
||||
if is_dump:
|
||||
options.color = 'never'
|
||||
options.dump = True
|
||||
options.sigdatafile2 = None
|
||||
options.sigargs = None
|
||||
|
||||
if options.debug:
|
||||
logger.setLevel(logging.DEBUG)
|
||||
@@ -155,32 +155,17 @@ color = (options.color == 'always' or (options.color == 'auto' and sys.stdout.is
|
||||
if options.taskargs:
|
||||
with bb.tinfoil.Tinfoil() as tinfoil:
|
||||
tinfoil.prepare(config_only=True)
|
||||
if not options.dump and options.sigargs:
|
||||
files = find_siginfo_task(tinfoil, options.taskargs[0], options.taskargs[1], options.sigargs[0], options.sigargs[1])
|
||||
if options.sigargs:
|
||||
find_compare_task(tinfoil, options.taskargs[0], options.taskargs[1], options.sigargs[0], options.sigargs[1], color=color)
|
||||
else:
|
||||
files = find_siginfo_task(tinfoil, options.taskargs[0], options.taskargs[1])
|
||||
|
||||
if options.dump:
|
||||
logger.debug("Signature file: %s" % files[-1])
|
||||
output = bb.siggen.dump_sigfile(files[-1])
|
||||
else:
|
||||
if len(files) < 2:
|
||||
logger.error('Only one matching sigdata file found for the specified task (%s %s)' % (options.taskargs[0], options.taskargs[1]))
|
||||
sys.exit(1)
|
||||
|
||||
# Recurse into signature comparison
|
||||
logger.debug("Signature file (previous): %s" % files[-2])
|
||||
logger.debug("Signature file (latest): %s" % files[-1])
|
||||
output = bb.siggen.compare_sigfiles(files[-2], files[-1], recursecb, color=color)
|
||||
find_compare_task(tinfoil, options.taskargs[0], options.taskargs[1], color=color)
|
||||
else:
|
||||
if options.sigargs:
|
||||
logger.error('-s/--signature can only be used together with -t/--task')
|
||||
sys.exit(1)
|
||||
try:
|
||||
if not options.dump and options.sigdatafile1 and options.sigdatafile2:
|
||||
with bb.tinfoil.Tinfoil() as tinfoil:
|
||||
tinfoil.prepare(config_only=True)
|
||||
output = bb.siggen.compare_sigfiles(options.sigdatafile1, options.sigdatafile2, recursecb, color=color)
|
||||
if options.sigdatafile1 and options.sigdatafile2:
|
||||
output = bb.siggen.compare_sigfiles(options.sigdatafile1, options.sigdatafile2, color=color)
|
||||
elif options.sigdatafile1:
|
||||
output = bb.siggen.dump_sigfile(options.sigdatafile1)
|
||||
else:
|
||||
@@ -194,5 +179,5 @@ else:
|
||||
logger.error('Invalid signature data - ensure you are specifying sigdata/siginfo files')
|
||||
sys.exit(1)
|
||||
|
||||
if output:
|
||||
print('\n'.join(output))
|
||||
if output:
|
||||
print('\n'.join(output))
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
bitbake-diffsigs
|
||||
94
bitbake/bin/bitbake-dumpsig
Executable file
94
bitbake/bin/bitbake-dumpsig
Executable file
@@ -0,0 +1,94 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# bitbake-dumpsig
|
||||
# BitBake task signature dump utility
|
||||
#
|
||||
# Copyright (C) 2013 Intel Corporation
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License version 2 as
|
||||
# published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
import os
|
||||
import sys
|
||||
import warnings
|
||||
import optparse
|
||||
import logging
|
||||
import pickle
|
||||
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(sys.argv[0])), 'lib'))
|
||||
|
||||
import bb.tinfoil
|
||||
import bb.siggen
|
||||
import bb.msg
|
||||
|
||||
logger = bb.msg.logger_create('bitbake-dumpsig')
|
||||
|
||||
def find_siginfo_task(bbhandler, pn, taskname):
|
||||
""" Find the most recent signature file for the specified PN/task """
|
||||
|
||||
if not hasattr(bb.siggen, 'find_siginfo'):
|
||||
logger.error('Metadata does not support finding signature data files')
|
||||
sys.exit(1)
|
||||
|
||||
if not taskname.startswith('do_'):
|
||||
taskname = 'do_%s' % taskname
|
||||
|
||||
filedates = bb.siggen.find_siginfo(pn, taskname, None, bbhandler.config_data)
|
||||
latestfiles = sorted(filedates.keys(), key=lambda f: filedates[f])[-1:]
|
||||
if not latestfiles:
|
||||
logger.error('No sigdata files found matching %s %s' % (pn, taskname))
|
||||
sys.exit(1)
|
||||
|
||||
return latestfiles[0]
|
||||
|
||||
parser = optparse.OptionParser(
|
||||
description = "Dumps siginfo/sigdata files written out by BitBake",
|
||||
usage = """
|
||||
%prog -t recipename taskname
|
||||
%prog sigdatafile""")
|
||||
|
||||
parser.add_option("-D", "--debug",
|
||||
help = "enable debug",
|
||||
action = "store_true", dest="debug", default = False)
|
||||
|
||||
parser.add_option("-t", "--task",
|
||||
help = "find the signature data file for the specified task",
|
||||
action="store", dest="taskargs", nargs=2, metavar='recipename taskname')
|
||||
|
||||
options, args = parser.parse_args(sys.argv)
|
||||
|
||||
if options.debug:
|
||||
logger.setLevel(logging.DEBUG)
|
||||
|
||||
if options.taskargs:
|
||||
tinfoil = bb.tinfoil.Tinfoil()
|
||||
tinfoil.prepare(config_only = True)
|
||||
file = find_siginfo_task(tinfoil, options.taskargs[0], options.taskargs[1])
|
||||
logger.debug("Signature file: %s" % file)
|
||||
elif len(args) == 1:
|
||||
parser.print_help()
|
||||
sys.exit(0)
|
||||
else:
|
||||
file = args[1]
|
||||
|
||||
try:
|
||||
output = bb.siggen.dump_sigfile(file)
|
||||
except IOError as e:
|
||||
logger.error(str(e))
|
||||
sys.exit(1)
|
||||
except (pickle.UnpicklingError, EOFError):
|
||||
logger.error('Invalid signature data - ensure you are specifying a sigdata/siginfo file')
|
||||
sys.exit(1)
|
||||
|
||||
if output:
|
||||
print('\n'.join(output))
|
||||
@@ -1,58 +0,0 @@
|
||||
#! /usr/bin/env python3
|
||||
#
|
||||
# Copyright (C) 2018 Garmin Ltd.
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
#
|
||||
|
||||
import os
|
||||
import sys
|
||||
import logging
|
||||
import argparse
|
||||
import sqlite3
|
||||
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(__file__)),'lib'))
|
||||
|
||||
import hashserv
|
||||
|
||||
VERSION = "1.0.0"
|
||||
|
||||
DEFAULT_HOST = ''
|
||||
DEFAULT_PORT = 8686
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description='HTTP Equivalence Reference Server. Version=%s' % VERSION)
|
||||
parser.add_argument('--address', default=DEFAULT_HOST, help='Bind address (default "%(default)s")')
|
||||
parser.add_argument('--port', type=int, default=DEFAULT_PORT, help='Bind port (default %(default)d)')
|
||||
parser.add_argument('--prefix', default='', help='HTTP path prefix (default "%(default)s")')
|
||||
parser.add_argument('--database', default='./hashserv.db', help='Database file (default "%(default)s")')
|
||||
parser.add_argument('--log', default='WARNING', help='Set logging level')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
logger = logging.getLogger('hashserv')
|
||||
|
||||
level = getattr(logging, args.log.upper(), None)
|
||||
if not isinstance(level, int):
|
||||
raise ValueError('Invalid log level: %s' % args.log)
|
||||
|
||||
logger.setLevel(level)
|
||||
console = logging.StreamHandler()
|
||||
console.setLevel(level)
|
||||
logger.addHandler(console)
|
||||
|
||||
db = sqlite3.connect(args.database)
|
||||
|
||||
server = hashserv.create_server((args.address, args.port), db, args.prefix)
|
||||
server.serve_forever()
|
||||
return 0
|
||||
|
||||
if __name__ == '__main__':
|
||||
try:
|
||||
ret = main()
|
||||
except Exception:
|
||||
ret = 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
sys.exit(ret)
|
||||
|
||||
@@ -7,8 +7,18 @@
|
||||
# Copyright (C) 2011 Mentor Graphics Corporation
|
||||
# Copyright (C) 2011-2015 Intel Corporation
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# 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 logging
|
||||
import os
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
#
|
||||
|
||||
import os
|
||||
import sys,logging
|
||||
import optparse
|
||||
|
||||
@@ -2,8 +2,18 @@
|
||||
#
|
||||
# Copyright (C) 2012 Richard Purdie
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License version 2 as
|
||||
# published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
import os
|
||||
import sys, logging
|
||||
@@ -12,24 +22,16 @@ sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(__file__)), 'lib
|
||||
import unittest
|
||||
try:
|
||||
import bb
|
||||
import hashserv
|
||||
import layerindexlib
|
||||
except RuntimeError as exc:
|
||||
sys.exit(str(exc))
|
||||
|
||||
tests = ["bb.tests.codeparser",
|
||||
"bb.tests.cooker",
|
||||
"bb.tests.cow",
|
||||
"bb.tests.data",
|
||||
"bb.tests.event",
|
||||
"bb.tests.fetch",
|
||||
"bb.tests.parse",
|
||||
"bb.tests.persist_data",
|
||||
"bb.tests.utils",
|
||||
"hashserv.tests",
|
||||
"layerindexlib.tests.layerindexobj",
|
||||
"layerindexlib.tests.restapi",
|
||||
"layerindexlib.tests.cooker"]
|
||||
"bb.tests.utils"]
|
||||
|
||||
for t in tests:
|
||||
t = '.'.join(t.split('.')[:3])
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
#
|
||||
|
||||
import os
|
||||
import sys
|
||||
@@ -139,7 +136,7 @@ def sigterm_handler(signum, frame):
|
||||
os.killpg(0, signal.SIGTERM)
|
||||
sys.exit()
|
||||
|
||||
def fork_off_task(cfg, data, databuilder, workerdata, fn, task, taskname, taskhash, unihash, appends, taskdepdata, extraconfigdata, quieterrors=False, dry_run_exec=False):
|
||||
def fork_off_task(cfg, data, databuilder, workerdata, fn, task, taskname, appends, taskdepdata, extraconfigdata, quieterrors=False, dry_run_exec=False):
|
||||
# We need to setup the environment BEFORE the fork, since
|
||||
# a fork() or exec*() activates PSEUDO...
|
||||
|
||||
@@ -237,8 +234,7 @@ def fork_off_task(cfg, data, databuilder, workerdata, fn, task, taskname, taskha
|
||||
ret = 0
|
||||
|
||||
the_data = bb_cache.loadDataFull(fn, appends)
|
||||
the_data.setVar('BB_TASKHASH', taskhash)
|
||||
the_data.setVar('BB_UNIHASH', unihash)
|
||||
the_data.setVar('BB_TASKHASH', workerdata["runq_hash"][task])
|
||||
|
||||
bb.utils.set_process_name("%s:%s" % (the_data.getVar("PN"), taskname.replace("do_", "")))
|
||||
|
||||
@@ -429,10 +425,10 @@ class BitbakeWorker(object):
|
||||
sys.exit(0)
|
||||
|
||||
def handle_runtask(self, data):
|
||||
fn, task, taskname, taskhash, unihash, quieterrors, appends, taskdepdata, dry_run_exec = pickle.loads(data)
|
||||
fn, task, taskname, quieterrors, appends, taskdepdata, dry_run_exec = pickle.loads(data)
|
||||
workerlog_write("Handling runtask %s %s %s\n" % (task, fn, taskname))
|
||||
|
||||
pid, pipein, pipeout = fork_off_task(self.cookercfg, self.data, self.databuilder, self.workerdata, fn, task, taskname, taskhash, unihash, appends, taskdepdata, self.extraconfigdata, quieterrors, dry_run_exec)
|
||||
pid, pipein, pipeout = fork_off_task(self.cookercfg, self.data, self.databuilder, self.workerdata, fn, task, taskname, appends, taskdepdata, self.extraconfigdata, quieterrors, dry_run_exec)
|
||||
|
||||
self.build_pids[pid] = task
|
||||
self.build_pipes[pid] = runQueueWorkerPipe(pipein, pipeout)
|
||||
|
||||
@@ -4,8 +4,18 @@
|
||||
#
|
||||
# Copyright (C) 2005 Holger Hans Peter Freyther
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# 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 optparse, os, sys
|
||||
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
#
|
||||
|
||||
"""git-make-shallow: make the current git repository shallow
|
||||
|
||||
Remove the history of the specified revisions, then optionally filter the
|
||||
|
||||
@@ -3,17 +3,25 @@
|
||||
# toaster - shell script to start Toaster
|
||||
|
||||
# Copyright (C) 2013-2015 Intel Corp.
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
# 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, see http://www.gnu.org/licenses/.
|
||||
|
||||
HELP="
|
||||
Usage: source toaster start|stop [webport=<address:port>] [noweb] [nobuild] [toasterdir]
|
||||
Usage: source toaster start|stop [webport=<address:port>] [noweb]
|
||||
Optional arguments:
|
||||
[nobuild] Setup the environment for capturing builds with toaster but disable managed builds
|
||||
[noweb] Setup the environment for capturing builds with toaster but don't start the web server
|
||||
[noweb] Setup the environment for building with toaster but don't start the development server
|
||||
[webport] Set the development server (default: localhost:8000)
|
||||
[toasterdir] Set absolute path to be used as TOASTER_DIR (default: BUILDDIR/../)
|
||||
"
|
||||
|
||||
custom_extention()
|
||||
@@ -59,7 +67,7 @@ webserverKillAll()
|
||||
if [ -f ${pidfile} ]; then
|
||||
pid=`cat ${pidfile}`
|
||||
while kill -0 $pid 2>/dev/null; do
|
||||
kill -SIGTERM $pid 2>/dev/null
|
||||
kill -SIGTERM -$pid 2>/dev/null
|
||||
sleep 1
|
||||
done
|
||||
rm ${pidfile}
|
||||
@@ -82,7 +90,7 @@ webserverStartAll()
|
||||
|
||||
echo "Starting webserver..."
|
||||
|
||||
$MANAGE runserver --noreload "$ADDR_PORT" \
|
||||
$MANAGE runserver "$ADDR_PORT" \
|
||||
</dev/null >>${BUILDDIR}/toaster_web.log 2>&1 \
|
||||
& echo $! >${BUILDDIR}/.toastermain.pid
|
||||
|
||||
@@ -151,9 +159,7 @@ fi
|
||||
|
||||
export BBBASEDIR=`dirname $TOASTER`/..
|
||||
MANAGE="python3 $BBBASEDIR/lib/toaster/manage.py"
|
||||
if [ -z "$OE_ROOT" ]; then
|
||||
OE_ROOT=`dirname $TOASTER`/../..
|
||||
fi
|
||||
OE_ROOT=`dirname $TOASTER`/../..
|
||||
|
||||
# this is the configuraton file we are using for toaster
|
||||
# we are using the same logic that oe-setup-builddir uses
|
||||
@@ -177,18 +183,13 @@ unset OE_ROOT
|
||||
|
||||
|
||||
WEBSERVER=1
|
||||
export TOASTER_BUILDSERVER=1
|
||||
ADDR_PORT="localhost:8000"
|
||||
TOASTERDIR=`dirname $BUILDDIR`
|
||||
unset CMD
|
||||
for param in $*; do
|
||||
case $param in
|
||||
noweb )
|
||||
WEBSERVER=0
|
||||
;;
|
||||
nobuild )
|
||||
TOASTER_BUILDSERVER=0
|
||||
;;
|
||||
start )
|
||||
CMD=$param
|
||||
;;
|
||||
@@ -205,9 +206,6 @@ for param in $*; do
|
||||
ADDR_PORT="localhost:$PORT"
|
||||
fi
|
||||
;;
|
||||
toasterdir=*)
|
||||
TOASTERDIR="${param#*=}"
|
||||
;;
|
||||
--help)
|
||||
echo "$HELP"
|
||||
return 0
|
||||
@@ -238,7 +236,7 @@ fi
|
||||
# 2) the build dir (in build)
|
||||
# 3) the sqlite db if that is being used.
|
||||
# 4) pid's we need to clean up on exit/shutdown
|
||||
export TOASTER_DIR=$TOASTERDIR
|
||||
export TOASTER_DIR=`dirname $BUILDDIR`
|
||||
export BB_ENV_EXTRAWHITE="$BB_ENV_EXTRAWHITE TOASTER_DIR"
|
||||
|
||||
# Determine the action. If specified by arguments, fine, if not, toggle it
|
||||
@@ -288,13 +286,9 @@ case $CMD in
|
||||
return 4
|
||||
fi
|
||||
export BITBAKE_UI='toasterui'
|
||||
if [ $TOASTER_BUILDSERVER -eq 1 ] ; then
|
||||
$MANAGE runbuilds \
|
||||
</dev/null >>${BUILDDIR}/toaster_runbuilds.log 2>&1 \
|
||||
& echo $! >${BUILDDIR}/.runbuilds.pid
|
||||
else
|
||||
echo "Toaster build server not started."
|
||||
fi
|
||||
$MANAGE runbuilds \
|
||||
</dev/null >>${BUILDDIR}/toaster_runbuilds.log 2>&1 \
|
||||
& echo $! >${BUILDDIR}/.runbuilds.pid
|
||||
|
||||
# set fail safe stop system on terminal exit
|
||||
trap stop_system SIGHUP
|
||||
|
||||
@@ -4,11 +4,22 @@
|
||||
#
|
||||
# Copyright (C) 2014 Alex Damian
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
#
|
||||
# This file re-uses code spread throughout other Bitbake source files.
|
||||
# As such, all other copyrights belong to their own right holders.
|
||||
#
|
||||
#
|
||||
# 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 command takes a filename as a single parameter. The filename is read
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# ex:ts=4:sw=4:sts=4:et
|
||||
# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
|
||||
#
|
||||
# Copyright (C) 2012, 2018 Wind River Systems, Inc.
|
||||
# Copyright (C) 2012 Wind River Systems, Inc.
|
||||
#
|
||||
# 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
|
||||
@@ -18,68 +18,51 @@
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
#
|
||||
# Used for dumping the bb_cache.dat
|
||||
# This is used for dumping the bb_cache.dat, the output format is:
|
||||
# recipe_path PN PV PACKAGES
|
||||
#
|
||||
import os
|
||||
import sys
|
||||
import argparse
|
||||
import warnings
|
||||
|
||||
# For importing bb.cache
|
||||
sys.path.insert(0, os.path.join(os.path.abspath(os.path.dirname(sys.argv[0])), '../lib'))
|
||||
from bb.cache import CoreRecipeInfo
|
||||
|
||||
import pickle
|
||||
import pickle as pickle
|
||||
|
||||
class DumpCache(object):
|
||||
def __init__(self):
|
||||
parser = argparse.ArgumentParser(
|
||||
description="bb_cache.dat's dumper",
|
||||
epilog="Use %(prog)s --help to get help")
|
||||
parser.add_argument("-r", "--recipe",
|
||||
help="specify the recipe, default: all recipes", action="store")
|
||||
parser.add_argument("-m", "--members",
|
||||
help = "specify the member, use comma as separator for multiple ones, default: all members", action="store", default="")
|
||||
parser.add_argument("-s", "--skip",
|
||||
help = "skip skipped recipes", action="store_true")
|
||||
parser.add_argument("cachefile",
|
||||
help = "specify bb_cache.dat", nargs = 1, action="store", default="")
|
||||
def main(argv=None):
|
||||
"""
|
||||
Get the mapping for the target recipe.
|
||||
"""
|
||||
if len(argv) != 1:
|
||||
print("Error, need one argument!", file=sys.stderr)
|
||||
return 2
|
||||
|
||||
self.args = parser.parse_args()
|
||||
cachefile = argv[0]
|
||||
|
||||
def main(self):
|
||||
with open(self.args.cachefile[0], "rb") as cachefile:
|
||||
pickled = pickle.Unpickler(cachefile)
|
||||
while True:
|
||||
try:
|
||||
key = pickled.load()
|
||||
val = pickled.load()
|
||||
except Exception:
|
||||
break
|
||||
if isinstance(val, CoreRecipeInfo):
|
||||
pn = val.pn
|
||||
with open(cachefile, "rb") as cachefile:
|
||||
pickled = pickle.Unpickler(cachefile)
|
||||
while cachefile:
|
||||
try:
|
||||
key = pickled.load()
|
||||
val = pickled.load()
|
||||
except Exception:
|
||||
break
|
||||
if isinstance(val, CoreRecipeInfo) and (not val.skipped):
|
||||
pn = val.pn
|
||||
# Filter out the native recipes.
|
||||
if key.startswith('virtual:native:') or pn.endswith("-native"):
|
||||
continue
|
||||
|
||||
if self.args.recipe and self.args.recipe != pn:
|
||||
continue
|
||||
# 1.0 is the default version for a no PV recipe.
|
||||
if "pv" in val.__dict__:
|
||||
pv = val.pv
|
||||
else:
|
||||
pv = "1.0"
|
||||
|
||||
if self.args.skip and val.skipped:
|
||||
continue
|
||||
|
||||
if self.args.members:
|
||||
out = key
|
||||
for member in self.args.members.split(','):
|
||||
out += ": %s" % val.__dict__.get(member)
|
||||
print("%s" % out)
|
||||
else:
|
||||
print("%s: %s" % (key, val.__dict__))
|
||||
elif not self.args.recipe:
|
||||
print("%s %s" % (key, val))
|
||||
print("%s %s %s %s" % (key, pn, pv, ' '.join(val.packages)))
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
dump = DumpCache()
|
||||
ret = dump.main()
|
||||
except Exception as esc:
|
||||
ret = 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
sys.exit(ret)
|
||||
sys.exit(main(sys.argv[1:]))
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
<para>
|
||||
Prior to executing BitBake, you should take advantage of available
|
||||
parallel thread execution on your build host by setting the
|
||||
<link linkend='var-bb-BB_NUMBER_THREADS'><filename>BB_NUMBER_THREADS</filename></link>
|
||||
<link linkend='var-BB_NUMBER_THREADS'><filename>BB_NUMBER_THREADS</filename></link>
|
||||
variable in your project's <filename>local.conf</filename>
|
||||
configuration file.
|
||||
</para>
|
||||
@@ -87,9 +87,9 @@
|
||||
<para>
|
||||
The <filename>layer.conf</filename> files are used to
|
||||
construct key variables such as
|
||||
<link linkend='var-bb-BBPATH'><filename>BBPATH</filename></link>
|
||||
<link linkend='var-BBPATH'><filename>BBPATH</filename></link>
|
||||
and
|
||||
<link linkend='var-bb-BBFILES'><filename>BBFILES</filename></link>.
|
||||
<link linkend='var-BBFILES'><filename>BBFILES</filename></link>.
|
||||
<filename>BBPATH</filename> is used to search for
|
||||
configuration and class files under the
|
||||
<filename>conf</filename> and <filename>classes</filename>
|
||||
@@ -117,19 +117,19 @@
|
||||
at certain variables, including:
|
||||
<itemizedlist>
|
||||
<listitem><para>
|
||||
<link linkend='var-bb-BB_ENV_WHITELIST'><filename>BB_ENV_WHITELIST</filename></link>
|
||||
<link linkend='var-BB_ENV_WHITELIST'><filename>BB_ENV_WHITELIST</filename></link>
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
<link linkend='var-bb-BB_ENV_EXTRAWHITE'><filename>BB_ENV_EXTRAWHITE</filename></link>
|
||||
<link linkend='var-BB_ENV_EXTRAWHITE'><filename>BB_ENV_EXTRAWHITE</filename></link>
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
<link linkend='var-bb-BB_PRESERVE_ENV'><filename>BB_PRESERVE_ENV</filename></link>
|
||||
<link linkend='var-BB_PRESERVE_ENV'><filename>BB_PRESERVE_ENV</filename></link>
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
<link linkend='var-bb-BB_ORIGENV'><filename>BB_ORIGENV</filename></link>
|
||||
<link linkend='var-BB_ORIGENV'><filename>BB_ORIGENV</filename></link>
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
<link linkend='var-bb-BITBAKE_UI'><filename>BITBAKE_UI</filename></link>
|
||||
<link linkend='var-BITBAKE_UI'><filename>BITBAKE_UI</filename></link>
|
||||
</para></listitem>
|
||||
</itemizedlist>
|
||||
The first four variables in this list relate to how BitBake treats shell
|
||||
@@ -156,7 +156,7 @@
|
||||
BitBake first searches the current working directory for an
|
||||
optional <filename>conf/bblayers.conf</filename> configuration file.
|
||||
This file is expected to contain a
|
||||
<link linkend='var-bb-BBLAYERS'><filename>BBLAYERS</filename></link>
|
||||
<link linkend='var-BBLAYERS'><filename>BBLAYERS</filename></link>
|
||||
variable that is a space-delimited list of 'layer' directories.
|
||||
Recall that if BitBake cannot find a <filename>bblayers.conf</filename>
|
||||
file, then it is assumed the user has set the <filename>BBPATH</filename>
|
||||
@@ -166,10 +166,10 @@
|
||||
<para>
|
||||
For each directory (layer) in this list, a <filename>conf/layer.conf</filename>
|
||||
file is located and parsed with the
|
||||
<link linkend='var-bb-LAYERDIR'><filename>LAYERDIR</filename></link>
|
||||
<link linkend='var-LAYERDIR'><filename>LAYERDIR</filename></link>
|
||||
variable being set to the directory where the layer was found.
|
||||
The idea is these files automatically set up
|
||||
<link linkend='var-bb-BBPATH'><filename>BBPATH</filename></link>
|
||||
<link linkend='var-BBPATH'><filename>BBPATH</filename></link>
|
||||
and other variables correctly for a given build directory.
|
||||
</para>
|
||||
|
||||
@@ -189,7 +189,7 @@
|
||||
depending on the environment variables previously
|
||||
mentioned or set in the configuration files.
|
||||
The
|
||||
"<link linkend='ref-bb-variables-glos'>Variables Glossary</link>"
|
||||
"<link linkend='ref-variables-glos'>Variables Glossary</link>"
|
||||
chapter presents a full list of variables.
|
||||
</para>
|
||||
|
||||
@@ -204,7 +204,7 @@
|
||||
<para>
|
||||
The <filename>base.bbclass</filename> file is always included.
|
||||
Other classes that are specified in the configuration using the
|
||||
<link linkend='var-bb-INHERIT'><filename>INHERIT</filename></link>
|
||||
<link linkend='var-INHERIT'><filename>INHERIT</filename></link>
|
||||
variable are also included.
|
||||
BitBake searches for class files in a
|
||||
<filename>classes</filename> subdirectory under
|
||||
@@ -270,7 +270,7 @@
|
||||
|
||||
<para>
|
||||
During the configuration phase, BitBake will have set
|
||||
<link linkend='var-bb-BBFILES'><filename>BBFILES</filename></link>.
|
||||
<link linkend='var-BBFILES'><filename>BBFILES</filename></link>.
|
||||
BitBake now uses it to construct a list of recipes to parse,
|
||||
along with any append files (<filename>.bbappend</filename>)
|
||||
to apply.
|
||||
@@ -292,7 +292,7 @@
|
||||
Any inherit statements cause BitBake to find and
|
||||
then parse class files (<filename>.bbclass</filename>)
|
||||
using
|
||||
<link linkend='var-bb-BBPATH'><filename>BBPATH</filename></link>
|
||||
<link linkend='var-BBPATH'><filename>BBPATH</filename></link>
|
||||
as the search path.
|
||||
Finally, BitBake parses in order any append files found in
|
||||
<filename>BBFILES</filename>.
|
||||
@@ -303,8 +303,8 @@
|
||||
pieces of metadata.
|
||||
For example, in <filename>bitbake.conf</filename> the recipe
|
||||
name and version are used to set the variables
|
||||
<link linkend='var-bb-PN'><filename>PN</filename></link> and
|
||||
<link linkend='var-bb-PV'><filename>PV</filename></link>:
|
||||
<link linkend='var-PN'><filename>PN</filename></link> and
|
||||
<link linkend='var-PV'><filename>PV</filename></link>:
|
||||
<literallayout class='monospaced'>
|
||||
PN = "${@bb.parse.BBHandler.vars_from_file(d.getVar('FILE', False),d)[0] or 'defaultpkgname'}"
|
||||
PV = "${@bb.parse.BBHandler.vars_from_file(d.getVar('FILE', False),d)[1] or '1.0'}"
|
||||
@@ -336,7 +336,7 @@
|
||||
recipe information.
|
||||
The validity of this cache is determined by first computing a
|
||||
checksum of the base configuration data (see
|
||||
<link linkend='var-bb-BB_HASHCONFIG_WHITELIST'><filename>BB_HASHCONFIG_WHITELIST</filename></link>)
|
||||
<link linkend='var-BB_HASHCONFIG_WHITELIST'><filename>BB_HASHCONFIG_WHITELIST</filename></link>)
|
||||
and then checking if the checksum matches.
|
||||
If that checksum matches what is in the cache and the recipe
|
||||
and class files have not changed, Bitbake is able to use
|
||||
@@ -384,9 +384,9 @@
|
||||
the recipe can be known.
|
||||
Each recipe's <filename>PROVIDES</filename> list is created
|
||||
implicitly through the recipe's
|
||||
<link linkend='var-bb-PN'><filename>PN</filename></link> variable
|
||||
<link linkend='var-PN'><filename>PN</filename></link> variable
|
||||
and explicitly through the recipe's
|
||||
<link linkend='var-bb-PROVIDES'><filename>PROVIDES</filename></link>
|
||||
<link linkend='var-PROVIDES'><filename>PROVIDES</filename></link>
|
||||
variable, which is optional.
|
||||
</para>
|
||||
|
||||
@@ -427,7 +427,7 @@
|
||||
PREFERRED_PROVIDER_virtual/kernel = "linux-yocto"
|
||||
</literallayout>
|
||||
The default
|
||||
<link linkend='var-bb-PREFERRED_PROVIDER'><filename>PREFERRED_PROVIDER</filename></link>
|
||||
<link linkend='var-PREFERRED_PROVIDER'><filename>PREFERRED_PROVIDER</filename></link>
|
||||
is the provider with the same name as the target.
|
||||
Bitbake iterates through each target it needs to build and
|
||||
resolves them and their dependencies using this process.
|
||||
@@ -439,10 +439,10 @@
|
||||
BitBake defaults to the highest version of a provider.
|
||||
Version comparisons are made using the same method as Debian.
|
||||
You can use the
|
||||
<link linkend='var-bb-PREFERRED_VERSION'><filename>PREFERRED_VERSION</filename></link>
|
||||
<link linkend='var-PREFERRED_VERSION'><filename>PREFERRED_VERSION</filename></link>
|
||||
variable to specify a particular version.
|
||||
You can influence the order by using the
|
||||
<link linkend='var-bb-DEFAULT_PREFERENCE'><filename>DEFAULT_PREFERENCE</filename></link>
|
||||
<link linkend='var-DEFAULT_PREFERENCE'><filename>DEFAULT_PREFERENCE</filename></link>
|
||||
variable.
|
||||
</para>
|
||||
|
||||
@@ -464,7 +464,7 @@
|
||||
BitBake defaults to selecting the most recent
|
||||
version, unless otherwise specified.
|
||||
If the recipe in question has a
|
||||
<link linkend='var-bb-DEFAULT_PREFERENCE'><filename>DEFAULT_PREFERENCE</filename></link>
|
||||
<link linkend='var-DEFAULT_PREFERENCE'><filename>DEFAULT_PREFERENCE</filename></link>
|
||||
set lower than the other recipes (default is 0), then
|
||||
it will not be selected.
|
||||
This allows the person or persons maintaining
|
||||
@@ -475,9 +475,9 @@
|
||||
|
||||
<para>
|
||||
If the first recipe is named <filename>a_1.1.bb</filename>, then the
|
||||
<link linkend='var-bb-PN'><filename>PN</filename></link> variable
|
||||
<link linkend='var-PN'><filename>PN</filename></link> variable
|
||||
will be set to “a”, and the
|
||||
<link linkend='var-bb-PV'><filename>PV</filename></link>
|
||||
<link linkend='var-PV'><filename>PV</filename></link>
|
||||
variable will be set to 1.1.
|
||||
</para>
|
||||
|
||||
@@ -532,11 +532,11 @@
|
||||
<para>
|
||||
Dependencies are defined through several variables.
|
||||
You can find information about variables BitBake uses in
|
||||
the <link linkend='ref-bb-variables-glos'>Variables Glossary</link>
|
||||
the <link linkend='ref-variables-glos'>Variables Glossary</link>
|
||||
near the end of this manual.
|
||||
At a basic level, it is sufficient to know that BitBake uses the
|
||||
<link linkend='var-bb-DEPENDS'><filename>DEPENDS</filename></link> and
|
||||
<link linkend='var-bb-RDEPENDS'><filename>RDEPENDS</filename></link> variables when
|
||||
<link linkend='var-DEPENDS'><filename>DEPENDS</filename></link> and
|
||||
<link linkend='var-RDEPENDS'><filename>RDEPENDS</filename></link> variables when
|
||||
calculating dependencies.
|
||||
</para>
|
||||
|
||||
@@ -560,7 +560,7 @@
|
||||
|
||||
<para>
|
||||
The build now starts with BitBake forking off threads up to the limit set in the
|
||||
<link linkend='var-bb-BB_NUMBER_THREADS'><filename>BB_NUMBER_THREADS</filename></link>
|
||||
<link linkend='var-BB_NUMBER_THREADS'><filename>BB_NUMBER_THREADS</filename></link>
|
||||
variable.
|
||||
BitBake continues to fork threads as long as there are tasks ready to run,
|
||||
those tasks have all their dependencies met, and the thread threshold has not been
|
||||
@@ -574,7 +574,7 @@
|
||||
|
||||
<para>
|
||||
As each task completes, a timestamp is written to the directory specified by the
|
||||
<link linkend='var-bb-STAMP'><filename>STAMP</filename></link> variable.
|
||||
<link linkend='var-STAMP'><filename>STAMP</filename></link> variable.
|
||||
On subsequent runs, BitBake looks in the build directory within
|
||||
<filename>tmp/stamps</filename> and does not rerun
|
||||
tasks that are already completed unless a timestamp is found to be invalid.
|
||||
@@ -618,7 +618,7 @@
|
||||
<para>
|
||||
Tasks can be either a shell task or a Python task.
|
||||
For shell tasks, BitBake writes a shell script to
|
||||
<filename>${</filename><link linkend='var-bb-T'><filename>T</filename></link><filename>}/run.do_taskname.pid</filename>
|
||||
<filename>${</filename><link linkend='var-T'><filename>T</filename></link><filename>}/run.do_taskname.pid</filename>
|
||||
and then executes the script.
|
||||
The generated shell script contains all the exported variables,
|
||||
and the shell functions with all variables expanded.
|
||||
@@ -645,10 +645,10 @@
|
||||
behavior:
|
||||
<itemizedlist>
|
||||
<listitem><para>
|
||||
<link linkend='var-bb-BB_SCHEDULER'><filename>BB_SCHEDULER</filename></link>
|
||||
<link linkend='var-BB_SCHEDULER'><filename>BB_SCHEDULER</filename></link>
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
<link linkend='var-bb-BB_SCHEDULERS'><filename>BB_SCHEDULERS</filename></link>
|
||||
<link linkend='var-BB_SCHEDULERS'><filename>BB_SCHEDULERS</filename></link>
|
||||
</para></listitem>
|
||||
</itemizedlist>
|
||||
It is possible to have functions run before and after a task's main
|
||||
@@ -684,7 +684,7 @@
|
||||
The simplistic approach for excluding the working directory is to set
|
||||
it to some fixed value and create the checksum for the "run" script.
|
||||
BitBake goes one step better and uses the
|
||||
<link linkend='var-bb-BB_HASHBASE_WHITELIST'><filename>BB_HASHBASE_WHITELIST</filename></link>
|
||||
<link linkend='var-BB_HASHBASE_WHITELIST'><filename>BB_HASHBASE_WHITELIST</filename></link>
|
||||
variable to define a list of variables that should never be included
|
||||
when generating the signatures.
|
||||
</para>
|
||||
@@ -781,7 +781,7 @@
|
||||
The code in <filename>meta/lib/oe/sstatesig.py</filename> shows two examples
|
||||
of this and also illustrates how you can insert your own policy into the system
|
||||
if so desired.
|
||||
This file defines the two basic signature generators OpenEmbedded-Core
|
||||
This file defines the two basic signature generators OpenEmbedded Core
|
||||
uses: "OEBasic" and "OEBasicHash".
|
||||
By default, there is a dummy "noop" signature handler enabled in BitBake.
|
||||
This means that behavior is unchanged from previous versions.
|
||||
@@ -795,7 +795,7 @@
|
||||
This results in any metadata change that changes the task hash, automatically
|
||||
causing the task to be run again.
|
||||
This removes the need to bump
|
||||
<link linkend='var-bb-PR'><filename>PR</filename></link>
|
||||
<link linkend='var-PR'><filename>PR</filename></link>
|
||||
values, and changes to metadata automatically ripple across the build.
|
||||
</para>
|
||||
|
||||
@@ -884,7 +884,7 @@
|
||||
|
||||
<para>
|
||||
BitBake first calls the function defined by the
|
||||
<link linkend='var-bb-BB_HASHCHECK_FUNCTION'><filename>BB_HASHCHECK_FUNCTION</filename></link>
|
||||
<link linkend='var-BB_HASHCHECK_FUNCTION'><filename>BB_HASHCHECK_FUNCTION</filename></link>
|
||||
variable with a list of tasks and corresponding
|
||||
hashes it wants to build.
|
||||
This function is designed to be fast and returns a list
|
||||
@@ -908,7 +908,7 @@
|
||||
For example, it is pointless to obtain a compiler if you
|
||||
already have the compiled binary.
|
||||
To handle this, BitBake calls the
|
||||
<link linkend='var-bb-BB_SETSCENE_DEPVALID'><filename>BB_SETSCENE_DEPVALID</filename></link>
|
||||
<link linkend='var-BB_SETSCENE_DEPVALID'><filename>BB_SETSCENE_DEPVALID</filename></link>
|
||||
function for each successful setscene task to know whether or not it needs
|
||||
to obtain the dependencies of that task.
|
||||
</para>
|
||||
@@ -916,7 +916,7 @@
|
||||
<para>
|
||||
Finally, after all the setscene tasks have executed, BitBake calls the
|
||||
function listed in
|
||||
<link linkend='var-bb-BB_SETSCENE_VERIFY_FUNCTION2'><filename>BB_SETSCENE_VERIFY_FUNCTION2</filename></link>
|
||||
<link linkend='var-BB_SETSCENE_VERIFY_FUNCTION2'><filename>BB_SETSCENE_VERIFY_FUNCTION2</filename></link>
|
||||
with the list of tasks BitBake thinks has been "covered".
|
||||
The metadata can then ensure that this list is correct and can
|
||||
inform BitBake that it wants specific tasks to be run regardless
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
</literallayout>
|
||||
This code sets up an instance of the fetch class.
|
||||
The instance uses a space-separated list of URLs from the
|
||||
<link linkend='var-bb-SRC_URI'><filename>SRC_URI</filename></link>
|
||||
<link linkend='var-SRC_URI'><filename>SRC_URI</filename></link>
|
||||
variable and then calls the <filename>download</filename>
|
||||
method to download the files.
|
||||
</para>
|
||||
@@ -78,7 +78,7 @@
|
||||
<listitem><para><emphasis>Pre-mirror Sites:</emphasis>
|
||||
BitBake first uses pre-mirrors to try and find source files.
|
||||
These locations are defined using the
|
||||
<link linkend='var-bb-PREMIRRORS'><filename>PREMIRRORS</filename></link>
|
||||
<link linkend='var-PREMIRRORS'><filename>PREMIRRORS</filename></link>
|
||||
variable.
|
||||
</para></listitem>
|
||||
<listitem><para><emphasis>Source URI:</emphasis>
|
||||
@@ -88,7 +88,7 @@
|
||||
<listitem><para><emphasis>Mirror Sites:</emphasis>
|
||||
If fetch failures occur, BitBake next uses mirror locations as
|
||||
defined by the
|
||||
<link linkend='var-bb-MIRRORS'><filename>MIRRORS</filename></link>
|
||||
<link linkend='var-MIRRORS'><filename>MIRRORS</filename></link>
|
||||
variable.
|
||||
</para></listitem>
|
||||
</itemizedlist>
|
||||
@@ -144,7 +144,7 @@
|
||||
Any source files that are not local (i.e.
|
||||
downloaded from the Internet) are placed into the download
|
||||
directory, which is specified by the
|
||||
<link linkend='var-bb-DL_DIR'><filename>DL_DIR</filename></link>
|
||||
<link linkend='var-DL_DIR'><filename>DL_DIR</filename></link>
|
||||
variable.
|
||||
</para>
|
||||
|
||||
@@ -184,11 +184,11 @@
|
||||
|
||||
<para>
|
||||
If
|
||||
<link linkend='var-bb-BB_STRICT_CHECKSUM'><filename>BB_STRICT_CHECKSUM</filename></link>
|
||||
<link linkend='var-BB_STRICT_CHECKSUM'><filename>BB_STRICT_CHECKSUM</filename></link>
|
||||
is set, any download without a checksum triggers an
|
||||
error message.
|
||||
The
|
||||
<link linkend='var-bb-BB_NO_NETWORK'><filename>BB_NO_NETWORK</filename></link>
|
||||
<link linkend='var-BB_NO_NETWORK'><filename>BB_NO_NETWORK</filename></link>
|
||||
variable can be used to make any attempted network access a fatal
|
||||
error, which is useful for checking that mirrors are complete
|
||||
as well as other things.
|
||||
@@ -265,11 +265,11 @@
|
||||
The filename you specify within the URL can be
|
||||
either an absolute or relative path to a file.
|
||||
If the filename is relative, the contents of the
|
||||
<link linkend='var-bb-FILESPATH'><filename>FILESPATH</filename></link>
|
||||
<link linkend='var-FILESPATH'><filename>FILESPATH</filename></link>
|
||||
variable is used in the same way
|
||||
<filename>PATH</filename> is used to find executables.
|
||||
If the file cannot be found, it is assumed that it is available in
|
||||
<link linkend='var-bb-DL_DIR'><filename>DL_DIR</filename></link>
|
||||
<link linkend='var-DL_DIR'><filename>DL_DIR</filename></link>
|
||||
by the time the <filename>download()</filename> method is called.
|
||||
</para>
|
||||
|
||||
@@ -304,7 +304,7 @@
|
||||
allows the name of the downloaded file to be specified.
|
||||
Specifying the name of the downloaded file is useful
|
||||
for avoiding collisions in
|
||||
<link linkend='var-bb-DL_DIR'><filename>DL_DIR</filename></link>
|
||||
<link linkend='var-DL_DIR'><filename>DL_DIR</filename></link>
|
||||
when dealing with multiple files that have the same name.
|
||||
</para>
|
||||
|
||||
@@ -355,7 +355,7 @@
|
||||
A special value of "now" causes the checkout to
|
||||
be updated on every build.
|
||||
</para></listitem>
|
||||
<listitem><para><emphasis><link linkend='var-bb-CVSDIR'><filename>CVSDIR</filename></link>:</emphasis>
|
||||
<listitem><para><emphasis><link linkend='var-CVSDIR'><filename>CVSDIR</filename></link>:</emphasis>
|
||||
Specifies where a temporary checkout is saved.
|
||||
The location is often <filename>DL_DIR/cvs</filename>.
|
||||
</para></listitem>
|
||||
@@ -395,7 +395,7 @@
|
||||
<listitem><para><emphasis>"date":</emphasis>
|
||||
Specifies a date.
|
||||
If no "date" is specified, the
|
||||
<link linkend='var-bb-SRCDATE'><filename>SRCDATE</filename></link>
|
||||
<link linkend='var-SRCDATE'><filename>SRCDATE</filename></link>
|
||||
of the configuration is used to checkout a specific date.
|
||||
The special value of "now" causes the checkout to be
|
||||
updated on every build.
|
||||
@@ -406,7 +406,7 @@
|
||||
to which the module is unpacked.
|
||||
You are forcing the module into a special
|
||||
directory relative to
|
||||
<link linkend='var-bb-CVSDIR'><filename>CVSDIR</filename></link>.
|
||||
<link linkend='var-CVSDIR'><filename>CVSDIR</filename></link>.
|
||||
</para></listitem>
|
||||
<listitem><para><emphasis>"rsh"</emphasis>
|
||||
Used in conjunction with the "method" parameter.
|
||||
@@ -448,7 +448,7 @@
|
||||
<filename>FETCHCMD_svn</filename>, which defaults
|
||||
to "svn".
|
||||
The fetcher's temporary working directory is set by
|
||||
<link linkend='var-bb-SVNDIR'><filename>SVNDIR</filename></link>,
|
||||
<link linkend='var-SVNDIR'><filename>SVNDIR</filename></link>,
|
||||
which is usually <filename>DL_DIR/svn</filename>.
|
||||
</para>
|
||||
|
||||
@@ -509,7 +509,7 @@
|
||||
source control system.
|
||||
The fetcher works by creating a bare clone of the
|
||||
remote into
|
||||
<link linkend='var-bb-GITDIR'><filename>GITDIR</filename></link>,
|
||||
<link linkend='var-GITDIR'><filename>GITDIR</filename></link>,
|
||||
which is usually <filename>DL_DIR/git2</filename>.
|
||||
This bare clone is then cloned into the work directory during the
|
||||
unpack stage when a specific tree is checked out.
|
||||
@@ -588,14 +588,6 @@
|
||||
The name of the path in which to place the checkout.
|
||||
By default, the path is <filename>git/</filename>.
|
||||
</para></listitem>
|
||||
<listitem><para><emphasis>"usehead":</emphasis>
|
||||
Enables local <filename>git://</filename> URLs to use the
|
||||
current branch HEAD as the revision for use with
|
||||
<filename>AUTOREV</filename>.
|
||||
The "usehead" parameter implies no branch and only works
|
||||
when the transfer protocol is
|
||||
<filename>file://</filename>.
|
||||
</para></listitem>
|
||||
</itemizedlist>
|
||||
Here are some example URLs:
|
||||
<literallayout class='monospaced'>
|
||||
@@ -612,7 +604,7 @@
|
||||
This fetcher submodule inherits from the
|
||||
<link linkend='git-fetcher'>Git fetcher</link> and extends
|
||||
that fetcher's behavior by fetching a repository's submodules.
|
||||
<link linkend='var-bb-SRC_URI'><filename>SRC_URI</filename></link>
|
||||
<link linkend='var-SRC_URI'><filename>SRC_URI</filename></link>
|
||||
is passed to the Git fetcher as described in the
|
||||
"<link linkend='git-fetcher'>Git Fetcher (<filename>git://</filename>)</link>"
|
||||
section.
|
||||
@@ -647,9 +639,9 @@
|
||||
|
||||
<para>
|
||||
To use this fetcher, make sure your recipe has proper
|
||||
<link linkend='var-bb-SRC_URI'><filename>SRC_URI</filename></link>,
|
||||
<link linkend='var-bb-SRCREV'><filename>SRCREV</filename></link>, and
|
||||
<link linkend='var-bb-PV'><filename>PV</filename></link> settings.
|
||||
<link linkend='var-SRC_URI'><filename>SRC_URI</filename></link>,
|
||||
<link linkend='var-SRCREV'><filename>SRCREV</filename></link>, and
|
||||
<link linkend='var-PV'><filename>PV</filename></link> settings.
|
||||
Here is an example:
|
||||
<literallayout class='monospaced'>
|
||||
SRC_URI = "ccrc://cc.example.org/ccrc;vob=/example_vob;module=/example_module"
|
||||
@@ -734,15 +726,15 @@
|
||||
<filename>FETCHCMD_p4</filename>, which defaults
|
||||
to "p4".
|
||||
The fetcher's temporary working directory is set by
|
||||
<link linkend='var-bb-P4DIR'><filename>P4DIR</filename></link>,
|
||||
<link linkend='var-P4DIR'><filename>P4DIR</filename></link>,
|
||||
which defaults to "DL_DIR/p4".
|
||||
</para>
|
||||
|
||||
<para>
|
||||
To use this fetcher, make sure your recipe has proper
|
||||
<link linkend='var-bb-SRC_URI'><filename>SRC_URI</filename></link>,
|
||||
<link linkend='var-bb-SRCREV'><filename>SRCREV</filename></link>, and
|
||||
<link linkend='var-bb-PV'><filename>PV</filename></link> values.
|
||||
<link linkend='var-SRC_URI'><filename>SRC_URI</filename></link>,
|
||||
<link linkend='var-SRCREV'><filename>SRCREV</filename></link>, and
|
||||
<link linkend='var-PV'><filename>PV</filename></link> values.
|
||||
The p4 executable is able to use the config file defined by your
|
||||
system's <filename>P4CONFIG</filename> environment variable in
|
||||
order to define the Perforce server URL and port, username, and
|
||||
@@ -785,43 +777,6 @@
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id='repo-fetcher'>
|
||||
<title>Repo Fetcher (<filename>repo://</filename>)</title>
|
||||
|
||||
<para>
|
||||
This fetcher submodule fetches code from
|
||||
<filename>google-repo</filename> source control system.
|
||||
The fetcher works by initiating and syncing sources of the
|
||||
repository into
|
||||
<link linkend='var-bb-REPODIR'><filename>REPODIR</filename></link>,
|
||||
which is usually
|
||||
<link linkend='var-bb-DL_DIR'><filename>DL_DIR</filename></link><filename>/repo</filename>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
This fetcher supports the following parameters:
|
||||
<itemizedlist>
|
||||
<listitem><para>
|
||||
<emphasis>"protocol":</emphasis>
|
||||
Protocol to fetch the repository manifest (default: git).
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
<emphasis>"branch":</emphasis>
|
||||
Branch or tag of repository to get (default: master).
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
<emphasis>"manifest":</emphasis>
|
||||
Name of the manifest file (default: <filename>default.xml</filename>).
|
||||
</para></listitem>
|
||||
</itemizedlist>
|
||||
Here are some example URLs:
|
||||
<literallayout class='monospaced'>
|
||||
SRC_URI = "repo://REPOROOT;protocol=git;branch=some_branch;manifest=my_manifest.xml"
|
||||
SRC_URI = "repo://REPOROOT;protocol=file;branch=some_branch;manifest=my_manifest.xml"
|
||||
</literallayout>
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id='other-fetchers'>
|
||||
<title>Other Fetchers</title>
|
||||
|
||||
@@ -840,6 +795,9 @@
|
||||
<listitem><para>
|
||||
Secure Shell (<filename>ssh://</filename>)
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
Repo (<filename>repo://</filename>)
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
OSC (<filename>osc://</filename>)
|
||||
</para></listitem>
|
||||
|
||||
@@ -194,7 +194,7 @@
|
||||
<para>
|
||||
When you run BitBake, it begins looking for metadata files.
|
||||
The
|
||||
<link linkend='var-bb-BBPATH'><filename>BBPATH</filename></link>
|
||||
<link linkend='var-BBPATH'><filename>BBPATH</filename></link>
|
||||
variable is what tells BitBake where to look for those files.
|
||||
<filename>BBPATH</filename> is not set and you need to set it.
|
||||
Without <filename>BBPATH</filename>, Bitbake cannot
|
||||
@@ -260,7 +260,7 @@
|
||||
files.
|
||||
For this example, you need to create the file in your project directory
|
||||
and define some key BitBake variables.
|
||||
For more information on the <filename>bitbake.conf</filename> file,
|
||||
For more information on the <filename>bitbake.conf</filename>,
|
||||
see
|
||||
<ulink url='http://git.openembedded.org/bitbake/tree/conf/bitbake.conf'></ulink>.
|
||||
</para>
|
||||
@@ -273,32 +273,14 @@
|
||||
some editor to create the <filename>bitbake.conf</filename>
|
||||
so that it contains the following:
|
||||
<literallayout class='monospaced'>
|
||||
<link linkend='var-bb-PN'>PN</link> = "${@bb.parse.BBHandler.vars_from_file(d.getVar('FILE', False),d)[0] or 'defaultpkgname'}"
|
||||
TMPDIR = "${<link linkend='var-TOPDIR'>TOPDIR</link>}/tmp"
|
||||
<link linkend='var-CACHE'>CACHE</link> = "${TMPDIR}/cache"
|
||||
<link linkend='var-STAMP'>STAMP</link> = "${TMPDIR}/stamps"
|
||||
<link linkend='var-T'>T</link> = "${TMPDIR}/work"
|
||||
<link linkend='var-B'>B</link> = "${TMPDIR}"
|
||||
</literallayout>
|
||||
<literallayout class='monospaced'>
|
||||
TMPDIR = "${<link linkend='var-bb-TOPDIR'>TOPDIR</link>}/tmp"
|
||||
<link linkend='var-bb-CACHE'>CACHE</link> = "${TMPDIR}/cache"
|
||||
<link linkend='var-bb-STAMP'>STAMP</link> = "${TMPDIR}/${PN}/stamps"
|
||||
<link linkend='var-bb-T'>T</link> = "${TMPDIR}/${PN}/work"
|
||||
<link linkend='var-bb-B'>B</link> = "${TMPDIR}/${PN}"
|
||||
</literallayout>
|
||||
<note>
|
||||
Without a value for <filename>PN</filename>, the
|
||||
variables <filename>STAMP</filename>,
|
||||
<filename>T</filename>, and <filename>B</filename>,
|
||||
prevent more than one recipe from working. You can fix
|
||||
this by either setting <filename>PN</filename> to have
|
||||
a value similar to what OpenEmbedded and BitBake use
|
||||
in the default <filename>bitbake.conf</filename> file
|
||||
(see previous example). Or, by manually updating each
|
||||
recipe to set <filename>PN</filename>. You will also
|
||||
need to include <filename>PN</filename> as part of the
|
||||
<filename>STAMP</filename>, <filename>T</filename>, and
|
||||
<filename>B</filename> variable definitions in the
|
||||
<filename>local.conf</filename> file.
|
||||
</note>
|
||||
The <filename>TMPDIR</filename> variable establishes a directory
|
||||
that BitBake uses for build output and intermediate files other
|
||||
that BitBake uses for build output and intermediate files (other
|
||||
than the cached information used by the
|
||||
<link linkend='setscene'>Setscene</link> process.
|
||||
Here, the <filename>TMPDIR</filename> directory is set to
|
||||
@@ -318,19 +300,19 @@
|
||||
file exists, you can run the <filename>bitbake</filename>
|
||||
command again:
|
||||
<literallayout class='monospaced'>
|
||||
$ bitbake
|
||||
ERROR: Traceback (most recent call last):
|
||||
File "/home/scott-lenovo/bitbake/lib/bb/cookerdata.py", line 163, in wrapped
|
||||
return func(fn, *args)
|
||||
File "/home/scott-lenovo/bitbake/lib/bb/cookerdata.py", line 177, in _inherit
|
||||
bb.parse.BBHandler.inherit(bbclass, "configuration INHERITs", 0, data)
|
||||
File "/home/scott-lenovo/bitbake/lib/bb/parse/parse_py/BBHandler.py", line 92, in inherit
|
||||
include(fn, file, lineno, d, "inherit")
|
||||
File "/home/scott-lenovo/bitbake/lib/bb/parse/parse_py/ConfHandler.py", line 100, in include
|
||||
raise ParseError("Could not %(error_out)s file %(fn)s" % vars(), oldfn, lineno)
|
||||
ParseError: ParseError in configuration INHERITs: Could not inherit file classes/base.bbclass
|
||||
$ bitbake
|
||||
ERROR: Traceback (most recent call last):
|
||||
File "/home/scott-lenovo/bitbake/lib/bb/cookerdata.py", line 163, in wrapped
|
||||
return func(fn, *args)
|
||||
File "/home/scott-lenovo/bitbake/lib/bb/cookerdata.py", line 177, in _inherit
|
||||
bb.parse.BBHandler.inherit(bbclass, "configuration INHERITs", 0, data)
|
||||
File "/home/scott-lenovo/bitbake/lib/bb/parse/parse_py/BBHandler.py", line 92, in inherit
|
||||
include(fn, file, lineno, d, "inherit")
|
||||
File "/home/scott-lenovo/bitbake/lib/bb/parse/parse_py/ConfHandler.py", line 100, in include
|
||||
raise ParseError("Could not %(error_out)s file %(fn)s" % vars(), oldfn, lineno)
|
||||
ParseError: ParseError in configuration INHERITs: Could not inherit file classes/base.bbclass
|
||||
|
||||
ERROR: Unable to parse base: ParseError in configuration INHERITs: Could not inherit file classes/base.bbclass
|
||||
ERROR: Unable to parse base: ParseError in configuration INHERITs: Could not inherit file classes/base.bbclass
|
||||
</literallayout>
|
||||
In the sample output, BitBake could not find the
|
||||
<filename>classes/base.bbclass</filename> file.
|
||||
@@ -383,10 +365,10 @@
|
||||
code separate from the general metadata used by BitBake.
|
||||
Thus, this example creates and uses a layer called "mylayer".
|
||||
<note>
|
||||
You can find additional information on layers in the
|
||||
"<link linkend='layers'>Layers</link>" section.
|
||||
</note></para>
|
||||
|
||||
You can find additional information on layers at
|
||||
<ulink url='http://www.yoctoproject.org/docs/2.3/bitbake-user-manual/bitbake-user-manual.html#layers'></ulink>.
|
||||
</note>
|
||||
</para>
|
||||
<para>Minimally, you need a recipe file and a layer configuration
|
||||
file in your layer.
|
||||
The configuration file needs to be in the <filename>conf</filename>
|
||||
@@ -402,12 +384,12 @@
|
||||
Move to the <filename>conf</filename> directory and create a
|
||||
<filename>layer.conf</filename> file that has the following:
|
||||
<literallayout class='monospaced'>
|
||||
BBPATH .= ":${<link linkend='var-bb-LAYERDIR'>LAYERDIR</link>}"
|
||||
BBPATH .= ":${<link linkend='var-LAYERDIR'>LAYERDIR</link>}"
|
||||
|
||||
<link linkend='var-bb-BBFILES'>BBFILES</link> += "${LAYERDIR}/*.bb"
|
||||
<link linkend='var-BBFILES'>BBFILES</link> += "${LAYERDIR}/*.bb"
|
||||
|
||||
<link linkend='var-bb-BBFILE_COLLECTIONS'>BBFILE_COLLECTIONS</link> += "mylayer"
|
||||
<link linkend='var-bb-BBFILE_PATTERN'>BBFILE_PATTERN_mylayer</link> := "^${LAYERDIR_RE}/"
|
||||
<link linkend='var-BBFILE_COLLECTIONS'>BBFILE_COLLECTIONS</link> += "mylayer"
|
||||
<link linkend='var-BBFILE_PATTERN'>BBFILE_PATTERN_mylayer</link> := "^${LAYERDIR_RE}/"
|
||||
</literallayout>
|
||||
For information on these variables, click the links
|
||||
to go to the definitions in the glossary.</para>
|
||||
@@ -416,9 +398,9 @@
|
||||
a recipe file named <filename>printhello.bb</filename> that
|
||||
has the following:
|
||||
<literallayout class='monospaced'>
|
||||
<link linkend='var-bb-DESCRIPTION'>DESCRIPTION</link> = "Prints Hello World"
|
||||
<link linkend='var-bb-PN'>PN</link> = 'printhello'
|
||||
<link linkend='var-bb-PV'>PV</link> = '1'
|
||||
<link linkend='var-DESCRIPTION'>DESCRIPTION</link> = "Prints Hello World"
|
||||
<link linkend='var-PN'>PN</link> = 'printhello'
|
||||
<link linkend='var-PV'>PV</link> = '1'
|
||||
|
||||
python do_build() {
|
||||
bb.plain("********************");
|
||||
|
||||
@@ -342,14 +342,13 @@
|
||||
|
||||
<para>
|
||||
When you name an append file, you can use the
|
||||
"<filename>%</filename>" wildcard character to allow for matching
|
||||
recipe names.
|
||||
wildcard character (%) to allow for matching recipe names.
|
||||
For example, suppose you have an append file named
|
||||
as follows:
|
||||
<literallayout class='monospaced'>
|
||||
busybox_1.21.%.bbappend
|
||||
</literallayout>
|
||||
That append file would match any <filename>busybox_1.21.</filename><replaceable>x</replaceable><filename>.bb</filename>
|
||||
That append file would match any <filename>busybox_1.21.x.bb</filename>
|
||||
version of the recipe.
|
||||
So, the append file would match the following recipe names:
|
||||
<literallayout class='monospaced'>
|
||||
@@ -357,14 +356,6 @@
|
||||
busybox_1.21.2.bb
|
||||
busybox_1.21.3.bb
|
||||
</literallayout>
|
||||
<note><title>Important</title>
|
||||
The use of the "<filename>%</filename>" character
|
||||
is limited in that it only works directly in front of the
|
||||
<filename>.bbappend</filename> portion of the append file's
|
||||
name.
|
||||
You cannot use the wildcard character in any other
|
||||
location of the name.
|
||||
</note>
|
||||
If the <filename>busybox</filename> recipe was updated to
|
||||
<filename>busybox_1.3.0.bb</filename>, the append name would not
|
||||
match.
|
||||
@@ -497,6 +488,8 @@
|
||||
target that failed and anything depending on it cannot
|
||||
be built, as much as possible will be built before
|
||||
stopping.
|
||||
-a, --tryaltconfigs Continue with builds by trying to use alternative
|
||||
providers where possible.
|
||||
-f, --force Force the specified targets/task to run (invalidating
|
||||
any existing stamp file).
|
||||
-c CMD, --cmd=CMD Specify the task to execute. The exact options
|
||||
@@ -511,20 +504,19 @@
|
||||
Read the specified file before bitbake.conf.
|
||||
-R POSTFILE, --postread=POSTFILE
|
||||
Read the specified file after bitbake.conf.
|
||||
-v, --verbose Enable tracing of shell tasks (with 'set -x'). Also
|
||||
print bb.note(...) messages to stdout (in addition to
|
||||
writing them to ${T}/log.do_<task>).
|
||||
-D, --debug Increase the debug level. You can specify this more
|
||||
than once. -D sets the debug level to 1, where only
|
||||
bb.debug(1, ...) messages are printed to stdout; -DD
|
||||
sets the debug level to 2, where both bb.debug(1, ...)
|
||||
and bb.debug(2, ...) messages are printed; etc.
|
||||
Without -D, no debug messages are printed. Note that
|
||||
-D only affects output to stdout. All debug messages
|
||||
are written to ${T}/log.do_taskname, regardless of the
|
||||
debug level.
|
||||
-q, --quiet Output less log message data to the terminal. You can
|
||||
specify this more than once.
|
||||
-v, --verbose Enable tracing of shell tasks (with 'set -x').
|
||||
Also print bb.note(...) messages to stdout (in
|
||||
addition to writing them to ${T}/log.do_<task>).
|
||||
-D, --debug Increase the debug level. You can specify this
|
||||
more than once. -D sets the debug level to 1,
|
||||
where only bb.debug(1, ...) messages are printed
|
||||
to stdout; -DD sets the debug level to 2, where
|
||||
both bb.debug(1, ...) and bb.debug(2, ...)
|
||||
messages are printed; etc. Without -D, no debug
|
||||
messages are printed. Note that -D only affects
|
||||
output to stdout. All debug messages are written
|
||||
to ${T}/log.do_taskname, regardless of the debug
|
||||
level.
|
||||
-n, --dry-run Don't execute, just go through the motions.
|
||||
-S SIGNATURE_HANDLER, --dump-signatures=SIGNATURE_HANDLER
|
||||
Dump out the signature construction information, with
|
||||
@@ -547,38 +539,30 @@
|
||||
-l DEBUG_DOMAINS, --log-domains=DEBUG_DOMAINS
|
||||
Show debug logging for the specified logging domains
|
||||
-P, --profile Profile the command and save reports.
|
||||
-u UI, --ui=UI The user interface to use (knotty, ncurses or taskexp
|
||||
- default knotty).
|
||||
-u UI, --ui=UI The user interface to use (taskexp, knotty or
|
||||
ncurses - default knotty).
|
||||
-t SERVERTYPE, --servertype=SERVERTYPE
|
||||
Choose which server type to use (process or xmlrpc -
|
||||
default process).
|
||||
--token=XMLRPCTOKEN Specify the connection token to be used when
|
||||
connecting to a remote server.
|
||||
--revisions-changed Set the exit code depending on whether upstream
|
||||
floating revisions have changed or not.
|
||||
--server-only Run bitbake without a UI, only starting a server
|
||||
(cooker) process.
|
||||
-B BIND, --bind=BIND The name/address for the bitbake xmlrpc server to bind
|
||||
to.
|
||||
-T SERVER_TIMEOUT, --idle-timeout=SERVER_TIMEOUT
|
||||
Set timeout to unload bitbake server due to
|
||||
inactivity, set to -1 means no unload, default:
|
||||
Environment variable BB_SERVER_TIMEOUT.
|
||||
-B BIND, --bind=BIND The name/address for the bitbake server to bind to.
|
||||
--no-setscene Do not run any setscene tasks. sstate will be ignored
|
||||
and everything needed, built.
|
||||
--setscene-only Only run setscene tasks, don't run any real tasks.
|
||||
--remote-server=REMOTE_SERVER
|
||||
Connect to the specified server.
|
||||
-m, --kill-server Terminate any running bitbake server.
|
||||
-m, --kill-server Terminate the remote server.
|
||||
--observe-only Connect to a server as an observing-only client.
|
||||
--status-only Check the status of the remote bitbake server.
|
||||
-w WRITEEVENTLOG, --write-log=WRITEEVENTLOG
|
||||
Writes the event log of the build to a bitbake event
|
||||
json file. Use '' (empty string) to assign the name
|
||||
automatically.
|
||||
--runall=RUNALL Run the specified task for any recipe in the taskgraph
|
||||
of the specified target (even if it wouldn't otherwise
|
||||
have run).
|
||||
--runonly=RUNONLY Run only the specified task within the taskgraph of
|
||||
the specified targets (and any task dependencies those
|
||||
tasks may have).
|
||||
</literallayout>
|
||||
</para>
|
||||
</section>
|
||||
@@ -732,163 +716,6 @@
|
||||
</literallayout>
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id='executing-a-multiple-configuration-build'>
|
||||
<title>Executing a Multiple Configuration Build</title>
|
||||
|
||||
<para>
|
||||
BitBake is able to build multiple images or packages
|
||||
using a single command where the different targets
|
||||
require different configurations (multiple configuration
|
||||
builds).
|
||||
Each target, in this scenario, is referred to as a
|
||||
"multiconfig".
|
||||
</para>
|
||||
|
||||
<para>
|
||||
To accomplish a multiple configuration build, you must
|
||||
define each target's configuration separately using
|
||||
a parallel configuration file in the build directory.
|
||||
The location for these multiconfig configuration files
|
||||
is specific.
|
||||
They must reside in the current build directory in
|
||||
a sub-directory of <filename>conf</filename> named
|
||||
<filename>multiconfig</filename>.
|
||||
Following is an example for two separate targets:
|
||||
<imagedata fileref="figures/bb_multiconfig_files.png" align="center" width="4in" depth="3in" />
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The reason for this required file hierarchy
|
||||
is because the <filename>BBPATH</filename> variable
|
||||
is not constructed until the layers are parsed.
|
||||
Consequently, using the configuration file as a
|
||||
pre-configuration file is not possible unless it is
|
||||
located in the current working directory.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Minimally, each configuration file must define the
|
||||
machine and the temporary directory BitBake uses
|
||||
for the build.
|
||||
Suggested practice dictates that you do not
|
||||
overlap the temporary directories used during the
|
||||
builds.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Aside from separate configuration files for each
|
||||
target, you must also enable BitBake to perform multiple
|
||||
configuration builds.
|
||||
Enabling is accomplished by setting the
|
||||
<link linkend='var-bb-BBMULTICONFIG'><filename>BBMULTICONFIG</filename></link>
|
||||
variable in the <filename>local.conf</filename>
|
||||
configuration file.
|
||||
As an example, suppose you had configuration files
|
||||
for <filename>target1</filename> and
|
||||
<filename>target2</filename> defined in the build
|
||||
directory.
|
||||
The following statement in the
|
||||
<filename>local.conf</filename> file both enables
|
||||
BitBake to perform multiple configuration builds and
|
||||
specifies the two multiconfigs:
|
||||
<literallayout class='monospaced'>
|
||||
BBMULTICONFIG = "target1 target2"
|
||||
</literallayout>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Once the target configuration files are in place and
|
||||
BitBake has been enabled to perform multiple configuration
|
||||
builds, use the following command form to start the
|
||||
builds:
|
||||
<literallayout class='monospaced'>
|
||||
$ bitbake [multiconfig:<replaceable>multiconfigname</replaceable>:]<replaceable>target</replaceable> [[[multiconfig:<replaceable>multiconfigname</replaceable>:]<replaceable>target</replaceable>] ... ]
|
||||
</literallayout>
|
||||
Here is an example for two multiconfigs:
|
||||
<filename>target1</filename> and
|
||||
<filename>target2</filename>:
|
||||
<literallayout class='monospaced'>
|
||||
$ bitbake multiconfig:target1:<replaceable>target</replaceable> multiconfig:target2:<replaceable>target</replaceable>
|
||||
</literallayout>
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id='bb-enabling-multiple-configuration-build-dependencies'>
|
||||
<title>Enabling Multiple Configuration Build Dependencies</title>
|
||||
|
||||
<para>
|
||||
Sometimes dependencies can exist between targets
|
||||
(multiconfigs) in a multiple configuration build.
|
||||
For example, suppose that in order to build an image
|
||||
for a particular architecture, the root filesystem of
|
||||
another build for a different architecture needs to
|
||||
exist.
|
||||
In other words, the image for the first multiconfig depends
|
||||
on the root filesystem of the second multiconfig.
|
||||
This dependency is essentially that the task in the recipe
|
||||
that builds one multiconfig is dependent on the
|
||||
completion of the task in the recipe that builds
|
||||
another multiconfig.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
To enable dependencies in a multiple configuration
|
||||
build, you must declare the dependencies in the recipe
|
||||
using the following statement form:
|
||||
<literallayout class='monospaced'>
|
||||
<replaceable>task_or_package</replaceable>[mcdepends] = "multiconfig:<replaceable>from_multiconfig</replaceable>:<replaceable>to_multiconfig</replaceable>:<replaceable>recipe_name</replaceable>:<replaceable>task_on_which_to_depend</replaceable>"
|
||||
</literallayout>
|
||||
To better show how to use this statement, consider an
|
||||
example with two multiconfigs: <filename>target1</filename>
|
||||
and <filename>target2</filename>:
|
||||
<literallayout class='monospaced'>
|
||||
<replaceable>image_task</replaceable>[mcdepends] = "multiconfig:target1:target2:<replaceable>image2</replaceable>:<replaceable>rootfs_task</replaceable>"
|
||||
</literallayout>
|
||||
In this example, the
|
||||
<replaceable>from_multiconfig</replaceable> is "target1" and
|
||||
the <replaceable>to_multiconfig</replaceable> is "target2".
|
||||
The task on which the image whose recipe contains
|
||||
<replaceable>image_task</replaceable> depends on the
|
||||
completion of the <replaceable>rootfs_task</replaceable>
|
||||
used to build out <replaceable>image2</replaceable>, which
|
||||
is associated with the "target2" multiconfig.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Once you set up this dependency, you can build the
|
||||
"target1" multiconfig using a BitBake command as follows:
|
||||
<literallayout class='monospaced'>
|
||||
$ bitbake multiconfig:target1:<replaceable>image1</replaceable>
|
||||
</literallayout>
|
||||
This command executes all the tasks needed to create
|
||||
<replaceable>image1</replaceable> for the "target1"
|
||||
multiconfig.
|
||||
Because of the dependency, BitBake also executes through
|
||||
the <replaceable>rootfs_task</replaceable> for the "target2"
|
||||
multiconfig build.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Having a recipe depend on the root filesystem of another
|
||||
build might not seem that useful.
|
||||
Consider this change to the statement in the
|
||||
<replaceable>image1</replaceable> recipe:
|
||||
<literallayout class='monospaced'>
|
||||
<replaceable>image_task</replaceable>[mcdepends] = "multiconfig:target1:target2:<replaceable>image2</replaceable>:<replaceable>image_task</replaceable>"
|
||||
</literallayout>
|
||||
In this case, BitBake must create
|
||||
<replaceable>image2</replaceable> for the "target2"
|
||||
build since the "target1" build depends on it.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Because "target1" and "target2" are enabled for multiple
|
||||
configuration builds and have separate configuration
|
||||
files, BitBake places the artifacts for each build in the
|
||||
respective temporary build directories.
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
||||
</section>
|
||||
</chapter>
|
||||
|
||||
@@ -61,78 +61,6 @@
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id='modifying-existing-variables'>
|
||||
<title>Modifying Existing Variables</title>
|
||||
|
||||
<para>
|
||||
Sometimes you need to modify existing variables.
|
||||
Following are some cases where you might find you want to
|
||||
modify an existing variable:
|
||||
<itemizedlist>
|
||||
<listitem><para>
|
||||
Customize a recipe that uses the variable.
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
Change a variable's default value used in a
|
||||
<filename>*.bbclass</filename> file.
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
Change the variable in a <filename>*.bbappend</filename>
|
||||
file to override the variable in the original recipe.
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
Change the variable in a configuration file so that the
|
||||
value overrides an existing configuration.
|
||||
</para></listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Changing a variable value can sometimes depend on how the
|
||||
value was originally assigned and also on the desired
|
||||
intent of the change.
|
||||
In particular, when you append a value to a variable that
|
||||
has a default value, the resulting value might not be what
|
||||
you expect.
|
||||
In this case, the value you provide might replace the value
|
||||
rather than append to the default value.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
If after you have changed a variable's value and something
|
||||
unexplained occurs, you can use BitBake to check the actual
|
||||
value of the suspect variable.
|
||||
You can make these checks for both configuration and recipe
|
||||
level changes:
|
||||
<itemizedlist>
|
||||
<listitem><para>
|
||||
For configuration changes, use the following:
|
||||
<literallayout class='monospaced'>
|
||||
$ bitbake -e
|
||||
</literallayout>
|
||||
This command displays variable values after the
|
||||
configuration files (i.e. <filename>local.conf</filename>,
|
||||
<filename>bblayers.conf</filename>,
|
||||
<filename>bitbake.conf</filename> and so forth) have
|
||||
been parsed.
|
||||
<note>
|
||||
Variables that are exported to the environment are
|
||||
preceded by the string "export" in the command's
|
||||
output.
|
||||
</note>
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
For recipe changes, use the following:
|
||||
<literallayout class='monospaced'>
|
||||
$ bitbake <replaceable>recipe</replaceable> -e | grep VARIABLE="
|
||||
</literallayout>
|
||||
This command checks to see if the variable actually
|
||||
makes it into a specific recipe.
|
||||
</para></listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id='line-joining'>
|
||||
<title>Line Joining</title>
|
||||
|
||||
@@ -414,7 +342,7 @@
|
||||
|
||||
<para>
|
||||
When you use this syntax, BitBake expects one or more strings.
|
||||
Surrounding spaces and spacing are preserved.
|
||||
Surrounding spaces are removed as well.
|
||||
Here is an example:
|
||||
<literallayout class='monospaced'>
|
||||
FOO = "123 456 789 123456 123 456 123 456"
|
||||
@@ -424,9 +352,8 @@
|
||||
FOO2_remove = "abc def"
|
||||
</literallayout>
|
||||
The variable <filename>FOO</filename> becomes
|
||||
" 789 123456 "
|
||||
and <filename>FOO2</filename> becomes
|
||||
" ghi abcdef ".
|
||||
"789 123456" and <filename>FOO2</filename> becomes
|
||||
"ghi abcdef".
|
||||
</para>
|
||||
|
||||
<para>
|
||||
@@ -575,7 +502,7 @@
|
||||
</section>
|
||||
|
||||
<section id='unsetting-variables'>
|
||||
<title>Unsetting variables</title>
|
||||
<title>Unseting variables</title>
|
||||
|
||||
<para>
|
||||
It is possible to completely remove a variable or a variable flag
|
||||
@@ -667,7 +594,7 @@
|
||||
|
||||
<para>
|
||||
BitBake uses
|
||||
<link linkend='var-bb-OVERRIDES'><filename>OVERRIDES</filename></link>
|
||||
<link linkend='var-OVERRIDES'><filename>OVERRIDES</filename></link>
|
||||
to control what variables are overridden after BitBake
|
||||
parses recipes and configuration files.
|
||||
This section describes how you can use
|
||||
@@ -777,7 +704,7 @@
|
||||
|
||||
<para>Internally, this is implemented by prepending
|
||||
the task (e.g. "task-compile:") to the value of
|
||||
<link linkend='var-bb-OVERRIDES'><filename>OVERRIDES</filename></link>
|
||||
<link linkend='var-OVERRIDES'><filename>OVERRIDES</filename></link>
|
||||
for the local datastore of the <filename>do_compile</filename>
|
||||
task.</para>
|
||||
|
||||
@@ -940,7 +867,7 @@
|
||||
|
||||
<para>
|
||||
BitBake uses the
|
||||
<link linkend='var-bb-BBPATH'><filename>BBPATH</filename></link>
|
||||
<link linkend='var-BBPATH'><filename>BBPATH</filename></link>
|
||||
variable to locate needed include and class files.
|
||||
Additionally, BitBake searches the current directory for
|
||||
<filename>include</filename> and <filename>require</filename>
|
||||
@@ -1158,7 +1085,7 @@
|
||||
<para>
|
||||
When creating a configuration file (<filename>.conf</filename>),
|
||||
you can use the
|
||||
<link linkend='var-bb-INHERIT'><filename>INHERIT</filename></link>
|
||||
<link linkend='var-INHERIT'><filename>INHERIT</filename></link>
|
||||
configuration directive to inherit a class.
|
||||
BitBake only supports this directive when used within
|
||||
a configuration file.
|
||||
@@ -1442,7 +1369,7 @@
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
BitBake-style Python functions generate a separate
|
||||
<filename>${</filename><link linkend='var-bb-T'><filename>T</filename></link><filename>}/run.</filename><replaceable>function-name</replaceable><filename>.</filename><replaceable>pid</replaceable>
|
||||
<filename>${</filename><link linkend='var-T'><filename>T</filename></link><filename>}/run.</filename><replaceable>function-name</replaceable><filename>.</filename><replaceable>pid</replaceable>
|
||||
script that is executed to run the function, and also
|
||||
generate a log file in
|
||||
<filename>${T}/log.</filename><replaceable>function-name</replaceable><filename>.</filename><replaceable>pid</replaceable>
|
||||
@@ -1845,7 +1772,7 @@
|
||||
things exported or listed in its whitelist to ensure that the build
|
||||
environment is reproducible and consistent.
|
||||
You can prevent this "cleaning" by setting the
|
||||
<link linkend='var-bb-BB_PRESERVE_ENV'><filename>BB_PRESERVE_ENV</filename></link>
|
||||
<link linkend='var-BB_PRESERVE_ENV'><filename>BB_PRESERVE_ENV</filename></link>
|
||||
variable.
|
||||
</note>
|
||||
Consequently, if you do want something to get passed into the
|
||||
@@ -1855,9 +1782,9 @@
|
||||
Tell BitBake to load what you want from the environment
|
||||
into the datastore.
|
||||
You can do so through the
|
||||
<link linkend='var-bb-BB_ENV_WHITELIST'><filename>BB_ENV_WHITELIST</filename></link>
|
||||
<link linkend='var-BB_ENV_WHITELIST'><filename>BB_ENV_WHITELIST</filename></link>
|
||||
and
|
||||
<link linkend='var-bb-BB_ENV_EXTRAWHITE'><filename>BB_ENV_EXTRAWHITE</filename></link>
|
||||
<link linkend='var-BB_ENV_EXTRAWHITE'><filename>BB_ENV_EXTRAWHITE</filename></link>
|
||||
variables.
|
||||
For example, assume you want to prevent the build system from
|
||||
accessing your <filename>$HOME/.ccache</filename>
|
||||
@@ -1896,7 +1823,7 @@
|
||||
from the original execution environment.
|
||||
Bitbake saves a copy of the original environment into
|
||||
a special variable named
|
||||
<link linkend='var-bb-BB_ORIGENV'><filename>BB_ORIGENV</filename></link>.
|
||||
<link linkend='var-BB_ORIGENV'><filename>BB_ORIGENV</filename></link>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
@@ -1955,7 +1882,7 @@
|
||||
<listitem><para><emphasis><filename>[depends]</filename>:</emphasis>
|
||||
Controls inter-task dependencies.
|
||||
See the
|
||||
<link linkend='var-bb-DEPENDS'><filename>DEPENDS</filename></link>
|
||||
<link linkend='var-DEPENDS'><filename>DEPENDS</filename></link>
|
||||
variable and the
|
||||
"<link linkend='inter-task-dependencies'>Inter-Task Dependencies</link>"
|
||||
section for more information.
|
||||
@@ -1963,7 +1890,7 @@
|
||||
<listitem><para><emphasis><filename>[deptask]</filename>:</emphasis>
|
||||
Controls task build-time dependencies.
|
||||
See the
|
||||
<link linkend='var-bb-DEPENDS'><filename>DEPENDS</filename></link>
|
||||
<link linkend='var-DEPENDS'><filename>DEPENDS</filename></link>
|
||||
variable and the
|
||||
"<link linkend='build-dependencies'>Build Dependencies</link>"
|
||||
section for more information.
|
||||
@@ -2002,38 +1929,6 @@
|
||||
not careful.
|
||||
</note>
|
||||
</para></listitem>
|
||||
<listitem><para><emphasis><filename>[number_threads]</filename>:</emphasis>
|
||||
Limits tasks to a specific number of simultaneous threads
|
||||
during execution.
|
||||
This varflag is useful when your build host has a large number
|
||||
of cores but certain tasks need to be rate-limited due to various
|
||||
kinds of resource constraints (e.g. to avoid network throttling).
|
||||
<filename>number_threads</filename> works similarly to the
|
||||
<link linkend='var-bb-BB_NUMBER_THREADS'><filename>BB_NUMBER_THREADS</filename></link>
|
||||
variable but is task-specific.</para>
|
||||
|
||||
<para>Set the value globally.
|
||||
For example, the following makes sure the
|
||||
<filename>do_fetch</filename> task uses no more than two
|
||||
simultaneous execution threads:
|
||||
<literallayout class='monospaced'>
|
||||
do_fetch[number_threads] = "2"
|
||||
</literallayout>
|
||||
<note><title>Warnings</title>
|
||||
<itemizedlist>
|
||||
<listitem><para>
|
||||
Setting the varflag in individual recipes rather
|
||||
than globally can result in unpredictable behavior.
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
Setting the varflag to a value greater than the
|
||||
value used in the <filename>BB_NUMBER_THREADS</filename>
|
||||
variable causes <filename>number_threads</filename>
|
||||
to have no effect.
|
||||
</para></listitem>
|
||||
</itemizedlist>
|
||||
</note>
|
||||
</para></listitem>
|
||||
<listitem><para><emphasis><filename>[postfuncs]</filename>:</emphasis>
|
||||
List of functions to call after the completion of the task.
|
||||
</para></listitem>
|
||||
@@ -2043,9 +1938,9 @@
|
||||
<listitem><para><emphasis><filename>[rdepends]</filename>:</emphasis>
|
||||
Controls inter-task runtime dependencies.
|
||||
See the
|
||||
<link linkend='var-bb-RDEPENDS'><filename>RDEPENDS</filename></link>
|
||||
<link linkend='var-RDEPENDS'><filename>RDEPENDS</filename></link>
|
||||
variable, the
|
||||
<link linkend='var-bb-RRECOMMENDS'><filename>RRECOMMENDS</filename></link>
|
||||
<link linkend='var-RRECOMMENDS'><filename>RRECOMMENDS</filename></link>
|
||||
variable, and the
|
||||
"<link linkend='inter-task-dependencies'>Inter-Task Dependencies</link>"
|
||||
section for more information.
|
||||
@@ -2053,9 +1948,9 @@
|
||||
<listitem><para><emphasis><filename>[rdeptask]</filename>:</emphasis>
|
||||
Controls task runtime dependencies.
|
||||
See the
|
||||
<link linkend='var-bb-RDEPENDS'><filename>RDEPENDS</filename></link>
|
||||
<link linkend='var-RDEPENDS'><filename>RDEPENDS</filename></link>
|
||||
variable, the
|
||||
<link linkend='var-bb-RRECOMMENDS'><filename>RRECOMMENDS</filename></link>
|
||||
<link linkend='var-RRECOMMENDS'><filename>RRECOMMENDS</filename></link>
|
||||
variable, and the
|
||||
"<link linkend='runtime-dependencies'>Runtime Dependencies</link>"
|
||||
section for more information.
|
||||
@@ -2068,9 +1963,9 @@
|
||||
<listitem><para><emphasis><filename>[recrdeptask]</filename>:</emphasis>
|
||||
Controls task recursive runtime dependencies.
|
||||
See the
|
||||
<link linkend='var-bb-RDEPENDS'><filename>RDEPENDS</filename></link>
|
||||
<link linkend='var-RDEPENDS'><filename>RDEPENDS</filename></link>
|
||||
variable, the
|
||||
<link linkend='var-bb-RRECOMMENDS'><filename>RRECOMMENDS</filename></link>
|
||||
<link linkend='var-RRECOMMENDS'><filename>RRECOMMENDS</filename></link>
|
||||
variable, and the
|
||||
"<link linkend='recursive-dependencies'>Recursive Dependencies</link>"
|
||||
section for more information.
|
||||
@@ -2199,7 +2094,7 @@
|
||||
Any given datastore only has one such event executed
|
||||
against it, however.
|
||||
If
|
||||
<link linkende='var-bb-BB_INVALIDCONF'><filename>BB_INVALIDCONF</filename></link>
|
||||
<link linkende='var-BB_INVALIDCONF'><filename>BB_INVALIDCONF</filename></link>
|
||||
is set in the datastore by the event handler, the
|
||||
configuration is reparsed and a new event triggered,
|
||||
allowing the metadata to update configuration.
|
||||
@@ -2237,8 +2132,6 @@
|
||||
<listitem><para>
|
||||
<filename>bb.event.BuildStarted()</filename>:
|
||||
Fired when a new build starts.
|
||||
BitBake fires multiple "BuildStarted" events (one per configuration)
|
||||
when multiple configuration (multiconfig) is enabled.
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
<filename>bb.build.TaskStarted()</filename>:
|
||||
@@ -2328,17 +2221,17 @@
|
||||
from a single recipe file multiple incarnations of that
|
||||
recipe file where all incarnations are buildable.
|
||||
These features are enabled through the
|
||||
<link linkend='var-bb-BBCLASSEXTEND'><filename>BBCLASSEXTEND</filename></link>
|
||||
<link linkend='var-BBCLASSEXTEND'><filename>BBCLASSEXTEND</filename></link>
|
||||
and
|
||||
<link linkend='var-bb-BBVERSIONS'><filename>BBVERSIONS</filename></link>
|
||||
<link linkend='var-BBVERSIONS'><filename>BBVERSIONS</filename></link>
|
||||
variables.
|
||||
<note>
|
||||
The mechanism for this class extension is extremely
|
||||
specific to the implementation.
|
||||
Usually, the recipe's
|
||||
<link linkend='var-bb-PROVIDES'><filename>PROVIDES</filename></link>,
|
||||
<link linkend='var-bb-PN'><filename>PN</filename></link>, and
|
||||
<link linkend='var-bb-DEPENDS'><filename>DEPENDS</filename></link>
|
||||
<link linkend='var-PROVIDES'><filename>PROVIDES</filename></link>,
|
||||
<link linkend='var-PN'><filename>PN</filename></link>, and
|
||||
<link linkend='var-DEPENDS'><filename>DEPENDS</filename></link>
|
||||
variables would need to be modified by the extension class.
|
||||
For specific examples, see the OE-Core
|
||||
<filename>native</filename>, <filename>nativesdk</filename>,
|
||||
@@ -2359,7 +2252,7 @@
|
||||
project from a single recipe file.
|
||||
You can also specify conditional metadata
|
||||
(using the
|
||||
<link linkend='var-bb-OVERRIDES'><filename>OVERRIDES</filename></link>
|
||||
<link linkend='var-OVERRIDES'><filename>OVERRIDES</filename></link>
|
||||
mechanism) for a single version, or an optionally named range of versions.
|
||||
Here is an example:
|
||||
<literallayout class='monospaced'>
|
||||
@@ -2378,7 +2271,7 @@
|
||||
into overrides, but it is also made available for the metadata to use
|
||||
in the variable that defines the base recipe versions for use in
|
||||
<filename>file://</filename> search paths
|
||||
(<link linkend='var-bb-FILESPATH'><filename>FILESPATH</filename></link>).
|
||||
(<link linkend='var-FILESPATH'><filename>FILESPATH</filename></link>).
|
||||
</para></listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
@@ -2480,7 +2373,7 @@
|
||||
|
||||
<para>
|
||||
BitBake uses the
|
||||
<link linkend='var-bb-DEPENDS'><filename>DEPENDS</filename></link>
|
||||
<link linkend='var-DEPENDS'><filename>DEPENDS</filename></link>
|
||||
variable to manage build time dependencies.
|
||||
The <filename>[deptask]</filename> varflag for tasks
|
||||
signifies the task of each
|
||||
@@ -2501,9 +2394,9 @@
|
||||
|
||||
<para>
|
||||
BitBake uses the
|
||||
<link linkend='var-bb-PACKAGES'><filename>PACKAGES</filename></link>,
|
||||
<link linkend='var-bb-RDEPENDS'><filename>RDEPENDS</filename></link>, and
|
||||
<link linkend='var-bb-RRECOMMENDS'><filename>RRECOMMENDS</filename></link>
|
||||
<link linkend='var-PACKAGES'><filename>PACKAGES</filename></link>,
|
||||
<link linkend='var-RDEPENDS'><filename>RDEPENDS</filename></link>, and
|
||||
<link linkend='var-RRECOMMENDS'><filename>RRECOMMENDS</filename></link>
|
||||
variables to manage runtime dependencies.
|
||||
</para>
|
||||
|
||||
@@ -2757,97 +2650,48 @@
|
||||
</para>
|
||||
|
||||
<para>
|
||||
These checksums are stored in
|
||||
<link linkend='var-bb-STAMP'><filename>STAMP</filename></link>.
|
||||
You can examine the checksums using the following BitBake command:
|
||||
<literallayout class='monospaced'>
|
||||
$ bitbake-dumpsigs
|
||||
</literallayout>
|
||||
This command returns the signature data in a readable format
|
||||
that allows you to examine the inputs used when the
|
||||
OpenEmbedded build system generates signatures.
|
||||
For example, using <filename>bitbake-dumpsigs</filename>
|
||||
allows you to examine the <filename>do_compile</filename>
|
||||
task's “sigdata” for a C application (e.g.
|
||||
<filename>bash</filename>).
|
||||
Running the command also reveals that the “CC” variable is part of
|
||||
the inputs that are hashed.
|
||||
Any changes to this variable would invalidate the stamp and
|
||||
cause the <filename>do_compile</filename> task to run.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The following list describes related variables:
|
||||
This list is a place holder of content existed from previous work
|
||||
on the manual.
|
||||
Some or all of it probably needs integrated into the subsections
|
||||
that make up this section.
|
||||
For now, I have just provided a short glossary-like description
|
||||
for each variable.
|
||||
Ultimately, this list goes away.
|
||||
<itemizedlist>
|
||||
<listitem><para>
|
||||
<link linkend='var-bb-BB_HASHCHECK_FUNCTION'><filename>BB_HASHCHECK_FUNCTION</filename></link>:
|
||||
<listitem><para><filename>STAMP</filename>:
|
||||
The base path to create stamp files.</para></listitem>
|
||||
<listitem><para><filename>STAMPCLEAN</filename>
|
||||
Again, the base path to create stamp files but can use wildcards
|
||||
for matching a range of files for clean operations.
|
||||
</para></listitem>
|
||||
<listitem><para><filename>BB_STAMP_WHITELIST</filename>
|
||||
Lists stamp files that are looked at when the stamp policy
|
||||
is "whitelist".
|
||||
</para></listitem>
|
||||
<listitem><para><filename>BB_STAMP_POLICY</filename>
|
||||
Defines the mode for comparing timestamps of stamp files.
|
||||
</para></listitem>
|
||||
<listitem><para><filename>BB_HASHCHECK_FUNCTION</filename>
|
||||
Specifies the name of the function to call during
|
||||
the "setscene" part of the task's execution in order
|
||||
to validate the list of task hashes.
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
<link linkend='var-bb-BB_SETSCENE_DEPVALID'><filename>BB_SETSCENE_DEPVALID</filename></link>:
|
||||
Specifies a function BitBake calls that determines
|
||||
whether BitBake requires a setscene dependency to
|
||||
be met.
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
<link linkend='var-bb-BB_SETSCENE_VERIFY_FUNCTION2'><filename>BB_SETSCENE_VERIFY_FUNCTION2</filename></link>:
|
||||
<listitem><para><filename>BB_SETSCENE_VERIFY_FUNCTION2</filename>
|
||||
Specifies a function to call that verifies the list of
|
||||
planned task execution before the main task execution
|
||||
happens.
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
<link linkend='var-bb-BB_STAMP_POLICY'><filename>BB_STAMP_POLICY</filename></link>:
|
||||
Defines the mode for comparing timestamps of stamp files.
|
||||
<listitem><para><filename>BB_SETSCENE_DEPVALID</filename>
|
||||
Specifies a function BitBake calls that determines
|
||||
whether BitBake requires a setscene dependency to
|
||||
be met.
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
<link linkend='var-bb-BB_STAMP_WHITELIST'><filename>BB_STAMP_WHITELIST</filename></link>:
|
||||
Lists stamp files that are looked at when the stamp policy
|
||||
is "whitelist".
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
<link linkend='var-bb-BB_TASKHASH'><filename>BB_TASKHASH</filename></link>:
|
||||
<listitem><para><filename>BB_TASKHASH</filename>
|
||||
Within an executing task, this variable holds the hash
|
||||
of the task as returned by the currently enabled
|
||||
signature generator.
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
<link linkend='var-bb-STAMP'><filename>STAMP</filename></link>:
|
||||
The base path to create stamp files.
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
<link linkend='var-bb-STAMPCLEAN'><filename>STAMPCLEAN</filename></link>:
|
||||
Again, the base path to create stamp files but can use wildcards
|
||||
for matching a range of files for clean operations.
|
||||
</para></listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id='wildcard-support-in-variables'>
|
||||
<title>Wildcard Support in Variables</title>
|
||||
|
||||
<para>
|
||||
Support for wildcard use in variables varies depending on the
|
||||
context in which it is used.
|
||||
For example, some variables and file names allow limited use of
|
||||
wildcards through the "<filename>%</filename>" and
|
||||
"<filename>*</filename>" characters.
|
||||
Other variables or names support Python's
|
||||
<ulink url='https://docs.python.org/3/library/glob.html'><filename>glob</filename></ulink>
|
||||
syntax,
|
||||
<ulink url='https://docs.python.org/3/library/fnmatch.html#module-fnmatch'><filename>fnmatch</filename></ulink>
|
||||
syntax, or
|
||||
<ulink url='https://docs.python.org/3/library/re.html#re'><filename>Regular Expression (re)</filename></ulink>
|
||||
syntax.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
For variables that have wildcard suport, the
|
||||
documentation describes which form of wildcard, its
|
||||
use, and its limitations.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
</chapter>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -56,7 +56,7 @@
|
||||
-->
|
||||
|
||||
<copyright>
|
||||
<year>2004-2018</year>
|
||||
<year>2004-2016</year>
|
||||
<holder>Richard Purdie</holder>
|
||||
<holder>Chris Larson</holder>
|
||||
<holder>and Phil Blundell</holder>
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 20 KiB |
@@ -17,6 +17,13 @@
|
||||
<!ENTITY OE_DOCS_URL "http://docs.openembedded.org">
|
||||
<!ENTITY OH_HOME_URL "http://o-hand.com">
|
||||
<!ENTITY BITBAKE_HOME_URL "http://developer.berlios.de/projects/bitbake/">
|
||||
<!ENTITY ECLIPSE_MAIN_URL "http://www.eclipse.org/downloads">
|
||||
<!ENTITY ECLIPSE_DL_URL "http://download.eclipse.org">
|
||||
<!ENTITY ECLIPSE_DL_PLUGIN_URL "&YOCTO_DL_URL;/releases/eclipse-plugin/&DISTRO;">
|
||||
<!ENTITY ECLIPSE_UPDATES_URL "&ECLIPSE_DL_URL;/tm/updates/3.3">
|
||||
<!ENTITY ECLIPSE_INDIGO_URL "&ECLIPSE_DL_URL;/releases/indigo">
|
||||
<!ENTITY ECLIPSE_JUNO_URL "&ECLIPSE_DL_URL;/releases/juno">
|
||||
<!ENTITY ECLIPSE_INDIGO_CDT_URL "&ECLIPSE_DL_URL;tools/cdt/releases/indigo">
|
||||
<!ENTITY YOCTO_DOCS_URL "&YOCTO_HOME_URL;/docs">
|
||||
<!ENTITY YOCTO_SOURCES_URL "&YOCTO_HOME_URL;/sources/">
|
||||
<!ENTITY YOCTO_AB_PORT_URL "&YOCTO_AB_URL;:8010">
|
||||
@@ -24,6 +31,7 @@
|
||||
<!ENTITY YOCTO_POKY_URL "&YOCTO_DL_URL;/releases/poky/">
|
||||
<!ENTITY YOCTO_RELEASE_DL_URL "&YOCTO_DL_URL;/releases/yocto/yocto-&DISTRO;">
|
||||
<!ENTITY YOCTO_TOOLCHAIN_DL_URL "&YOCTO_RELEASE_DL_URL;/toolchain/">
|
||||
<!ENTITY YOCTO_ECLIPSE_DL_URL "&YOCTO_RELEASE_DL_URL;/eclipse-plugin/indigo;">
|
||||
<!ENTITY YOCTO_ADTINSTALLER_DL_URL "&YOCTO_RELEASE_DL_URL;/adt_installer">
|
||||
<!ENTITY YOCTO_POKY_DL_URL "&YOCTO_RELEASE_DL_URL;/&YOCTO_POKY;.tar.bz2">
|
||||
<!ENTITY YOCTO_MACHINES_DL_URL "&YOCTO_RELEASE_DL_URL;/machines">
|
||||
|
||||
@@ -5,6 +5,19 @@
|
||||
#
|
||||
# Copyright (C) 2006 Tim Ansell
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
#Please Note:
|
||||
# Be careful when using mutable types (ie Dict and Lists) - operations involving these are SLOW.
|
||||
# Assign a file to __warn__ to get warnings about slow operations.
|
||||
@@ -137,7 +150,7 @@ class COWDictMeta(COWMeta):
|
||||
yield value
|
||||
if type == "items":
|
||||
yield (key, value)
|
||||
return
|
||||
raise StopIteration()
|
||||
|
||||
def iterkeys(cls):
|
||||
return cls.iter("keys")
|
||||
|
||||
@@ -8,10 +8,20 @@
|
||||
#
|
||||
# Based on Gentoo's portage.py.
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# 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.
|
||||
|
||||
__version__ = "1.42.0"
|
||||
__version__ = "1.36.0"
|
||||
|
||||
import sys
|
||||
if sys.version_info < (3, 4, 0):
|
||||
@@ -53,10 +63,6 @@ class BBLogger(Logger):
|
||||
def verbose(self, msg, *args, **kwargs):
|
||||
return self.log(logging.INFO - 1, msg, *args, **kwargs)
|
||||
|
||||
def verbnote(self, msg, *args, **kwargs):
|
||||
return self.log(logging.INFO + 2, msg, *args, **kwargs)
|
||||
|
||||
|
||||
logging.raiseExceptions = False
|
||||
logging.setLoggerClass(BBLogger)
|
||||
|
||||
@@ -87,18 +93,6 @@ def debug(lvl, *args):
|
||||
def note(*args):
|
||||
mainlogger.info(''.join(args))
|
||||
|
||||
#
|
||||
# A higher prioity note which will show on the console but isn't a warning
|
||||
#
|
||||
# Something is happening the user should be aware of but they probably did
|
||||
# something to make it happen
|
||||
#
|
||||
def verbnote(*args):
|
||||
mainlogger.verbnote(''.join(args))
|
||||
|
||||
#
|
||||
# Warnings - things the user likely needs to pay attention to and fix
|
||||
#
|
||||
def warn(*args):
|
||||
mainlogger.warning(''.join(args))
|
||||
|
||||
|
||||
@@ -10,7 +10,18 @@
|
||||
#
|
||||
# Based on Gentoo's portage.py.
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# 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
|
||||
|
||||
@@ -30,6 +41,8 @@ from bb import data, event, utils
|
||||
bblogger = logging.getLogger('BitBake')
|
||||
logger = logging.getLogger('BitBake.Build')
|
||||
|
||||
NULL = open(os.devnull, 'r+')
|
||||
|
||||
__mtime_cache = {}
|
||||
|
||||
def cached_mtime_noerror(f):
|
||||
@@ -293,10 +306,9 @@ def exec_func_python(func, d, runfile, cwd=None, pythonexception=False):
|
||||
utils.better_exec(comp, {"d": d}, code, "exec_python_func() autogenerated", pythonexception=pythonexception)
|
||||
except (bb.parse.SkipRecipe, bb.build.FuncFailed):
|
||||
raise
|
||||
except Exception as e:
|
||||
except:
|
||||
if pythonexception:
|
||||
raise
|
||||
logger.error(str(e))
|
||||
raise FuncFailed(func, None)
|
||||
finally:
|
||||
bb.debug(2, "Python function %s finished" % func)
|
||||
@@ -521,6 +533,7 @@ def _exec_task(fn, task, d, quieterr):
|
||||
self.triggered = True
|
||||
|
||||
# Handle logfiles
|
||||
si = open('/dev/null', 'r')
|
||||
try:
|
||||
bb.utils.mkdirhier(os.path.dirname(logfn))
|
||||
logfile = open(logfn, 'w')
|
||||
@@ -534,8 +547,7 @@ def _exec_task(fn, task, d, quieterr):
|
||||
ose = [os.dup(sys.stderr.fileno()), sys.stderr.fileno()]
|
||||
|
||||
# Replace those fds with our own
|
||||
with open('/dev/null', 'r') as si:
|
||||
os.dup2(si.fileno(), osi[1])
|
||||
os.dup2(si.fileno(), osi[1])
|
||||
os.dup2(logfile.fileno(), oso[1])
|
||||
os.dup2(logfile.fileno(), ose[1])
|
||||
|
||||
@@ -596,6 +608,7 @@ def _exec_task(fn, task, d, quieterr):
|
||||
os.close(osi[0])
|
||||
os.close(oso[0])
|
||||
os.close(ose[0])
|
||||
si.close()
|
||||
|
||||
logfile.close()
|
||||
if os.path.exists(logfn) and os.path.getsize(logfn) == 0:
|
||||
@@ -790,7 +803,6 @@ def add_tasks(tasklist, d):
|
||||
if name in flags:
|
||||
deptask = d.expand(flags[name])
|
||||
task_deps[name][task] = deptask
|
||||
getTask('mcdepends')
|
||||
getTask('depends')
|
||||
getTask('rdepends')
|
||||
getTask('deptask')
|
||||
@@ -860,12 +872,6 @@ def preceedtask(task, with_recrdeptasks, d):
|
||||
that this may lead to the task itself being listed.
|
||||
"""
|
||||
preceed = set()
|
||||
|
||||
# Ignore tasks which don't exist
|
||||
tasks = d.getVar('__BBTASKS', False)
|
||||
if task not in tasks:
|
||||
return preceed
|
||||
|
||||
preceed.update(d.getVarFlag(task, 'deps') or [])
|
||||
if with_recrdeptasks:
|
||||
recrdeptask = d.getVarFlag(task, 'recrdeptask')
|
||||
|
||||
@@ -15,8 +15,18 @@
|
||||
# Copyright (C) 2005 Holger Hans Peter Freyther
|
||||
# Copyright (C) 2005 ROAD GmbH
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License version 2 as
|
||||
# published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
import os
|
||||
import sys
|
||||
@@ -27,7 +37,7 @@ import bb.utils
|
||||
|
||||
logger = logging.getLogger("BitBake.Cache")
|
||||
|
||||
__cache_version__ = "152"
|
||||
__cache_version__ = "151"
|
||||
|
||||
def getCacheFile(path, filename, data_hash):
|
||||
return os.path.join(path, filename + "." + data_hash)
|
||||
@@ -87,7 +97,7 @@ class CoreRecipeInfo(RecipeInfoCommon):
|
||||
|
||||
self.skipreason = self.getvar('__SKIPPED', metadata)
|
||||
if self.skipreason:
|
||||
self.pn = self.getvar('PN', metadata) or bb.parse.vars_from_file(filename,metadata)[0]
|
||||
self.pn = self.getvar('PN', metadata) or bb.parse.BBHandler.vars_from_file(filename,metadata)[0]
|
||||
self.skipped = True
|
||||
self.provides = self.depvar('PROVIDES', metadata)
|
||||
self.rprovides = self.depvar('RPROVIDES', metadata)
|
||||
@@ -385,7 +395,7 @@ class Cache(NoCache):
|
||||
self.has_cache = True
|
||||
self.cachefile = getCacheFile(self.cachedir, "bb_cache.dat", self.data_hash)
|
||||
|
||||
logger.debug(1, "Cache dir: %s", self.cachedir)
|
||||
logger.debug(1, "Using cache in '%s'", self.cachedir)
|
||||
bb.utils.mkdirhier(self.cachedir)
|
||||
|
||||
cache_ok = True
|
||||
@@ -398,8 +408,6 @@ class Cache(NoCache):
|
||||
self.load_cachefile()
|
||||
elif os.path.isfile(self.cachefile):
|
||||
logger.info("Out of date cache found, rebuilding...")
|
||||
else:
|
||||
logger.debug(1, "Cache file %s not found, building..." % self.cachefile)
|
||||
|
||||
def load_cachefile(self):
|
||||
cachesize = 0
|
||||
@@ -416,7 +424,6 @@ class Cache(NoCache):
|
||||
|
||||
for cache_class in self.caches_array:
|
||||
cachefile = getCacheFile(self.cachedir, cache_class.cachefile, self.data_hash)
|
||||
logger.debug(1, 'Loading cache file: %s' % cachefile)
|
||||
with open(cachefile, "rb") as cachefile:
|
||||
pickled = pickle.Unpickler(cachefile)
|
||||
# Check cache version information
|
||||
|
||||
@@ -12,8 +12,18 @@
|
||||
|
||||
# Copyright (C) 2011, Intel Corporation. All rights reserved.
|
||||
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# 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.
|
||||
|
||||
from bb.cache import RecipeInfoCommon
|
||||
|
||||
|
||||
@@ -2,8 +2,18 @@
|
||||
#
|
||||
# Copyright (C) 2012 Intel Corporation
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# 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 operator
|
||||
@@ -87,8 +97,6 @@ class FileChecksumCache(MultiProcessCache):
|
||||
|
||||
def checksum_dir(pth):
|
||||
# Handle directories recursively
|
||||
if pth == "/":
|
||||
bb.fatal("Refusing to checksum /")
|
||||
dirchecksums = []
|
||||
for root, dirs, files in os.walk(pth):
|
||||
for name in files:
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
#
|
||||
|
||||
"""
|
||||
BitBake code parser
|
||||
|
||||
@@ -37,7 +33,7 @@ from bb.cache import MultiProcessCache
|
||||
logger = logging.getLogger('BitBake.CodeParser')
|
||||
|
||||
def bbhash(s):
|
||||
return hashlib.sha256(s.encode("utf-8")).hexdigest()
|
||||
return hashlib.md5(s.encode("utf-8")).hexdigest()
|
||||
|
||||
def check_indent(codestr):
|
||||
"""If the code is indented, add a top level piece of code to 'remove' the indentation"""
|
||||
@@ -144,7 +140,7 @@ class CodeParserCache(MultiProcessCache):
|
||||
# so that an existing cache gets invalidated. Additionally you'll need
|
||||
# to increment __cache_version__ in cache.py in order to ensure that old
|
||||
# recipe caches don't trigger "Taskhash mismatch" errors.
|
||||
CACHE_VERSION = 11
|
||||
CACHE_VERSION = 9
|
||||
|
||||
def __init__(self):
|
||||
MultiProcessCache.__init__(self)
|
||||
@@ -218,7 +214,7 @@ class BufferedLogger(Logger):
|
||||
self.buffer = []
|
||||
|
||||
class PythonParser():
|
||||
getvars = (".getVar", ".appendVar", ".prependVar", "oe.utils.conditional")
|
||||
getvars = (".getVar", ".appendVar", ".prependVar")
|
||||
getvarflags = (".getVarFlag", ".appendVarFlag", ".prependVarFlag")
|
||||
containsfuncs = ("bb.utils.contains", "base_contains")
|
||||
containsanyfuncs = ("bb.utils.contains_any", "bb.utils.filter")
|
||||
@@ -372,9 +368,8 @@ class ShellParser():
|
||||
def _parse_shell(self, value):
|
||||
try:
|
||||
tokens, _ = pyshyacc.parse(value, eof=True, debug=False)
|
||||
except Exception:
|
||||
bb.error('Error during parse shell code, the last 5 lines are:\n%s' % '\n'.join(value.split('\n')[-5:]))
|
||||
raise
|
||||
except pyshlex.NeedMore:
|
||||
raise sherrors.ShellSyntaxError("Unexpected EOF")
|
||||
|
||||
self.process_tokens(tokens)
|
||||
|
||||
|
||||
@@ -6,8 +6,18 @@ Provide an interface to interact with the bitbake server through 'commands'
|
||||
|
||||
# Copyright (C) 2006-2007 Richard Purdie
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# 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.
|
||||
|
||||
"""
|
||||
The bitbake server takes 'commands' from its UI/commandline.
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
#
|
||||
|
||||
"""Code pulled from future python versions, here for compatibility"""
|
||||
|
||||
from collections import MutableMapping, KeysView, ValuesView, ItemsView, OrderedDict
|
||||
|
||||
@@ -9,8 +9,19 @@
|
||||
# Copyright (C) 2005 ROAD GmbH
|
||||
# Copyright (C) 2006 - 2007 Richard Purdie
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# 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 sys, os, glob, os.path, re, time
|
||||
import atexit
|
||||
@@ -164,31 +175,18 @@ class BBCooker:
|
||||
|
||||
self.configuration = configuration
|
||||
|
||||
bb.debug(1, "BBCooker starting %s" % time.time())
|
||||
sys.stdout.flush()
|
||||
|
||||
self.configwatcher = pyinotify.WatchManager()
|
||||
bb.debug(1, "BBCooker pyinotify1 %s" % time.time())
|
||||
sys.stdout.flush()
|
||||
|
||||
self.configwatcher.bbseen = []
|
||||
self.configwatcher.bbwatchedfiles = []
|
||||
self.confignotifier = pyinotify.Notifier(self.configwatcher, self.config_notifications)
|
||||
bb.debug(1, "BBCooker pyinotify2 %s" % time.time())
|
||||
sys.stdout.flush()
|
||||
self.watchmask = pyinotify.IN_CLOSE_WRITE | pyinotify.IN_CREATE | pyinotify.IN_DELETE | \
|
||||
pyinotify.IN_DELETE_SELF | pyinotify.IN_MODIFY | pyinotify.IN_MOVE_SELF | \
|
||||
pyinotify.IN_MOVED_FROM | pyinotify.IN_MOVED_TO
|
||||
self.watcher = pyinotify.WatchManager()
|
||||
bb.debug(1, "BBCooker pyinotify3 %s" % time.time())
|
||||
sys.stdout.flush()
|
||||
self.watcher.bbseen = []
|
||||
self.watcher.bbwatchedfiles = []
|
||||
self.notifier = pyinotify.Notifier(self.watcher, self.notifications)
|
||||
|
||||
bb.debug(1, "BBCooker pyinotify complete %s" % time.time())
|
||||
sys.stdout.flush()
|
||||
|
||||
# If being called by something like tinfoil, we need to clean cached data
|
||||
# which may now be invalid
|
||||
bb.parse.clear_cache()
|
||||
@@ -198,9 +196,6 @@ class BBCooker:
|
||||
|
||||
self.initConfigurationData()
|
||||
|
||||
bb.debug(1, "BBCooker parsed base configuration %s" % time.time())
|
||||
sys.stdout.flush()
|
||||
|
||||
# we log all events to a file if so directed
|
||||
if self.configuration.writeeventlog:
|
||||
# register the log file writer as UI Handler
|
||||
@@ -238,9 +233,6 @@ class BBCooker:
|
||||
# Let SIGHUP exit as SIGTERM
|
||||
signal.signal(signal.SIGHUP, self.sigterm_exception)
|
||||
|
||||
bb.debug(1, "BBCooker startup complete %s" % time.time())
|
||||
sys.stdout.flush()
|
||||
|
||||
def process_inotify_updates(self):
|
||||
for n in [self.confignotifier, self.notifier]:
|
||||
if n.check_events(timeout=0):
|
||||
@@ -380,9 +372,8 @@ class BBCooker:
|
||||
if CookerFeatures.BASEDATASTORE_TRACKING in self.featureset:
|
||||
self.disableDataTracking()
|
||||
|
||||
for mc in self.databuilder.mcdata.values():
|
||||
mc.renameVar("__depends", "__base_depends")
|
||||
self.add_filewatch(mc.getVar("__base_depends", False), self.configwatcher)
|
||||
self.data.renameVar("__depends", "__base_depends")
|
||||
self.add_filewatch(self.data.getVar("__base_depends", False), self.configwatcher)
|
||||
|
||||
self.baseconfig_valid = True
|
||||
self.parsecache_valid = False
|
||||
@@ -525,8 +516,6 @@ class BBCooker:
|
||||
fn = runlist[0][3]
|
||||
else:
|
||||
envdata = self.data
|
||||
data.expandKeys(envdata)
|
||||
parse.ast.runAnonFuncs(envdata)
|
||||
|
||||
if fn:
|
||||
try:
|
||||
@@ -547,6 +536,7 @@ class BBCooker:
|
||||
logger.plain(env.getvalue())
|
||||
|
||||
# emit the metadata which isnt valid shell
|
||||
data.expandKeys(envdata)
|
||||
for e in sorted(envdata.keys()):
|
||||
if envdata.getVarFlag(e, 'func', False) and envdata.getVarFlag(e, 'python', False):
|
||||
logger.plain("\npython %s () {\n%s}\n", e, envdata.getVar(e, False))
|
||||
@@ -629,37 +619,6 @@ class BBCooker:
|
||||
runlist.append([mc, k, ktask, fn])
|
||||
bb.event.fire(bb.event.TreeDataPreparationProgress(current, len(fulltargetlist)), self.data)
|
||||
|
||||
havemc = False
|
||||
for mc in self.multiconfigs:
|
||||
if taskdata[mc].get_mcdepends():
|
||||
havemc = True
|
||||
|
||||
# No need to do check providers if there are no mcdeps or not an mc build
|
||||
if havemc or len(self.multiconfigs) > 1:
|
||||
seen = set()
|
||||
new = True
|
||||
# Make sure we can provide the multiconfig dependency
|
||||
while new:
|
||||
mcdeps = set()
|
||||
# Add unresolved first, so we can get multiconfig indirect dependencies on time
|
||||
for mc in self.multiconfigs:
|
||||
taskdata[mc].add_unresolved(localdata[mc], self.recipecaches[mc])
|
||||
mcdeps |= set(taskdata[mc].get_mcdepends())
|
||||
new = False
|
||||
for mc in self.multiconfigs:
|
||||
for k in mcdeps:
|
||||
if k in seen:
|
||||
continue
|
||||
l = k.split(':')
|
||||
depmc = l[2]
|
||||
if depmc not in self.multiconfigs:
|
||||
bb.fatal("Multiconfig dependency %s depends on nonexistent mc configuration %s" % (k,depmc))
|
||||
else:
|
||||
logger.debug(1, "Adding providers for multiconfig dependency %s" % l[3])
|
||||
taskdata[depmc].add_provider(localdata[depmc], self.recipecaches[depmc], l[3])
|
||||
seen.add(k)
|
||||
new = True
|
||||
|
||||
for mc in self.multiconfigs:
|
||||
taskdata[mc].add_unresolved(localdata[mc], self.recipecaches[mc])
|
||||
|
||||
@@ -746,8 +705,8 @@ class BBCooker:
|
||||
if not dotname in depend_tree["tdepends"]:
|
||||
depend_tree["tdepends"][dotname] = []
|
||||
for dep in rq.rqdata.runtaskentries[tid].depends:
|
||||
(depmc, depfn, _, deptaskfn) = bb.runqueue.split_tid_mcfn(dep)
|
||||
deppn = self.recipecaches[depmc].pkg_fn[deptaskfn]
|
||||
(depmc, depfn, deptaskname, deptaskfn) = bb.runqueue.split_tid_mcfn(dep)
|
||||
deppn = self.recipecaches[mc].pkg_fn[deptaskfn]
|
||||
depend_tree["tdepends"][dotname].append("%s.%s" % (deppn, bb.runqueue.taskname_from_tid(dep)))
|
||||
if taskfn not in seen_fns:
|
||||
seen_fns.append(taskfn)
|
||||
@@ -897,12 +856,12 @@ class BBCooker:
|
||||
|
||||
with open('task-depends.dot', 'w') as f:
|
||||
f.write("digraph depends {\n")
|
||||
for task in sorted(depgraph["tdepends"]):
|
||||
for task in depgraph["tdepends"]:
|
||||
(pn, taskname) = task.rsplit(".", 1)
|
||||
fn = depgraph["pn"][pn]["filename"]
|
||||
version = depgraph["pn"][pn]["version"]
|
||||
f.write('"%s.%s" [label="%s %s\\n%s\\n%s"]\n' % (pn, taskname, pn, taskname, version, fn))
|
||||
for dep in sorted(depgraph["tdepends"][task]):
|
||||
for dep in depgraph["tdepends"][task]:
|
||||
f.write('"%s" -> "%s"\n' % (task, dep))
|
||||
f.write("}\n")
|
||||
logger.info("Task dependencies saved to 'task-depends.dot'")
|
||||
@@ -910,23 +869,23 @@ class BBCooker:
|
||||
with open('recipe-depends.dot', 'w') as f:
|
||||
f.write("digraph depends {\n")
|
||||
pndeps = {}
|
||||
for task in sorted(depgraph["tdepends"]):
|
||||
for task in depgraph["tdepends"]:
|
||||
(pn, taskname) = task.rsplit(".", 1)
|
||||
if pn not in pndeps:
|
||||
pndeps[pn] = set()
|
||||
for dep in sorted(depgraph["tdepends"][task]):
|
||||
for dep in depgraph["tdepends"][task]:
|
||||
(deppn, deptaskname) = dep.rsplit(".", 1)
|
||||
pndeps[pn].add(deppn)
|
||||
for pn in sorted(pndeps):
|
||||
for pn in pndeps:
|
||||
fn = depgraph["pn"][pn]["filename"]
|
||||
version = depgraph["pn"][pn]["version"]
|
||||
f.write('"%s" [label="%s\\n%s\\n%s"]\n' % (pn, pn, version, fn))
|
||||
for dep in sorted(pndeps[pn]):
|
||||
for dep in pndeps[pn]:
|
||||
if dep == pn:
|
||||
continue
|
||||
f.write('"%s" -> "%s"\n' % (pn, dep))
|
||||
f.write("}\n")
|
||||
logger.info("Flattened recipe dependencies saved to 'recipe-depends.dot'")
|
||||
logger.info("Flatened recipe dependencies saved to 'recipe-depends.dot'")
|
||||
|
||||
def show_appends_with_no_recipes(self):
|
||||
# Determine which bbappends haven't been applied
|
||||
@@ -1210,7 +1169,6 @@ class BBCooker:
|
||||
continue
|
||||
elif regex == "":
|
||||
parselog.debug(1, "BBFILE_PATTERN_%s is empty" % c)
|
||||
cre = re.compile('^NULL$')
|
||||
errors = False
|
||||
else:
|
||||
try:
|
||||
@@ -1606,7 +1564,7 @@ class BBCooker:
|
||||
pkgs_to_build.append(t)
|
||||
|
||||
if 'universe' in pkgs_to_build:
|
||||
parselog.verbnote("The \"universe\" target is only intended for testing and may produce errors.")
|
||||
parselog.warning("The \"universe\" target is only intended for testing and may produce errors.")
|
||||
parselog.debug(1, "collating packages for \"universe\"")
|
||||
pkgs_to_build.remove('universe')
|
||||
for mc in self.multiconfigs:
|
||||
@@ -1645,6 +1603,8 @@ class BBCooker:
|
||||
|
||||
if self.parser:
|
||||
self.parser.shutdown(clean=not force, force=force)
|
||||
self.notifier.stop()
|
||||
self.confignotifier.stop()
|
||||
|
||||
def finishcommand(self):
|
||||
self.state = state.initial
|
||||
@@ -1673,10 +1633,7 @@ class CookerExit(bb.event.Event):
|
||||
class CookerCollectFiles(object):
|
||||
def __init__(self, priorities):
|
||||
self.bbappends = []
|
||||
# Priorities is a list of tupples, with the second element as the pattern.
|
||||
# We need to sort the list with the longest pattern first, and so on to
|
||||
# the shortest. This allows nested layers to be properly evaluated.
|
||||
self.bbfile_config_priorities = sorted(priorities, key=lambda tup: tup[1], reverse=True)
|
||||
self.bbfile_config_priorities = priorities
|
||||
|
||||
def calc_bbfile_priority( self, filename, matched = None ):
|
||||
for _, _, regex, pri in self.bbfile_config_priorities:
|
||||
@@ -1850,25 +1807,21 @@ class CookerCollectFiles(object):
|
||||
realfn, cls, mc = bb.cache.virtualfn2realfn(p)
|
||||
priorities[p] = self.calc_bbfile_priority(realfn, matched)
|
||||
|
||||
# Don't show the warning if the BBFILE_PATTERN did match .bbappend files
|
||||
unmatched = set()
|
||||
for _, _, regex, pri in self.bbfile_config_priorities:
|
||||
if not regex in matched:
|
||||
unmatched.add(regex)
|
||||
|
||||
# Don't show the warning if the BBFILE_PATTERN did match .bbappend files
|
||||
def find_bbappend_match(regex):
|
||||
def findmatch(regex):
|
||||
for b in self.bbappends:
|
||||
(bbfile, append) = b
|
||||
if regex.match(append):
|
||||
# If the bbappend is matched by already "matched set", return False
|
||||
for matched_regex in matched:
|
||||
if matched_regex.match(append):
|
||||
return False
|
||||
return True
|
||||
return False
|
||||
|
||||
for unmatch in unmatched.copy():
|
||||
if find_bbappend_match(unmatch):
|
||||
if findmatch(unmatch):
|
||||
unmatched.remove(unmatch)
|
||||
|
||||
for collection, pattern, regex, _ in self.bbfile_config_priorities:
|
||||
@@ -1884,6 +1837,35 @@ class ParsingFailure(Exception):
|
||||
self.recipe = recipe
|
||||
Exception.__init__(self, realexception, recipe)
|
||||
|
||||
class Feeder(multiprocessing.Process):
|
||||
def __init__(self, jobs, to_parsers, quit):
|
||||
self.quit = quit
|
||||
self.jobs = jobs
|
||||
self.to_parsers = to_parsers
|
||||
multiprocessing.Process.__init__(self)
|
||||
|
||||
def run(self):
|
||||
while True:
|
||||
try:
|
||||
quit = self.quit.get_nowait()
|
||||
except queue.Empty:
|
||||
pass
|
||||
else:
|
||||
if quit == 'cancel':
|
||||
self.to_parsers.cancel_join_thread()
|
||||
break
|
||||
|
||||
try:
|
||||
job = self.jobs.pop()
|
||||
except IndexError:
|
||||
break
|
||||
|
||||
try:
|
||||
self.to_parsers.put(job, timeout=0.5)
|
||||
except queue.Full:
|
||||
self.jobs.insert(0, job)
|
||||
continue
|
||||
|
||||
class Parser(multiprocessing.Process):
|
||||
def __init__(self, jobs, results, quit, init, profile):
|
||||
self.jobs = jobs
|
||||
@@ -1930,8 +1912,11 @@ class Parser(multiprocessing.Process):
|
||||
result = pending.pop()
|
||||
else:
|
||||
try:
|
||||
job = self.jobs.pop()
|
||||
except IndexError:
|
||||
job = self.jobs.get(timeout=0.25)
|
||||
except queue.Empty:
|
||||
continue
|
||||
|
||||
if job is None:
|
||||
break
|
||||
result = self.parse(*job)
|
||||
|
||||
@@ -2015,15 +2000,14 @@ class CookerParser(object):
|
||||
multiprocessing.util.Finalize(None, bb.codeparser.parser_cache_save, exitpriority=1)
|
||||
multiprocessing.util.Finalize(None, bb.fetch.fetcher_parse_save, exitpriority=1)
|
||||
|
||||
self.feeder_quit = multiprocessing.Queue(maxsize=1)
|
||||
self.parser_quit = multiprocessing.Queue(maxsize=self.num_processes)
|
||||
self.jobs = multiprocessing.Queue(maxsize=self.num_processes)
|
||||
self.result_queue = multiprocessing.Queue()
|
||||
|
||||
def chunkify(lst,n):
|
||||
return [lst[i::n] for i in range(n)]
|
||||
self.jobs = chunkify(self.willparse, self.num_processes)
|
||||
|
||||
self.feeder = Feeder(self.willparse, self.jobs, self.feeder_quit)
|
||||
self.feeder.start()
|
||||
for i in range(0, self.num_processes):
|
||||
parser = Parser(self.jobs[i], self.result_queue, self.parser_quit, init, self.cooker.configuration.profile)
|
||||
parser = Parser(self.jobs, self.result_queue, self.parser_quit, init, self.cooker.configuration.profile)
|
||||
parser.start()
|
||||
self.process_names.append(parser.name)
|
||||
self.processes.append(parser)
|
||||
@@ -2044,19 +2028,25 @@ class CookerParser(object):
|
||||
self.total)
|
||||
|
||||
bb.event.fire(event, self.cfgdata)
|
||||
self.feeder_quit.put(None)
|
||||
for process in self.processes:
|
||||
self.parser_quit.put(None)
|
||||
else:
|
||||
self.feeder_quit.put('cancel')
|
||||
|
||||
self.parser_quit.cancel_join_thread()
|
||||
for process in self.processes:
|
||||
self.parser_quit.put(None)
|
||||
|
||||
self.jobs.cancel_join_thread()
|
||||
|
||||
for process in self.processes:
|
||||
if force:
|
||||
process.join(.1)
|
||||
process.terminate()
|
||||
else:
|
||||
process.join()
|
||||
self.feeder.join()
|
||||
|
||||
sync = threading.Thread(target=self.bb_cache.sync)
|
||||
sync.start()
|
||||
|
||||
@@ -9,14 +9,23 @@
|
||||
# Copyright (C) 2005 ROAD GmbH
|
||||
# Copyright (C) 2006 Richard Purdie
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# 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 logging
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import hashlib
|
||||
from functools import wraps
|
||||
import bb
|
||||
from bb import data
|
||||
@@ -134,8 +143,7 @@ class CookerConfiguration(object):
|
||||
self.writeeventlog = False
|
||||
self.server_only = False
|
||||
self.limited_deps = False
|
||||
self.runall = []
|
||||
self.runonly = []
|
||||
self.runall = None
|
||||
|
||||
self.env = {}
|
||||
|
||||
@@ -270,7 +278,6 @@ class CookerDataBuilder(object):
|
||||
self.mcdata = {}
|
||||
|
||||
def parseBaseConfiguration(self):
|
||||
data_hash = hashlib.sha256()
|
||||
try:
|
||||
bb.parse.init_parser(self.basedata)
|
||||
self.data = self.parseConfigurationFiles(self.prefiles, self.postfiles)
|
||||
@@ -294,7 +301,7 @@ class CookerDataBuilder(object):
|
||||
bb.event.fire(bb.event.ConfigParsed(), self.data)
|
||||
|
||||
bb.parse.init_parser(self.data)
|
||||
data_hash.update(self.data.get_hash().encode('utf-8'))
|
||||
self.data_hash = self.data.get_hash()
|
||||
self.mcdata[''] = self.data
|
||||
|
||||
multiconfig = (self.data.getVar("BBMULTICONFIG") or "").split()
|
||||
@@ -302,11 +309,9 @@ class CookerDataBuilder(object):
|
||||
mcdata = self.parseConfigurationFiles(self.prefiles, self.postfiles, config)
|
||||
bb.event.fire(bb.event.ConfigParsed(), mcdata)
|
||||
self.mcdata[config] = mcdata
|
||||
data_hash.update(mcdata.get_hash().encode('utf-8'))
|
||||
if multiconfig:
|
||||
bb.event.fire(bb.event.MultiConfigParsed(self.mcdata), self.data)
|
||||
|
||||
self.data_hash = data_hash.hexdigest()
|
||||
except (SyntaxError, bb.BBHandledException):
|
||||
raise bb.BBHandledException
|
||||
except bb.data_smart.ExpansionError as e:
|
||||
@@ -385,17 +390,11 @@ class CookerDataBuilder(object):
|
||||
bb.fatal("BBFILES_DYNAMIC entries must be of the form <collection name>:<filename pattern>, not:\n %s" % "\n ".join(invalid))
|
||||
|
||||
layerseries = set((data.getVar("LAYERSERIES_CORENAMES") or "").split())
|
||||
collections_tmp = collections[:]
|
||||
for c in collections:
|
||||
collections_tmp.remove(c)
|
||||
if c in collections_tmp:
|
||||
bb.fatal("Found duplicated BBFILE_COLLECTIONS '%s', check bblayers.conf or layer.conf to fix it." % c)
|
||||
compat = set((data.getVar("LAYERSERIES_COMPAT_%s" % c) or "").split())
|
||||
if compat and not (compat & layerseries):
|
||||
bb.fatal("Layer %s is not compatible with the core layer which only supports these series: %s (layer is compatible with %s)"
|
||||
% (c, " ".join(layerseries), " ".join(compat)))
|
||||
elif not compat and not data.getVar("BB_WORKERCONTEXT"):
|
||||
bb.warn("Layer %s should set LAYERSERIES_COMPAT_%s in its conf/layer.conf file to list the core layer names it is compatible with." % (c, c))
|
||||
|
||||
if not data.getVar("BBPATH"):
|
||||
msg = "The BBPATH variable is not set"
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
#
|
||||
|
||||
"""
|
||||
Python Daemonizing helper
|
||||
|
||||
@@ -20,10 +16,6 @@ def createDaemon(function, logfile):
|
||||
background as a daemon, returning control to the caller.
|
||||
"""
|
||||
|
||||
# Ensure stdout/stderror are flushed before forking to avoid duplicate output
|
||||
sys.stdout.flush()
|
||||
sys.stderr.flush()
|
||||
|
||||
try:
|
||||
# Fork a child process so the parent can exit. This returns control to
|
||||
# the command-line or shell. It also guarantees that the child will not
|
||||
@@ -57,8 +49,8 @@ def createDaemon(function, logfile):
|
||||
# exit() or _exit()?
|
||||
# _exit is like exit(), but it doesn't call any functions registered
|
||||
# with atexit (and on_exit) or any registered signal handlers. It also
|
||||
# closes any open file descriptors, but doesn't flush any buffered output.
|
||||
# Using exit() may cause all any temporary files to be unexpectedly
|
||||
# closes any open file descriptors. Using exit() may cause all stdio
|
||||
# streams to be flushed twice and any temporary files may be unexpectedly
|
||||
# removed. It's therefore recommended that child branches of a fork()
|
||||
# and the parent branch(es) of a daemon use _exit().
|
||||
os._exit(0)
|
||||
@@ -69,19 +61,17 @@ def createDaemon(function, logfile):
|
||||
# The second child.
|
||||
|
||||
# Replace standard fds with our own
|
||||
with open('/dev/null', 'r') as si:
|
||||
os.dup2(si.fileno(), sys.stdin.fileno())
|
||||
si = open('/dev/null', 'r')
|
||||
os.dup2(si.fileno(), sys.stdin.fileno())
|
||||
|
||||
try:
|
||||
so = open(logfile, 'a+')
|
||||
se = so
|
||||
os.dup2(so.fileno(), sys.stdout.fileno())
|
||||
os.dup2(so.fileno(), sys.stderr.fileno())
|
||||
os.dup2(se.fileno(), sys.stderr.fileno())
|
||||
except io.UnsupportedOperation:
|
||||
sys.stdout = open(logfile, 'a+')
|
||||
|
||||
# Have stdout and stderr be the same so log output matches chronologically
|
||||
# and there aren't two seperate buffers
|
||||
sys.stderr = sys.stdout
|
||||
sys.stderr = sys.stdout
|
||||
|
||||
try:
|
||||
function()
|
||||
@@ -89,9 +79,4 @@ def createDaemon(function, logfile):
|
||||
traceback.print_exc()
|
||||
finally:
|
||||
bb.event.print_ui_queue()
|
||||
# os._exit() doesn't flush open files like os.exit() does. Manually flush
|
||||
# stdout and stderr so that any logging output will be seen, particularly
|
||||
# exception tracebacks.
|
||||
sys.stdout.flush()
|
||||
sys.stderr.flush()
|
||||
os._exit(0)
|
||||
|
||||
@@ -22,12 +22,22 @@ the speed is more critical here.
|
||||
# Copyright (C) 2003, 2004 Chris Larson
|
||||
# Copyright (C) 2005 Holger Hans Peter Freyther
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# 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 sys, os, re
|
||||
import hashlib
|
||||
if sys.argv[0][-5:] == "pydoc":
|
||||
path = os.path.dirname(os.path.dirname(sys.argv[1]))
|
||||
else:
|
||||
@@ -273,12 +283,14 @@ def build_dependencies(key, keys, shelldeps, varflagsexcl, d):
|
||||
try:
|
||||
if key[-1] == ']':
|
||||
vf = key[:-1].split('[')
|
||||
value, parser = d.getVarFlag(vf[0], vf[1], False, retparser=True)
|
||||
value = d.getVarFlag(vf[0], vf[1], False)
|
||||
parser = d.expandWithRefs(value, key)
|
||||
deps |= parser.references
|
||||
deps = deps | (keys & parser.execs)
|
||||
return deps, value
|
||||
varflags = d.getVarFlags(key, ["vardeps", "vardepvalue", "vardepsexclude", "exports", "postfuncs", "prefuncs", "lineno", "filename"]) or {}
|
||||
vardeps = varflags.get("vardeps")
|
||||
value = d.getVarFlag(key, "_content", False)
|
||||
|
||||
def handle_contains(value, contains, d):
|
||||
newvalue = ""
|
||||
@@ -297,34 +309,25 @@ def build_dependencies(key, keys, shelldeps, varflagsexcl, d):
|
||||
return newvalue
|
||||
return value + newvalue
|
||||
|
||||
def handle_remove(value, deps, removes, d):
|
||||
for r in sorted(removes):
|
||||
r2 = d.expandWithRefs(r, None)
|
||||
value += "\n_remove of %s" % r
|
||||
deps |= r2.references
|
||||
deps = deps | (keys & r2.execs)
|
||||
return value
|
||||
|
||||
if "vardepvalue" in varflags:
|
||||
value = varflags.get("vardepvalue")
|
||||
value = varflags.get("vardepvalue")
|
||||
elif varflags.get("func"):
|
||||
if varflags.get("python"):
|
||||
value = d.getVarFlag(key, "_content", False)
|
||||
parser = bb.codeparser.PythonParser(key, logger)
|
||||
if value and "\t" in value:
|
||||
logger.warning("Variable %s contains tabs, please remove these (%s)" % (key, d.getVar("FILE")))
|
||||
parser.parse_python(value, filename=varflags.get("filename"), lineno=varflags.get("lineno"))
|
||||
deps = deps | parser.references
|
||||
deps = deps | (keys & parser.execs)
|
||||
value = handle_contains(value, parser.contains, d)
|
||||
else:
|
||||
value, parsedvar = d.getVarFlag(key, "_content", False, retparser=True)
|
||||
parsedvar = d.expandWithRefs(value, key)
|
||||
parser = bb.codeparser.ShellParser(key, logger)
|
||||
parser.parse_shell(parsedvar.value)
|
||||
deps = deps | shelldeps
|
||||
deps = deps | parsedvar.references
|
||||
deps = deps | (keys & parser.execs) | (keys & parsedvar.execs)
|
||||
value = handle_contains(value, parsedvar.contains, d)
|
||||
if hasattr(parsedvar, "removes"):
|
||||
value = handle_remove(value, deps, parsedvar.removes, d)
|
||||
if vardeps is None:
|
||||
parser.log.flush()
|
||||
if "prefuncs" in varflags:
|
||||
@@ -334,12 +337,10 @@ def build_dependencies(key, keys, shelldeps, varflagsexcl, d):
|
||||
if "exports" in varflags:
|
||||
deps = deps | set(varflags["exports"].split())
|
||||
else:
|
||||
value, parser = d.getVarFlag(key, "_content", False, retparser=True)
|
||||
parser = d.expandWithRefs(value, key)
|
||||
deps |= parser.references
|
||||
deps = deps | (keys & parser.execs)
|
||||
value = handle_contains(value, parser.contains, d)
|
||||
if hasattr(parser, "removes"):
|
||||
value = handle_remove(value, deps, parser.removes, d)
|
||||
|
||||
if "vardepvalueexclude" in varflags:
|
||||
exclude = varflags.get("vardepvalueexclude")
|
||||
@@ -393,43 +394,6 @@ def generate_dependencies(d):
|
||||
#print "For %s: %s" % (task, str(deps[task]))
|
||||
return tasklist, deps, values
|
||||
|
||||
def generate_dependency_hash(tasklist, gendeps, lookupcache, whitelist, fn):
|
||||
taskdeps = {}
|
||||
basehash = {}
|
||||
|
||||
for task in tasklist:
|
||||
data = lookupcache[task]
|
||||
|
||||
if data is None:
|
||||
bb.error("Task %s from %s seems to be empty?!" % (task, fn))
|
||||
data = ''
|
||||
|
||||
gendeps[task] -= whitelist
|
||||
newdeps = gendeps[task]
|
||||
seen = set()
|
||||
while newdeps:
|
||||
nextdeps = newdeps
|
||||
seen |= nextdeps
|
||||
newdeps = set()
|
||||
for dep in nextdeps:
|
||||
if dep in whitelist:
|
||||
continue
|
||||
gendeps[dep] -= whitelist
|
||||
newdeps |= gendeps[dep]
|
||||
newdeps -= seen
|
||||
|
||||
alldeps = sorted(seen)
|
||||
for dep in alldeps:
|
||||
data = data + dep
|
||||
var = lookupcache[dep]
|
||||
if var is not None:
|
||||
data = data + str(var)
|
||||
k = fn + "." + task
|
||||
basehash[k] = hashlib.sha256(data.encode("utf-8")).hexdigest()
|
||||
taskdeps[task] = alldeps
|
||||
|
||||
return taskdeps, basehash
|
||||
|
||||
def inherits_class(klass, d):
|
||||
val = d.getVar('__inherit_cache', False) or []
|
||||
needle = os.path.join('classes', '%s.bbclass' % klass)
|
||||
|
||||
@@ -14,8 +14,18 @@ BitBake build tools.
|
||||
# Copyright (C) 2005 Uli Luckas
|
||||
# Copyright (C) 2005 ROAD GmbH
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# 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 copy, re, sys, traceback
|
||||
@@ -29,11 +39,9 @@ from bb.COW import COWDictBase
|
||||
logger = logging.getLogger("BitBake.Data")
|
||||
|
||||
__setvar_keyword__ = ["_append", "_prepend", "_remove"]
|
||||
__setvar_regexp__ = re.compile(r'(?P<base>.*?)(?P<keyword>_append|_prepend|_remove)(_(?P<add>[^A-Z]*))?$')
|
||||
__expand_var_regexp__ = re.compile(r"\${[a-zA-Z0-9\-_+./~]+?}")
|
||||
__setvar_regexp__ = re.compile('(?P<base>.*?)(?P<keyword>_append|_prepend|_remove)(_(?P<add>[^A-Z]*))?$')
|
||||
__expand_var_regexp__ = re.compile(r"\${[^{}@\n\t :]+}")
|
||||
__expand_python_regexp__ = re.compile(r"\${@.+?}")
|
||||
__whitespace_split__ = re.compile(r'(\s)')
|
||||
__override_regexp__ = re.compile(r'[a-z0-9]+')
|
||||
|
||||
def infer_caller_details(loginfo, parent = False, varval = True):
|
||||
"""Save the caller the trouble of specifying everything."""
|
||||
@@ -96,7 +104,11 @@ class VariableParse:
|
||||
if self.varname and key:
|
||||
if self.varname == key:
|
||||
raise Exception("variable %s references itself!" % self.varname)
|
||||
var = self.d.getVarFlag(key, "_content")
|
||||
if key in self.d.expand_cache:
|
||||
varparse = self.d.expand_cache[key]
|
||||
var = varparse.value
|
||||
else:
|
||||
var = self.d.getVarFlag(key, "_content")
|
||||
self.references.add(key)
|
||||
if var is not None:
|
||||
return var
|
||||
@@ -113,11 +125,7 @@ class VariableParse:
|
||||
connector = self.d["_remote_data"]
|
||||
return connector.expandPythonRef(self.varname, code, self.d)
|
||||
|
||||
if self.varname:
|
||||
varname = 'Var <%s>' % self.varname
|
||||
else:
|
||||
varname = '<expansion>'
|
||||
codeobj = compile(code.strip(), varname, "eval")
|
||||
codeobj = compile(code.strip(), self.varname or "<expansion>", "eval")
|
||||
|
||||
parser = bb.codeparser.PythonParser(self.varname, logger)
|
||||
parser.parse_python(code)
|
||||
@@ -259,16 +267,6 @@ class VariableHistory(object):
|
||||
return
|
||||
self.variables[var].append(loginfo.copy())
|
||||
|
||||
def rename_variable_hist(self, oldvar, newvar):
|
||||
if not self.dataroot._tracking:
|
||||
return
|
||||
if oldvar not in self.variables:
|
||||
return
|
||||
if newvar not in self.variables:
|
||||
self.variables[newvar] = []
|
||||
for i in self.variables[oldvar]:
|
||||
self.variables[newvar].append(i.copy())
|
||||
|
||||
def variable(self, var):
|
||||
remote_connector = self.dataroot.getVar('_remote_data', False)
|
||||
if remote_connector:
|
||||
@@ -403,6 +401,9 @@ class DataSmart(MutableMapping):
|
||||
if not isinstance(s, str): # sanity check
|
||||
return VariableParse(varname, self, s)
|
||||
|
||||
if varname and varname in self.expand_cache:
|
||||
return self.expand_cache[varname]
|
||||
|
||||
varparse = VariableParse(varname, self)
|
||||
|
||||
while s.find('${') != -1:
|
||||
@@ -422,11 +423,13 @@ class DataSmart(MutableMapping):
|
||||
except bb.parse.SkipRecipe:
|
||||
raise
|
||||
except Exception as exc:
|
||||
tb = sys.exc_info()[2]
|
||||
raise ExpansionError(varname, s, exc).with_traceback(tb) from exc
|
||||
raise ExpansionError(varname, s, exc) from exc
|
||||
|
||||
varparse.value = s
|
||||
|
||||
if varname:
|
||||
self.expand_cache[varname] = varparse
|
||||
|
||||
return varparse
|
||||
|
||||
def expand(self, s, varname = None):
|
||||
@@ -495,7 +498,6 @@ class DataSmart(MutableMapping):
|
||||
|
||||
def setVar(self, var, value, **loginfo):
|
||||
#print("var=" + str(var) + " val=" + str(value))
|
||||
self.expand_cache = {}
|
||||
parsing=False
|
||||
if 'parsing' in loginfo:
|
||||
parsing=True
|
||||
@@ -508,7 +510,7 @@ class DataSmart(MutableMapping):
|
||||
|
||||
if 'op' not in loginfo:
|
||||
loginfo['op'] = "set"
|
||||
|
||||
self.expand_cache = {}
|
||||
match = __setvar_regexp__.match(var)
|
||||
if match and match.group("keyword") in __setvar_keyword__:
|
||||
base = match.group('base')
|
||||
@@ -588,7 +590,7 @@ class DataSmart(MutableMapping):
|
||||
# aka pay the cookie monster
|
||||
override = var[var.rfind('_')+1:]
|
||||
shortvar = var[:var.rfind('_')]
|
||||
while override and __override_regexp__.match(override):
|
||||
while override and override.islower():
|
||||
if shortvar not in self.overridedata:
|
||||
self.overridedata[shortvar] = []
|
||||
if [var, override] not in self.overridedata[shortvar]:
|
||||
@@ -617,7 +619,6 @@ class DataSmart(MutableMapping):
|
||||
|
||||
val = self.getVar(key, 0, parsing=True)
|
||||
if val is not None:
|
||||
self.varhistory.rename_variable_hist(key, newkey)
|
||||
loginfo['variable'] = newkey
|
||||
loginfo['op'] = 'rename from %s' % key
|
||||
loginfo['detail'] = val
|
||||
@@ -659,7 +660,6 @@ class DataSmart(MutableMapping):
|
||||
self.setVar(var + "_prepend", value, ignore=True, parsing=True)
|
||||
|
||||
def delVar(self, var, **loginfo):
|
||||
self.expand_cache = {}
|
||||
if '_remote_data' in self.dict:
|
||||
connector = self.dict["_remote_data"]["_content"]
|
||||
res = connector.delVar(var)
|
||||
@@ -669,6 +669,7 @@ class DataSmart(MutableMapping):
|
||||
loginfo['detail'] = ""
|
||||
loginfo['op'] = 'del'
|
||||
self.varhistory.record(**loginfo)
|
||||
self.expand_cache = {}
|
||||
self.dict[var] = {}
|
||||
if var in self.overridedata:
|
||||
del self.overridedata[var]
|
||||
@@ -691,13 +692,13 @@ class DataSmart(MutableMapping):
|
||||
override = None
|
||||
|
||||
def setVarFlag(self, var, flag, value, **loginfo):
|
||||
self.expand_cache = {}
|
||||
if '_remote_data' in self.dict:
|
||||
connector = self.dict["_remote_data"]["_content"]
|
||||
res = connector.setVarFlag(var, flag, value)
|
||||
if not res:
|
||||
return
|
||||
|
||||
self.expand_cache = {}
|
||||
if 'op' not in loginfo:
|
||||
loginfo['op'] = "set"
|
||||
loginfo['flag'] = flag
|
||||
@@ -718,21 +719,9 @@ class DataSmart(MutableMapping):
|
||||
self.dict["__exportlist"]["_content"] = set()
|
||||
self.dict["__exportlist"]["_content"].add(var)
|
||||
|
||||
def getVarFlag(self, var, flag, expand=True, noweakdefault=False, parsing=False, retparser=False):
|
||||
if flag == "_content":
|
||||
cachename = var
|
||||
else:
|
||||
if not flag:
|
||||
bb.warn("Calling getVarFlag with flag unset is invalid")
|
||||
return None
|
||||
cachename = var + "[" + flag + "]"
|
||||
|
||||
if expand and cachename in self.expand_cache:
|
||||
return self.expand_cache[cachename].value
|
||||
|
||||
def getVarFlag(self, var, flag, expand=True, noweakdefault=False, parsing=False):
|
||||
local_var, overridedata = self._findVar(var)
|
||||
value = None
|
||||
removes = set()
|
||||
if flag == "_content" and overridedata is not None and not parsing:
|
||||
match = False
|
||||
active = {}
|
||||
@@ -759,11 +748,7 @@ class DataSmart(MutableMapping):
|
||||
match = active[a]
|
||||
del active[a]
|
||||
if match:
|
||||
value, subparser = self.getVarFlag(match, "_content", False, retparser=True)
|
||||
if hasattr(subparser, "removes"):
|
||||
# We have to carry the removes from the overridden variable to apply at the
|
||||
# end of processing
|
||||
removes = subparser.removes
|
||||
value = self.getVar(match, False)
|
||||
|
||||
if local_var is not None and value is None:
|
||||
if flag in local_var:
|
||||
@@ -799,13 +784,17 @@ class DataSmart(MutableMapping):
|
||||
if match:
|
||||
value = r + value
|
||||
|
||||
parser = None
|
||||
if expand or retparser:
|
||||
parser = self.expandWithRefs(value, cachename)
|
||||
if expand:
|
||||
value = parser.value
|
||||
if expand and value:
|
||||
# Only getvar (flag == _content) hits the expand cache
|
||||
cachename = None
|
||||
if flag == "_content":
|
||||
cachename = var
|
||||
else:
|
||||
cachename = var + "[" + flag + "]"
|
||||
value = self.expand(value, cachename)
|
||||
|
||||
if value and flag == "_content" and local_var is not None and "_remove" in local_var and not parsing:
|
||||
if value and flag == "_content" and local_var is not None and "_remove" in local_var:
|
||||
removes = []
|
||||
self.need_overrides()
|
||||
for (r, o) in local_var["_remove"]:
|
||||
match = True
|
||||
@@ -814,45 +803,26 @@ class DataSmart(MutableMapping):
|
||||
if not o2 in self.overrides:
|
||||
match = False
|
||||
if match:
|
||||
removes.add(r)
|
||||
|
||||
if value and flag == "_content" and not parsing:
|
||||
if removes and parser:
|
||||
expanded_removes = {}
|
||||
for r in removes:
|
||||
expanded_removes[r] = self.expand(r).split()
|
||||
|
||||
parser.removes = set()
|
||||
val = ""
|
||||
for v in __whitespace_split__.split(parser.value):
|
||||
skip = False
|
||||
for r in removes:
|
||||
if v in expanded_removes[r]:
|
||||
parser.removes.add(r)
|
||||
skip = True
|
||||
if skip:
|
||||
continue
|
||||
val = val + v
|
||||
parser.value = val
|
||||
if expand:
|
||||
value = parser.value
|
||||
|
||||
if parser:
|
||||
self.expand_cache[cachename] = parser
|
||||
|
||||
if retparser:
|
||||
return value, parser
|
||||
removes.extend(self.expand(r).split())
|
||||
|
||||
if removes:
|
||||
filtered = filter(lambda v: v not in removes,
|
||||
value.split())
|
||||
value = " ".join(filtered)
|
||||
if expand and var in self.expand_cache:
|
||||
# We need to ensure the expand cache has the correct value
|
||||
# flag == "_content" here
|
||||
self.expand_cache[var].value = value
|
||||
return value
|
||||
|
||||
def delVarFlag(self, var, flag, **loginfo):
|
||||
self.expand_cache = {}
|
||||
if '_remote_data' in self.dict:
|
||||
connector = self.dict["_remote_data"]["_content"]
|
||||
res = connector.delVarFlag(var, flag)
|
||||
if not res:
|
||||
return
|
||||
|
||||
self.expand_cache = {}
|
||||
local_var, _ = self._findVar(var)
|
||||
if not local_var:
|
||||
return
|
||||
@@ -1064,4 +1034,4 @@ class DataSmart(MutableMapping):
|
||||
data.update({i:value})
|
||||
|
||||
data_str = str([(k, data[k]) for k in sorted(data.keys())])
|
||||
return hashlib.sha256(data_str.encode("utf-8")).hexdigest()
|
||||
return hashlib.md5(data_str.encode("utf-8")).hexdigest()
|
||||
|
||||
@@ -9,8 +9,18 @@ BitBake build tools.
|
||||
|
||||
# Copyright (C) 2003, 2004 Chris Larson
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# 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
|
||||
import warnings
|
||||
@@ -131,9 +141,6 @@ def print_ui_queue():
|
||||
logger = logging.getLogger("BitBake")
|
||||
if not _uiready:
|
||||
from bb.msg import BBLogFormatter
|
||||
# Flush any existing buffered content
|
||||
sys.stdout.flush()
|
||||
sys.stderr.flush()
|
||||
stdout = logging.StreamHandler(sys.stdout)
|
||||
stderr = logging.StreamHandler(sys.stderr)
|
||||
formatter = BBLogFormatter("%(levelname)s: %(message)s")
|
||||
@@ -388,7 +395,7 @@ class RecipeEvent(Event):
|
||||
Event.__init__(self)
|
||||
|
||||
class RecipePreFinalise(RecipeEvent):
|
||||
""" Recipe Parsing Complete but not yet finalised"""
|
||||
""" Recipe Parsing Complete but not yet finialised"""
|
||||
|
||||
class RecipeTaskPreProcess(RecipeEvent):
|
||||
"""
|
||||
@@ -442,6 +449,12 @@ class BuildBase(Event):
|
||||
def setName(self, name):
|
||||
self._name = name
|
||||
|
||||
def getCfg(self):
|
||||
return self.data
|
||||
|
||||
def setCfg(self, cfg):
|
||||
self.data = cfg
|
||||
|
||||
def getFailures(self):
|
||||
"""
|
||||
Return the number of failed packages
|
||||
@@ -450,6 +463,9 @@ class BuildBase(Event):
|
||||
|
||||
pkgs = property(getPkgs, setPkgs, None, "pkgs property")
|
||||
name = property(getName, setName, None, "name property")
|
||||
cfg = property(getCfg, setCfg, None, "cfg property")
|
||||
|
||||
|
||||
|
||||
class BuildInit(BuildBase):
|
||||
"""buildFile or buildTargets was invoked"""
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
#
|
||||
|
||||
import inspect
|
||||
import traceback
|
||||
|
||||
@@ -10,7 +10,18 @@ BitBake build tools.
|
||||
# Copyright (C) 2003, 2004 Chris Larson
|
||||
# Copyright (C) 2012 Intel Corporation
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# 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
|
||||
|
||||
@@ -245,7 +256,7 @@ class URI(object):
|
||||
|
||||
# Identify if the URI is relative or not
|
||||
if urlp.scheme in self._relative_schemes and \
|
||||
re.compile(r"^\w+:(?!//)").match(uri):
|
||||
re.compile("^\w+:(?!//)").match(uri):
|
||||
self.relative = True
|
||||
|
||||
if not self.relative:
|
||||
@@ -372,7 +383,7 @@ def decodeurl(url):
|
||||
path = location
|
||||
else:
|
||||
host = location
|
||||
path = "/"
|
||||
path = ""
|
||||
if user:
|
||||
m = re.compile('(?P<user>[^:]+)(:?(?P<pswd>.*))').match(user)
|
||||
if m:
|
||||
@@ -441,8 +452,8 @@ def uri_replace(ud, uri_find, uri_replace, replacements, d, mirrortarball=None):
|
||||
# Handle URL parameters
|
||||
if i:
|
||||
# Any specified URL parameters must match
|
||||
for k in uri_find_decoded[loc]:
|
||||
if uri_decoded[loc][k] != uri_find_decoded[loc][k]:
|
||||
for k in uri_replace_decoded[loc]:
|
||||
if uri_decoded[loc][k] != uri_replace_decoded[loc][k]:
|
||||
return None
|
||||
# Overwrite any specified replacement parameters
|
||||
for k in uri_replace_decoded[loc]:
|
||||
@@ -513,7 +524,7 @@ def fetcher_parse_save():
|
||||
def fetcher_parse_done():
|
||||
_checksum_cache.save_merge()
|
||||
|
||||
def fetcher_compare_revisions(d):
|
||||
def fetcher_compare_revisions():
|
||||
"""
|
||||
Compare the revisions in the persistant cache with current values and
|
||||
return true/false on whether they've changed.
|
||||
@@ -632,25 +643,26 @@ def verify_donestamp(ud, d, origud=None):
|
||||
if not ud.needdonestamp or (origud and not origud.needdonestamp):
|
||||
return True
|
||||
|
||||
if not os.path.exists(ud.localpath):
|
||||
# local path does not exist
|
||||
if os.path.exists(ud.donestamp):
|
||||
# done stamp exists, but the downloaded file does not; the done stamp
|
||||
# must be incorrect, re-trigger the download
|
||||
bb.utils.remove(ud.donestamp)
|
||||
if not os.path.exists(ud.donestamp):
|
||||
return False
|
||||
|
||||
if (not ud.method.supports_checksum(ud) or
|
||||
(origud and not origud.method.supports_checksum(origud))):
|
||||
# if done stamp exists and checksums not supported; assume the local
|
||||
# file is current
|
||||
return os.path.exists(ud.donestamp)
|
||||
# done stamp exists, checksums not supported; assume the local file is
|
||||
# current
|
||||
return True
|
||||
|
||||
if not os.path.exists(ud.localpath):
|
||||
# done stamp exists, but the downloaded file does not; the done stamp
|
||||
# must be incorrect, re-trigger the download
|
||||
bb.utils.remove(ud.donestamp)
|
||||
return False
|
||||
|
||||
precomputed_checksums = {}
|
||||
# Only re-use the precomputed checksums if the donestamp is newer than the
|
||||
# file. Do not rely on the mtime of directories, though. If ud.localpath is
|
||||
# a directory, there will probably not be any checksums anyway.
|
||||
if os.path.exists(ud.donestamp) and (os.path.isdir(ud.localpath) or
|
||||
if (os.path.isdir(ud.localpath) or
|
||||
os.path.getmtime(ud.localpath) < os.path.getmtime(ud.donestamp)):
|
||||
try:
|
||||
with open(ud.donestamp, "rb") as cachefile:
|
||||
@@ -766,8 +778,7 @@ def get_srcrev(d, method_name='sortable_revision'):
|
||||
#
|
||||
format = d.getVar('SRCREV_FORMAT')
|
||||
if not format:
|
||||
raise FetchError("The SRCREV_FORMAT variable must be set when multiple SCMs are used.\n"\
|
||||
"The SCMs are:\n%s" % '\n'.join(scms))
|
||||
raise FetchError("The SRCREV_FORMAT variable must be set when multiple SCMs are used.")
|
||||
|
||||
name_to_rev = {}
|
||||
seenautoinc = False
|
||||
@@ -817,7 +828,6 @@ def runfetchcmd(cmd, d, quiet=False, cleanup=None, log=None, workdir=None):
|
||||
'NO_PROXY', 'no_proxy',
|
||||
'ALL_PROXY', 'all_proxy',
|
||||
'GIT_PROXY_COMMAND',
|
||||
'GIT_SSH',
|
||||
'GIT_SSL_CAINFO',
|
||||
'GIT_SMART_HTTP',
|
||||
'SSH_AUTH_SOCK', 'SSH_AGENT_PID',
|
||||
@@ -828,16 +838,14 @@ def runfetchcmd(cmd, d, quiet=False, cleanup=None, log=None, workdir=None):
|
||||
if not cleanup:
|
||||
cleanup = []
|
||||
|
||||
# If PATH contains WORKDIR which contains PV-PR which contains SRCPV we
|
||||
# If PATH contains WORKDIR which contains PV which contains SRCPV we
|
||||
# can end up in circular recursion here so give the option of breaking it
|
||||
# in a data store copy.
|
||||
try:
|
||||
d.getVar("PV")
|
||||
d.getVar("PR")
|
||||
except bb.data_smart.ExpansionError:
|
||||
d = bb.data.createCopy(d)
|
||||
d.setVar("PV", "fetcheravoidrecurse")
|
||||
d.setVar("PR", "fetcheravoidrecurse")
|
||||
|
||||
origenv = d.getVar("BB_ORIGENV", False)
|
||||
for var in exportvars:
|
||||
@@ -845,18 +853,7 @@ def runfetchcmd(cmd, d, quiet=False, cleanup=None, log=None, workdir=None):
|
||||
if val:
|
||||
cmd = 'export ' + var + '=\"%s\"; %s' % (val, cmd)
|
||||
|
||||
# Ensure that a _PYTHON_SYSCONFIGDATA_NAME value set by a recipe
|
||||
# (for example via python3native.bbclass since warrior) is not set for
|
||||
# host Python (otherwise tools like git-make-shallow will fail)
|
||||
cmd = 'unset _PYTHON_SYSCONFIGDATA_NAME; ' + cmd
|
||||
|
||||
# Disable pseudo as it may affect ssh, potentially causing it to hang.
|
||||
cmd = 'export PSEUDO_DISABLED=1; ' + cmd
|
||||
|
||||
if workdir:
|
||||
logger.debug(1, "Running '%s' in %s" % (cmd, workdir))
|
||||
else:
|
||||
logger.debug(1, "Running %s", cmd)
|
||||
logger.debug(1, "Running %s", cmd)
|
||||
|
||||
success = False
|
||||
error_message = ""
|
||||
@@ -892,7 +889,7 @@ def check_network_access(d, info, url):
|
||||
log remote network access, and error if BB_NO_NETWORK is set or the given
|
||||
URI is untrusted
|
||||
"""
|
||||
if bb.utils.to_boolean(d.getVar("BB_NO_NETWORK")):
|
||||
if d.getVar("BB_NO_NETWORK") == "1":
|
||||
raise NetworkAccess(url, info)
|
||||
elif not trusted_network(d, url):
|
||||
raise UntrustedUrl(url, info)
|
||||
@@ -964,8 +961,7 @@ def rename_bad_checksum(ud, suffix):
|
||||
|
||||
new_localpath = "%s_bad-checksum_%s" % (ud.localpath, suffix)
|
||||
bb.warn("Renaming %s to %s" % (ud.localpath, new_localpath))
|
||||
if not bb.utils.movefile(ud.localpath, new_localpath):
|
||||
bb.warn("Renaming %s to %s failed, grep movefile in log.do_fetch to see why" % (ud.localpath, new_localpath))
|
||||
bb.utils.movefile(ud.localpath, new_localpath)
|
||||
|
||||
|
||||
def try_mirror_url(fetch, origud, ud, ld, check = False):
|
||||
@@ -1018,7 +1014,16 @@ def try_mirror_url(fetch, origud, ud, ld, check = False):
|
||||
origud.method.build_mirror_data(origud, ld)
|
||||
return origud.localpath
|
||||
# Otherwise the result is a local file:// and we symlink to it
|
||||
ensure_symlink(ud.localpath, origud.localpath)
|
||||
if not os.path.exists(origud.localpath):
|
||||
if os.path.islink(origud.localpath):
|
||||
# Broken symbolic link
|
||||
os.unlink(origud.localpath)
|
||||
|
||||
# As per above, in case two tasks end up here simultaneously.
|
||||
try:
|
||||
os.symlink(ud.localpath, origud.localpath)
|
||||
except FileExistsError:
|
||||
pass
|
||||
update_stamp(origud, ld)
|
||||
return ud.localpath
|
||||
|
||||
@@ -1026,7 +1031,7 @@ def try_mirror_url(fetch, origud, ud, ld, check = False):
|
||||
raise
|
||||
|
||||
except IOError as e:
|
||||
if e.errno in [errno.ESTALE]:
|
||||
if e.errno in [os.errno.ESTALE]:
|
||||
logger.warning("Stale Error Observed %s." % ud.url)
|
||||
return False
|
||||
raise
|
||||
@@ -1052,22 +1057,6 @@ def try_mirror_url(fetch, origud, ud, ld, check = False):
|
||||
bb.utils.unlockfile(lf)
|
||||
|
||||
|
||||
def ensure_symlink(target, link_name):
|
||||
if not os.path.exists(link_name):
|
||||
if os.path.islink(link_name):
|
||||
# Broken symbolic link
|
||||
os.unlink(link_name)
|
||||
|
||||
# In case this is executing without any file locks held (as is
|
||||
# the case for file:// URLs), two tasks may end up here at the
|
||||
# same time, in which case we do not want the second task to
|
||||
# fail when the link has already been created by the first task.
|
||||
try:
|
||||
os.symlink(target, link_name)
|
||||
except FileExistsError:
|
||||
pass
|
||||
|
||||
|
||||
def try_mirrors(fetch, d, origud, mirrors, check = False):
|
||||
"""
|
||||
Try to use a mirrored version of the sources.
|
||||
@@ -1093,13 +1082,11 @@ def trusted_network(d, url):
|
||||
BB_ALLOWED_NETWORKS is set globally or for a specific recipe.
|
||||
Note: modifies SRC_URI & mirrors.
|
||||
"""
|
||||
if bb.utils.to_boolean(d.getVar("BB_NO_NETWORK")):
|
||||
if d.getVar('BB_NO_NETWORK') == "1":
|
||||
return True
|
||||
|
||||
pkgname = d.expand(d.getVar('PN', False))
|
||||
trusted_hosts = None
|
||||
if pkgname:
|
||||
trusted_hosts = d.getVarFlag('BB_ALLOWED_NETWORKS', pkgname, False)
|
||||
trusted_hosts = d.getVarFlag('BB_ALLOWED_NETWORKS', pkgname, False)
|
||||
|
||||
if not trusted_hosts:
|
||||
trusted_hosts = d.getVar('BB_ALLOWED_NETWORKS')
|
||||
@@ -1402,7 +1389,7 @@ class FetchMethod(object):
|
||||
Fetch urls
|
||||
Assumes localpath was called first
|
||||
"""
|
||||
raise NoMethodError(urldata.url)
|
||||
raise NoMethodError(url)
|
||||
|
||||
def unpack(self, urldata, rootdir, data):
|
||||
iterate = False
|
||||
@@ -1437,7 +1424,7 @@ class FetchMethod(object):
|
||||
cmd = 'gzip -dc %s > %s' % (file, efile)
|
||||
elif file.endswith('.bz2'):
|
||||
cmd = 'bzip2 -dc %s > %s' % (file, efile)
|
||||
elif file.endswith('.txz') or file.endswith('.tar.xz'):
|
||||
elif file.endswith('.tar.xz'):
|
||||
cmd = 'xz -dc %s | tar x --no-same-owner -f -' % file
|
||||
elif file.endswith('.xz'):
|
||||
cmd = 'xz -dc %s > %s' % (file, efile)
|
||||
@@ -1468,7 +1455,7 @@ class FetchMethod(object):
|
||||
else:
|
||||
cmd = 'rpm2cpio.sh %s | cpio -id' % (file)
|
||||
elif file.endswith('.deb') or file.endswith('.ipk'):
|
||||
output = subprocess.check_output(['ar', '-t', file], preexec_fn=subprocess_setup)
|
||||
output = subprocess.check_output('ar -t %s' % file, preexec_fn=subprocess_setup, shell=True)
|
||||
datafile = None
|
||||
if output:
|
||||
for line in output.decode().splitlines():
|
||||
@@ -1546,7 +1533,7 @@ class FetchMethod(object):
|
||||
Check the status of a URL
|
||||
Assumes localpath was called first
|
||||
"""
|
||||
logger.info("URL %s could not be checked for status since no method exists.", urldata.url)
|
||||
logger.info("URL %s could not be checked for status since no method exists.", url)
|
||||
return True
|
||||
|
||||
def latest_revision(self, ud, d, name):
|
||||
@@ -1554,7 +1541,7 @@ class FetchMethod(object):
|
||||
Look in the cache for the latest revision, if not present ask the SCM.
|
||||
"""
|
||||
if not hasattr(self, "_latest_revision"):
|
||||
raise ParameterError("The fetcher for this URL does not support _latest_revision", ud.url)
|
||||
raise ParameterError("The fetcher for this URL does not support _latest_revision", url)
|
||||
|
||||
revs = bb.persist_data.persist('BB_URI_HEADREVS', d)
|
||||
key = self.generate_revision_key(ud, d, name)
|
||||
@@ -1637,7 +1624,7 @@ class Fetch(object):
|
||||
urls = self.urls
|
||||
|
||||
network = self.d.getVar("BB_NO_NETWORK")
|
||||
premirroronly = bb.utils.to_boolean(self.d.getVar("BB_FETCH_PREMIRRORONLY"))
|
||||
premirroronly = (self.d.getVar("BB_FETCH_PREMIRRORONLY") == "1")
|
||||
|
||||
for u in urls:
|
||||
ud = self.ud[u]
|
||||
@@ -1715,7 +1702,7 @@ class Fetch(object):
|
||||
update_stamp(ud, self.d)
|
||||
|
||||
except IOError as e:
|
||||
if e.errno in [errno.ESTALE]:
|
||||
if e.errno in [os.errno.ESTALE]:
|
||||
logger.error("Stale Error Observed %s." % u)
|
||||
raise ChecksumError("Stale Error Detected")
|
||||
|
||||
@@ -1785,7 +1772,7 @@ class Fetch(object):
|
||||
|
||||
for url in urls:
|
||||
if url not in self.ud:
|
||||
self.ud[url] = FetchData(url, self.d)
|
||||
self.ud[url] = FetchData(url, d)
|
||||
ud = self.ud[url]
|
||||
ud.setup_localpath(self.d)
|
||||
|
||||
|
||||
@@ -10,8 +10,18 @@ BitBake 'Fetch' implementation for bzr.
|
||||
# BitBake build tools.
|
||||
# Copyright (C) 2003, 2004 Chris Larson
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License version 2 as
|
||||
# published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
import os
|
||||
import sys
|
||||
@@ -31,9 +41,8 @@ class Bzr(FetchMethod):
|
||||
init bzr specific variable within url data
|
||||
"""
|
||||
# Create paths to bzr checkouts
|
||||
bzrdir = d.getVar("BZRDIR") or (d.getVar("DL_DIR") + "/bzr")
|
||||
relpath = self._strip_leading_slashes(ud.path)
|
||||
ud.pkgdir = os.path.join(bzrdir, ud.host, relpath)
|
||||
ud.pkgdir = os.path.join(d.expand('${BZRDIR}'), ud.host, relpath)
|
||||
|
||||
ud.setup_revisions(d)
|
||||
|
||||
@@ -48,7 +57,7 @@ class Bzr(FetchMethod):
|
||||
command is "fetch", "update", "revno"
|
||||
"""
|
||||
|
||||
basecmd = d.getVar("FETCHCMD_bzr") or "/usr/bin/env bzr"
|
||||
basecmd = d.expand('${FETCHCMD_bzr}')
|
||||
|
||||
proto = ud.parm.get('protocol', 'http')
|
||||
|
||||
|
||||
@@ -47,7 +47,18 @@ User credentials:
|
||||
"""
|
||||
# Copyright (C) 2014 Siemens AG
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# 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
|
||||
@@ -58,6 +69,7 @@ from bb.fetch2 import FetchMethod
|
||||
from bb.fetch2 import FetchError
|
||||
from bb.fetch2 import runfetchcmd
|
||||
from bb.fetch2 import logger
|
||||
from distutils import spawn
|
||||
|
||||
class ClearCase(FetchMethod):
|
||||
"""Class to fetch urls via 'clearcase'"""
|
||||
@@ -95,7 +107,7 @@ class ClearCase(FetchMethod):
|
||||
else:
|
||||
ud.module = ""
|
||||
|
||||
ud.basecmd = d.getVar("FETCHCMD_ccrc") or "/usr/bin/env cleartool || rcleartool"
|
||||
ud.basecmd = d.getVar("FETCHCMD_ccrc") or spawn.find_executable("cleartool") or spawn.find_executable("rcleartool")
|
||||
|
||||
if d.getVar("SRCREV") == "INVALID":
|
||||
raise FetchError("Set a valid SRCREV for the clearcase fetcher in your recipe, e.g. SRCREV = \"/main/LATEST\" or any other label of your choice.")
|
||||
|
||||
@@ -10,9 +10,20 @@ BitBake build tools.
|
||||
|
||||
# Copyright (C) 2003, 2004 Chris Larson
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# 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.
|
||||
#
|
||||
# Based on functions from the base bb module, Copyright 2003 Holger Schurig
|
||||
# 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
|
||||
@@ -99,7 +110,7 @@ class Cvs(FetchMethod):
|
||||
if ud.tag:
|
||||
options.append("-r %s" % ud.tag)
|
||||
|
||||
cvsbasecmd = d.getVar("FETCHCMD_cvs") or "/usr/bin/env cvs"
|
||||
cvsbasecmd = d.getVar("FETCHCMD_cvs")
|
||||
cvscmd = cvsbasecmd + " '-d" + cvsroot + "' co " + " ".join(options) + " " + ud.module
|
||||
cvsupdatecmd = cvsbasecmd + " '-d" + cvsroot + "' update -d -P " + " ".join(options)
|
||||
|
||||
@@ -110,8 +121,7 @@ class Cvs(FetchMethod):
|
||||
# create module directory
|
||||
logger.debug(2, "Fetch: checking for module directory")
|
||||
pkg = d.getVar('PN')
|
||||
cvsdir = d.getVar("CVSDIR") or (d.getVar("DL_DIR") + "/cvs")
|
||||
pkgdir = os.path.join(cvsdir, pkg)
|
||||
pkgdir = os.path.join(d.getVar('CVSDIR'), pkg)
|
||||
moddir = os.path.join(pkgdir, localdir)
|
||||
workdir = None
|
||||
if os.access(os.path.join(moddir, 'CVS'), os.R_OK):
|
||||
|
||||
@@ -55,10 +55,20 @@ Supported SRC_URI options are:
|
||||
|
||||
"""
|
||||
|
||||
# Copyright (C) 2005 Richard Purdie
|
||||
#Copyright (C) 2005 Richard Purdie
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# 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 collections
|
||||
import errno
|
||||
@@ -115,9 +125,6 @@ class GitProgressHandler(bb.progress.LineFilterProgressHandler):
|
||||
|
||||
|
||||
class Git(FetchMethod):
|
||||
bitbake_dir = os.path.abspath(os.path.join(os.path.dirname(os.path.join(os.path.abspath(__file__))), '..', '..', '..'))
|
||||
make_shallow_path = os.path.join(bitbake_dir, 'bin', 'git-make-shallow')
|
||||
|
||||
"""Class to fetch a module or modules from git repositories"""
|
||||
def init(self, d):
|
||||
pass
|
||||
@@ -189,7 +196,7 @@ class Git(FetchMethod):
|
||||
depth_default = 1
|
||||
ud.shallow_depths = collections.defaultdict(lambda: depth_default)
|
||||
|
||||
revs_default = d.getVar("BB_GIT_SHALLOW_REVS")
|
||||
revs_default = d.getVar("BB_GIT_SHALLOW_REVS", True)
|
||||
ud.shallow_revs = []
|
||||
ud.branches = {}
|
||||
for pos, name in enumerate(ud.names):
|
||||
@@ -251,7 +258,7 @@ class Git(FetchMethod):
|
||||
gitsrcname = gitsrcname + '_' + ud.revisions[name]
|
||||
|
||||
dl_dir = d.getVar("DL_DIR")
|
||||
gitdir = d.getVar("GITDIR") or (dl_dir + "/git2")
|
||||
gitdir = d.getVar("GITDIR") or (dl_dir + "/git2/")
|
||||
ud.clonedir = os.path.join(gitdir, gitsrcname)
|
||||
ud.localfile = ud.clonedir
|
||||
|
||||
@@ -289,26 +296,21 @@ class Git(FetchMethod):
|
||||
return ud.clonedir
|
||||
|
||||
def need_update(self, ud, d):
|
||||
return self.clonedir_need_update(ud, d) or self.shallow_tarball_need_update(ud) or self.tarball_need_update(ud)
|
||||
|
||||
def clonedir_need_update(self, ud, d):
|
||||
if not os.path.exists(ud.clonedir):
|
||||
return True
|
||||
for name in ud.names:
|
||||
if not self._contains_ref(ud, d, name, ud.clonedir):
|
||||
return True
|
||||
if ud.shallow and ud.write_shallow_tarballs and not os.path.exists(ud.fullshallow):
|
||||
return True
|
||||
if ud.write_tarballs and not os.path.exists(ud.fullmirror):
|
||||
return True
|
||||
return False
|
||||
|
||||
def shallow_tarball_need_update(self, ud):
|
||||
return ud.shallow and ud.write_shallow_tarballs and not os.path.exists(ud.fullshallow)
|
||||
|
||||
def tarball_need_update(self, ud):
|
||||
return ud.write_tarballs and not os.path.exists(ud.fullmirror)
|
||||
|
||||
def try_premirror(self, ud, d):
|
||||
# If we don't do this, updating an existing checkout with only premirrors
|
||||
# is not possible
|
||||
if bb.utils.to_boolean(d.getVar("BB_FETCH_PREMIRRORONLY")):
|
||||
if d.getVar("BB_FETCH_PREMIRRORONLY") is not None:
|
||||
return True
|
||||
if os.path.exists(ud.clonedir):
|
||||
return False
|
||||
@@ -317,13 +319,16 @@ class Git(FetchMethod):
|
||||
def download(self, ud, d):
|
||||
"""Fetch url"""
|
||||
|
||||
no_clone = not os.path.exists(ud.clonedir)
|
||||
need_update = no_clone or self.need_update(ud, d)
|
||||
|
||||
# A current clone is preferred to either tarball, a shallow tarball is
|
||||
# preferred to an out of date clone, and a missing clone will use
|
||||
# either tarball.
|
||||
if ud.shallow and os.path.exists(ud.fullshallow) and self.need_update(ud, d):
|
||||
if ud.shallow and os.path.exists(ud.fullshallow) and need_update:
|
||||
ud.localpath = ud.fullshallow
|
||||
return
|
||||
elif os.path.exists(ud.fullmirror) and not os.path.exists(ud.clonedir):
|
||||
elif os.path.exists(ud.fullmirror) and no_clone:
|
||||
bb.utils.mkdirhier(ud.clonedir)
|
||||
runfetchcmd("tar -xzf %s" % ud.fullmirror, d, workdir=ud.clonedir)
|
||||
|
||||
@@ -345,12 +350,11 @@ class Git(FetchMethod):
|
||||
for name in ud.names:
|
||||
if not self._contains_ref(ud, d, name, ud.clonedir):
|
||||
needupdate = True
|
||||
break
|
||||
|
||||
if needupdate:
|
||||
output = runfetchcmd("%s remote" % ud.basecmd, d, quiet=True, workdir=ud.clonedir)
|
||||
if "origin" in output:
|
||||
runfetchcmd("%s remote rm origin" % ud.basecmd, d, workdir=ud.clonedir)
|
||||
try:
|
||||
runfetchcmd("%s remote rm origin" % ud.basecmd, d, workdir=ud.clonedir)
|
||||
except bb.fetch2.FetchError:
|
||||
logger.debug(1, "No Origin")
|
||||
|
||||
runfetchcmd("%s remote add --mirror=fetch origin %s" % (ud.basecmd, repourl), d, workdir=ud.clonedir)
|
||||
fetch_cmd = "LANG=C %s fetch -f --prune --progress %s refs/*:refs/*" % (ud.basecmd, repourl)
|
||||
@@ -359,14 +363,12 @@ class Git(FetchMethod):
|
||||
progresshandler = GitProgressHandler(d)
|
||||
runfetchcmd(fetch_cmd, d, log=progresshandler, workdir=ud.clonedir)
|
||||
runfetchcmd("%s prune-packed" % ud.basecmd, d, workdir=ud.clonedir)
|
||||
runfetchcmd("%s pack-refs --all" % ud.basecmd, d, workdir=ud.clonedir)
|
||||
runfetchcmd("%s pack-redundant --all | xargs -r rm" % ud.basecmd, d, workdir=ud.clonedir)
|
||||
try:
|
||||
os.unlink(ud.fullmirror)
|
||||
except OSError as exc:
|
||||
if exc.errno != errno.ENOENT:
|
||||
raise
|
||||
|
||||
for name in ud.names:
|
||||
if not self._contains_ref(ud, d, name, ud.clonedir):
|
||||
raise bb.fetch2.FetchError("Unable to find revision %s in branch %s even from upstream" % (ud.revisions[name], ud.branches[name]))
|
||||
@@ -443,7 +445,7 @@ class Git(FetchMethod):
|
||||
shallow_branches.append(r)
|
||||
|
||||
# Make the repository shallow
|
||||
shallow_cmd = [self.make_shallow_path, '-s']
|
||||
shallow_cmd = ['git', 'make-shallow', '-s']
|
||||
for b in shallow_branches:
|
||||
shallow_cmd.append('-r')
|
||||
shallow_cmd.append(b)
|
||||
@@ -466,44 +468,14 @@ class Git(FetchMethod):
|
||||
if os.path.exists(destdir):
|
||||
bb.utils.prunedir(destdir)
|
||||
|
||||
source_found = False
|
||||
source_error = []
|
||||
|
||||
if not source_found:
|
||||
clonedir_is_up_to_date = not self.clonedir_need_update(ud, d)
|
||||
if clonedir_is_up_to_date:
|
||||
runfetchcmd("%s clone %s %s/ %s" % (ud.basecmd, ud.cloneflags, ud.clonedir, destdir), d)
|
||||
source_found = True
|
||||
else:
|
||||
source_error.append("clone directory not available or not up to date: " + ud.clonedir)
|
||||
|
||||
if not source_found:
|
||||
if ud.shallow:
|
||||
if os.path.exists(ud.fullshallow):
|
||||
bb.utils.mkdirhier(destdir)
|
||||
runfetchcmd("tar -xzf %s" % ud.fullshallow, d, workdir=destdir)
|
||||
source_found = True
|
||||
else:
|
||||
source_error.append("shallow clone not available: " + ud.fullshallow)
|
||||
else:
|
||||
source_error.append("shallow clone not enabled")
|
||||
|
||||
if not source_found:
|
||||
raise bb.fetch2.UnpackError("No up to date source found: " + "; ".join(source_error), ud.url)
|
||||
if ud.shallow and (not os.path.exists(ud.clonedir) or self.need_update(ud, d)):
|
||||
bb.utils.mkdirhier(destdir)
|
||||
runfetchcmd("tar -xzf %s" % ud.fullshallow, d, workdir=destdir)
|
||||
else:
|
||||
runfetchcmd("%s clone %s %s/ %s" % (ud.basecmd, ud.cloneflags, ud.clonedir, destdir), d)
|
||||
|
||||
repourl = self._get_repo_url(ud)
|
||||
runfetchcmd("%s remote set-url origin %s" % (ud.basecmd, repourl), d, workdir=destdir)
|
||||
|
||||
if self._contains_lfs(ud, d, destdir):
|
||||
path = d.getVar('PATH')
|
||||
if path:
|
||||
gitlfstool = bb.utils.which(path, "git-lfs", executable=True)
|
||||
if not gitlfstool:
|
||||
raise bb.fetch2.FetchError("Repository %s has lfs content, install git-lfs plugin on host to download" % (repourl))
|
||||
else:
|
||||
bb.note("Could not find 'PATH'")
|
||||
|
||||
|
||||
if not ud.nocheckout:
|
||||
if subdir != "":
|
||||
runfetchcmd("%s read-tree %s%s" % (ud.basecmd, ud.revisions[ud.names[0]], readpathspec), d,
|
||||
@@ -523,17 +495,9 @@ class Git(FetchMethod):
|
||||
def clean(self, ud, d):
|
||||
""" clean the git directory """
|
||||
|
||||
to_remove = [ud.localpath, ud.fullmirror, ud.fullmirror + ".done"]
|
||||
# The localpath is a symlink to clonedir when it is cloned from a
|
||||
# mirror, so remove both of them.
|
||||
if os.path.islink(ud.localpath):
|
||||
clonedir = os.path.realpath(ud.localpath)
|
||||
to_remove.append(clonedir)
|
||||
|
||||
for r in to_remove:
|
||||
if os.path.exists(r):
|
||||
bb.note('Removing %s' % r)
|
||||
bb.utils.remove(r, True)
|
||||
bb.utils.remove(ud.localpath, True)
|
||||
bb.utils.remove(ud.fullmirror)
|
||||
bb.utils.remove(ud.fullmirror + ".done")
|
||||
|
||||
def supports_srcrev(self):
|
||||
return True
|
||||
@@ -554,20 +518,6 @@ class Git(FetchMethod):
|
||||
raise bb.fetch2.FetchError("The command '%s' gave output with more then 1 line unexpectedly, output: '%s'" % (cmd, output))
|
||||
return output.split()[0] != "0"
|
||||
|
||||
def _contains_lfs(self, ud, d, wd):
|
||||
"""
|
||||
Check if the repository has 'lfs' (large file) content
|
||||
"""
|
||||
cmd = "%s grep lfs HEAD:.gitattributes | wc -l" % (
|
||||
ud.basecmd)
|
||||
try:
|
||||
output = runfetchcmd(cmd, d, quiet=True, workdir=wd)
|
||||
if int(output) > 0:
|
||||
return True
|
||||
except (bb.fetch2.FetchError,ValueError):
|
||||
pass
|
||||
return False
|
||||
|
||||
def _get_repo_url(self, ud):
|
||||
"""
|
||||
Return the repository URL
|
||||
@@ -638,11 +588,10 @@ class Git(FetchMethod):
|
||||
"""
|
||||
pupver = ('', '')
|
||||
|
||||
tagregex = re.compile(d.getVar('UPSTREAM_CHECK_GITTAGREGEX') or r"(?P<pver>([0-9][\.|_]?)+)")
|
||||
tagregex = re.compile(d.getVar('UPSTREAM_CHECK_GITTAGREGEX') or "(?P<pver>([0-9][\.|_]?)+)")
|
||||
try:
|
||||
output = self._lsremote(ud, d, "refs/tags/*")
|
||||
except (bb.fetch2.FetchError, bb.fetch2.NetworkAccess) as e:
|
||||
bb.note("Could not list remote: %s" % str(e))
|
||||
except bb.fetch2.FetchError or bb.fetch2.NetworkAccess:
|
||||
return pupver
|
||||
|
||||
verstring = ""
|
||||
@@ -653,7 +602,7 @@ class Git(FetchMethod):
|
||||
|
||||
tag_head = line.split("/")[-1]
|
||||
# Ignore non-released branches
|
||||
m = re.search(r"(alpha|beta|rc|final)+", tag_head)
|
||||
m = re.search("(alpha|beta|rc|final)+", tag_head)
|
||||
if m:
|
||||
continue
|
||||
|
||||
|
||||
@@ -7,8 +7,18 @@ BitBake 'Fetch' git annex implementation
|
||||
# Copyright (C) 2014 Otavio Salvador
|
||||
# Copyright (C) 2014 O.S. Systems Software LTDA.
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# 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
|
||||
|
||||
@@ -16,17 +16,24 @@ NOTE: Switching a SRC_URI from "git://" to "gitsm://" requires a clean of your r
|
||||
|
||||
# Copyright (C) 2013 Richard Purdie
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# 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
|
||||
import copy
|
||||
from bb.fetch2.git import Git
|
||||
from bb.fetch2 import runfetchcmd
|
||||
from bb.fetch2 import logger
|
||||
from bb.fetch2 import Fetch
|
||||
from bb.fetch2 import BBFetchException
|
||||
|
||||
class GitSM(Git):
|
||||
def supports(self, ud, d):
|
||||
@@ -35,183 +42,94 @@ class GitSM(Git):
|
||||
"""
|
||||
return ud.type in ['gitsm']
|
||||
|
||||
def process_submodules(self, ud, workdir, function, d):
|
||||
"""
|
||||
Iterate over all of the submodules in this repository and execute
|
||||
the 'function' for each of them.
|
||||
"""
|
||||
|
||||
submodules = []
|
||||
paths = {}
|
||||
revision = {}
|
||||
uris = {}
|
||||
subrevision = {}
|
||||
|
||||
def parse_gitmodules(gitmodules):
|
||||
modules = {}
|
||||
module = ""
|
||||
for line in gitmodules.splitlines():
|
||||
if line.startswith('[submodule'):
|
||||
module = line.split('"')[1]
|
||||
modules[module] = {}
|
||||
elif module and line.strip().startswith('path'):
|
||||
path = line.split('=')[1].strip()
|
||||
modules[module]['path'] = path
|
||||
elif module and line.strip().startswith('url'):
|
||||
url = line.split('=')[1].strip()
|
||||
modules[module]['url'] = url
|
||||
return modules
|
||||
|
||||
# Collect the defined submodules, and their attributes
|
||||
def uses_submodules(self, ud, d, wd):
|
||||
for name in ud.names:
|
||||
try:
|
||||
gitmodules = runfetchcmd("%s show %s:.gitmodules" % (ud.basecmd, ud.revisions[name]), d, quiet=True, workdir=workdir)
|
||||
except:
|
||||
# No submodules to update
|
||||
continue
|
||||
|
||||
for m, md in parse_gitmodules(gitmodules).items():
|
||||
try:
|
||||
module_hash = runfetchcmd("%s ls-tree -z -d %s %s" % (ud.basecmd, ud.revisions[name], md['path']), d, quiet=True, workdir=workdir)
|
||||
except:
|
||||
# If the command fails, we don't have a valid file to check. If it doesn't
|
||||
# fail -- it still might be a failure, see next check...
|
||||
module_hash = ""
|
||||
|
||||
if not module_hash:
|
||||
logger.debug(1, "submodule %s is defined, but is not initialized in the repository. Skipping", m)
|
||||
continue
|
||||
|
||||
submodules.append(m)
|
||||
paths[m] = md['path']
|
||||
revision[m] = ud.revisions[name]
|
||||
uris[m] = md['url']
|
||||
subrevision[m] = module_hash.split()[2]
|
||||
|
||||
# Convert relative to absolute uri based on parent uri
|
||||
if uris[m].startswith('..'):
|
||||
newud = copy.copy(ud)
|
||||
newud.path = os.path.realpath(os.path.join(newud.path, uris[m]))
|
||||
uris[m] = Git._get_repo_url(self, newud)
|
||||
|
||||
for module in submodules:
|
||||
# Translate the module url into a SRC_URI
|
||||
|
||||
if "://" in uris[module]:
|
||||
# Properly formated URL already
|
||||
proto = uris[module].split(':', 1)[0]
|
||||
url = uris[module].replace('%s:' % proto, 'gitsm:', 1)
|
||||
else:
|
||||
if ":" in uris[module]:
|
||||
# Most likely an SSH style reference
|
||||
proto = "ssh"
|
||||
if ":/" in uris[module]:
|
||||
# Absolute reference, easy to convert..
|
||||
url = "gitsm://" + uris[module].replace(':/', '/', 1)
|
||||
else:
|
||||
# Relative reference, no way to know if this is right!
|
||||
logger.warning("Submodule included by %s refers to relative ssh reference %s. References may fail if not absolute." % (ud.url, uris[module]))
|
||||
url = "gitsm://" + uris[module].replace(':', '/', 1)
|
||||
else:
|
||||
# This has to be a file reference
|
||||
proto = "file"
|
||||
url = "gitsm://" + uris[module]
|
||||
|
||||
url += ';protocol=%s' % proto
|
||||
url += ";name=%s" % module
|
||||
url += ";subpath=%s" % module
|
||||
|
||||
ld = d.createCopy()
|
||||
# Not necessary to set SRC_URI, since we're passing the URI to
|
||||
# Fetch.
|
||||
#ld.setVar('SRC_URI', url)
|
||||
ld.setVar('SRCREV_%s' % module, subrevision[module])
|
||||
|
||||
# Workaround for issues with SRCPV/SRCREV_FORMAT errors
|
||||
# error refer to 'multiple' repositories. Only the repository
|
||||
# in the original SRC_URI actually matters...
|
||||
ld.setVar('SRCPV', d.getVar('SRCPV'))
|
||||
ld.setVar('SRCREV_FORMAT', module)
|
||||
|
||||
function(ud, url, module, paths[module], ld)
|
||||
|
||||
return submodules != []
|
||||
|
||||
def need_update(self, ud, d):
|
||||
if Git.need_update(self, ud, d):
|
||||
return True
|
||||
|
||||
try:
|
||||
# Check for the nugget dropped by the download operation
|
||||
known_srcrevs = runfetchcmd("%s config --get-all bitbake.srcrev" % \
|
||||
(ud.basecmd), d, workdir=ud.clonedir)
|
||||
|
||||
if ud.revisions[ud.names[0]] not in known_srcrevs.split():
|
||||
runfetchcmd("%s show %s:.gitmodules" % (ud.basecmd, ud.revisions[name]), d, quiet=True, workdir=wd)
|
||||
return True
|
||||
except bb.fetch2.FetchError:
|
||||
# No srcrev nuggets, so this is new and needs to be updated
|
||||
return True
|
||||
|
||||
except bb.fetch.FetchError:
|
||||
pass
|
||||
return False
|
||||
|
||||
def _set_relative_paths(self, repopath):
|
||||
"""
|
||||
Fix submodule paths to be relative instead of absolute,
|
||||
so that when we move the repo it doesn't break
|
||||
(In Git 1.7.10+ this is done automatically)
|
||||
"""
|
||||
submodules = []
|
||||
with open(os.path.join(repopath, '.gitmodules'), 'r') as f:
|
||||
for line in f.readlines():
|
||||
if line.startswith('[submodule'):
|
||||
submodules.append(line.split('"')[1])
|
||||
|
||||
for module in submodules:
|
||||
repo_conf = os.path.join(repopath, module, '.git')
|
||||
if os.path.exists(repo_conf):
|
||||
with open(repo_conf, 'r') as f:
|
||||
lines = f.readlines()
|
||||
newpath = ''
|
||||
for i, line in enumerate(lines):
|
||||
if line.startswith('gitdir:'):
|
||||
oldpath = line.split(': ')[-1].rstrip()
|
||||
if oldpath.startswith('/'):
|
||||
newpath = '../' * (module.count('/') + 1) + '.git/modules/' + module
|
||||
lines[i] = 'gitdir: %s\n' % newpath
|
||||
break
|
||||
if newpath:
|
||||
with open(repo_conf, 'w') as f:
|
||||
for line in lines:
|
||||
f.write(line)
|
||||
|
||||
repo_conf2 = os.path.join(repopath, '.git', 'modules', module, 'config')
|
||||
if os.path.exists(repo_conf2):
|
||||
with open(repo_conf2, 'r') as f:
|
||||
lines = f.readlines()
|
||||
newpath = ''
|
||||
for i, line in enumerate(lines):
|
||||
if line.lstrip().startswith('worktree = '):
|
||||
oldpath = line.split(' = ')[-1].rstrip()
|
||||
if oldpath.startswith('/'):
|
||||
newpath = '../' * (module.count('/') + 3) + module
|
||||
lines[i] = '\tworktree = %s\n' % newpath
|
||||
break
|
||||
if newpath:
|
||||
with open(repo_conf2, 'w') as f:
|
||||
for line in lines:
|
||||
f.write(line)
|
||||
|
||||
def update_submodules(self, 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)
|
||||
runfetchcmd(ud.basecmd + " reset --hard", d, workdir=tmpclonedir)
|
||||
runfetchcmd(ud.basecmd + " checkout -f " + ud.revisions[ud.names[0]], d, workdir=tmpclonedir)
|
||||
runfetchcmd(ud.basecmd + " submodule update --init --recursive", d, workdir=tmpclonedir)
|
||||
self._set_relative_paths(tmpclonedir)
|
||||
runfetchcmd("sed " + gitdir + "/config -i -e 's/bare.*=.*false/bare = true/'", d, workdir=tmpclonedir)
|
||||
os.rename(gitdir, ud.clonedir,)
|
||||
bb.utils.remove(tmpclonedir, True)
|
||||
|
||||
def download(self, ud, d):
|
||||
def download_submodule(ud, url, module, modpath, d):
|
||||
url += ";bareclone=1;nobranch=1"
|
||||
|
||||
# Is the following still needed?
|
||||
#url += ";nocheckout=1"
|
||||
|
||||
try:
|
||||
newfetch = Fetch([url], d, cache=False)
|
||||
newfetch.download()
|
||||
# Drop a nugget to add each of the srcrevs we've fetched (used by need_update)
|
||||
runfetchcmd("%s config --add bitbake.srcrev %s" % \
|
||||
(ud.basecmd, ud.revisions[ud.names[0]]), d, workdir=ud.clonedir)
|
||||
except Exception as e:
|
||||
logger.error('gitsm: submodule download failed: %s %s' % (type(e).__name__, str(e)))
|
||||
raise
|
||||
|
||||
Git.download(self, ud, d)
|
||||
self.process_submodules(ud, ud.clonedir, download_submodule, d)
|
||||
|
||||
if not ud.shallow or ud.localpath != ud.fullshallow:
|
||||
submodules = self.uses_submodules(ud, d, ud.clonedir)
|
||||
if submodules:
|
||||
self.update_submodules(ud, d)
|
||||
|
||||
def clone_shallow_local(self, ud, dest, d):
|
||||
super(GitSM, self).clone_shallow_local(ud, dest, d)
|
||||
|
||||
runfetchcmd('cp -fpPRH "%s/modules" "%s/"' % (ud.clonedir, os.path.join(dest, '.git')), d)
|
||||
|
||||
def unpack(self, ud, destdir, d):
|
||||
def unpack_submodules(ud, url, module, modpath, d):
|
||||
url += ";bareclone=1;nobranch=1"
|
||||
|
||||
# Figure out where we clone over the bare submodules...
|
||||
if ud.bareclone:
|
||||
repo_conf = ud.destdir
|
||||
else:
|
||||
repo_conf = os.path.join(ud.destdir, '.git')
|
||||
|
||||
try:
|
||||
newfetch = Fetch([url], d, cache=False)
|
||||
newfetch.unpack(root=os.path.dirname(os.path.join(repo_conf, 'modules', module)))
|
||||
except Exception as e:
|
||||
logger.error('gitsm: submodule unpack failed: %s %s' % (type(e).__name__, str(e)))
|
||||
raise
|
||||
|
||||
local_path = newfetch.localpath(url)
|
||||
|
||||
# Correct the submodule references to the local download version...
|
||||
runfetchcmd("%(basecmd)s config submodule.%(module)s.url %(url)s" % {'basecmd': ud.basecmd, 'module': module, 'url' : local_path}, d, workdir=ud.destdir)
|
||||
|
||||
if ud.shallow:
|
||||
runfetchcmd("%(basecmd)s config submodule.%(module)s.shallow true" % {'basecmd': ud.basecmd, 'module': module}, d, workdir=ud.destdir)
|
||||
|
||||
# Ensure the submodule repository is NOT set to bare, since we're checking it out...
|
||||
try:
|
||||
runfetchcmd("%s config core.bare false" % (ud.basecmd), d, quiet=True, workdir=os.path.join(repo_conf, 'modules', module))
|
||||
except:
|
||||
logger.error("Unable to set git config core.bare to false for %s" % os.path.join(repo_conf, 'modules', module))
|
||||
raise
|
||||
|
||||
Git.unpack(self, ud, destdir, d)
|
||||
|
||||
ret = self.process_submodules(ud, ud.destdir, unpack_submodules, d)
|
||||
|
||||
if not ud.bareclone and ret:
|
||||
# All submodules should already be downloaded and configured in the tree. This simply sets
|
||||
# up the configuration and checks out the files. The main project config should remain
|
||||
# unmodified, and no download from the internet should occur.
|
||||
runfetchcmd("%s submodule update --recursive --no-fetch" % (ud.basecmd), d, quiet=True, workdir=ud.destdir)
|
||||
if self.uses_submodules(ud, d, ud.destdir):
|
||||
runfetchcmd(ud.basecmd + " checkout " + ud.revisions[ud.names[0]], d, workdir=ud.destdir)
|
||||
runfetchcmd(ud.basecmd + " submodule update --init --recursive", d, workdir=ud.destdir)
|
||||
|
||||
@@ -9,10 +9,20 @@ BitBake 'Fetch' implementation for mercurial DRCS (hg).
|
||||
# Copyright (C) 2004 Marcin Juszkiewicz
|
||||
# Copyright (C) 2007 Robert Schuster
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License version 2 as
|
||||
# published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
# Based on functions from the base bb module, Copyright 2003 Holger Schurig
|
||||
#
|
||||
|
||||
import os
|
||||
import sys
|
||||
@@ -70,7 +80,7 @@ class Hg(FetchMethod):
|
||||
ud.fullmirror = os.path.join(d.getVar("DL_DIR"), mirrortarball)
|
||||
ud.mirrortarballs = [mirrortarball]
|
||||
|
||||
hgdir = d.getVar("HGDIR") or (d.getVar("DL_DIR") + "/hg")
|
||||
hgdir = d.getVar("HGDIR") or (d.getVar("DL_DIR") + "/hg/")
|
||||
ud.pkgdir = os.path.join(hgdir, hgsrcname)
|
||||
ud.moddir = os.path.join(ud.pkgdir, ud.module)
|
||||
ud.localfile = ud.moddir
|
||||
@@ -89,7 +99,7 @@ class Hg(FetchMethod):
|
||||
def try_premirror(self, ud, d):
|
||||
# If we don't do this, updating an existing checkout with only premirrors
|
||||
# is not possible
|
||||
if bb.utils.to_boolean(d.getVar("BB_FETCH_PREMIRRORONLY")):
|
||||
if d.getVar("BB_FETCH_PREMIRRORONLY") is not None:
|
||||
return True
|
||||
if os.path.exists(ud.moddir):
|
||||
return False
|
||||
|
||||
@@ -10,10 +10,20 @@ BitBake build tools.
|
||||
|
||||
# Copyright (C) 2003, 2004 Chris Larson
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# 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 urllib.request, urllib.parse, urllib.error
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
#
|
||||
# ex:ts=4:sw=4:sts=4:et
|
||||
# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
|
||||
"""
|
||||
@@ -35,6 +32,7 @@ from bb.fetch2 import runfetchcmd
|
||||
from bb.fetch2 import logger
|
||||
from bb.fetch2 import UnpackError
|
||||
from bb.fetch2 import ParameterError
|
||||
from distutils import spawn
|
||||
|
||||
def subprocess_setup():
|
||||
# Python installs a SIGPIPE handler by default. This is usually not what
|
||||
@@ -197,11 +195,9 @@ class Npm(FetchMethod):
|
||||
outputurl = pdata['dist']['tarball']
|
||||
data[pkg] = {}
|
||||
data[pkg]['tgz'] = os.path.basename(outputurl)
|
||||
if outputurl in fetchedlist:
|
||||
return
|
||||
|
||||
self._runwget(ud, d, "%s --directory-prefix=%s %s" % (self.basecmd, ud.prefixdir, outputurl), False)
|
||||
fetchedlist.append(outputurl)
|
||||
if not outputurl in fetchedlist:
|
||||
self._runwget(ud, d, "%s --directory-prefix=%s %s" % (self.basecmd, ud.prefixdir, outputurl), False)
|
||||
fetchedlist.append(outputurl)
|
||||
|
||||
dependencies = pdata.get('dependencies', {})
|
||||
optionalDependencies = pdata.get('optionalDependencies', {})
|
||||
@@ -229,7 +225,7 @@ class Npm(FetchMethod):
|
||||
self._getshrinkeddependencies(obj, data['dependencies'][obj], data['dependencies'][obj]['version'], d, ud, lockdown, manifest, False)
|
||||
return
|
||||
outputurl = "invalid"
|
||||
if ('resolved' not in data) or (not data['resolved'].startswith('http://') and not data['resolved'].startswith('https://')):
|
||||
if ('resolved' not in data) or (not data['resolved'].startswith('http')):
|
||||
# will be the case for ${PN}
|
||||
fetchcmd = "npm view %s@%s dist.tarball --registry %s" % (pkg, version, ud.registry)
|
||||
logger.debug(2, "Found this matching URL: %s" % str(fetchcmd))
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
#
|
||||
# ex:ts=4:sw=4:sts=4:et
|
||||
# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
|
||||
"""
|
||||
@@ -35,9 +32,8 @@ class Osc(FetchMethod):
|
||||
ud.module = ud.parm["module"]
|
||||
|
||||
# Create paths to osc checkouts
|
||||
oscdir = d.getVar("OSCDIR") or (d.getVar("DL_DIR") + "/osc")
|
||||
relpath = self._strip_leading_slashes(ud.path)
|
||||
ud.pkgdir = os.path.join(oscdir, ud.host)
|
||||
ud.pkgdir = os.path.join(d.getVar('OSCDIR'), ud.host)
|
||||
ud.moddir = os.path.join(ud.pkgdir, relpath, ud.module)
|
||||
|
||||
if 'rev' in ud.parm:
|
||||
@@ -58,7 +54,7 @@ class Osc(FetchMethod):
|
||||
command is "fetch", "update", "info"
|
||||
"""
|
||||
|
||||
basecmd = d.getVar("FETCHCMD_osc") or "/usr/bin/env osc"
|
||||
basecmd = d.expand('${FETCHCMD_osc}')
|
||||
|
||||
proto = ud.parm.get('protocol', 'ocs')
|
||||
|
||||
|
||||
@@ -8,7 +8,18 @@ BitBake 'Fetch' implementation for perforce
|
||||
# Copyright (C) 2003, 2004 Chris Larson
|
||||
# Copyright (C) 2016 Kodak Alaris, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# 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
|
||||
|
||||
@@ -32,9 +43,13 @@ class Perforce(FetchMethod):
|
||||
provided by the env, use it. If P4PORT is specified by the recipe, use
|
||||
its values, which may override the settings in P4CONFIG.
|
||||
"""
|
||||
ud.basecmd = d.getVar("FETCHCMD_p4") or "/usr/bin/env p4"
|
||||
ud.basecmd = d.getVar('FETCHCMD_p4')
|
||||
if not ud.basecmd:
|
||||
ud.basecmd = "/usr/bin/env p4"
|
||||
|
||||
ud.dldir = d.getVar("P4DIR") or (d.getVar("DL_DIR") + "/p4")
|
||||
ud.dldir = d.getVar('P4DIR')
|
||||
if not ud.dldir:
|
||||
ud.dldir = '%s/%s' % (d.getVar('DL_DIR'), 'p4')
|
||||
|
||||
path = ud.url.split('://')[1]
|
||||
path = path.split(';')[0]
|
||||
|
||||
@@ -8,10 +8,20 @@ BitBake "Fetch" repo (git) implementation
|
||||
# Copyright (C) 2009 Tom Rini <trini@embeddedalley.com>
|
||||
#
|
||||
# Based on git.py which is:
|
||||
# Copyright (C) 2005 Richard Purdie
|
||||
#Copyright (C) 2005 Richard Purdie
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# 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
|
||||
@@ -35,8 +45,6 @@ class Repo(FetchMethod):
|
||||
"master".
|
||||
"""
|
||||
|
||||
ud.basecmd = d.getVar("FETCHCMD_repo") or "/usr/bin/env repo"
|
||||
|
||||
ud.proto = ud.parm.get('protocol', 'git')
|
||||
ud.branch = ud.parm.get('branch', 'master')
|
||||
ud.manifest = ud.parm.get('manifest', 'default.xml')
|
||||
@@ -52,8 +60,8 @@ class Repo(FetchMethod):
|
||||
logger.debug(1, "%s already exists (or was stashed). Skipping repo init / sync.", ud.localpath)
|
||||
return
|
||||
|
||||
repodir = d.getVar("REPODIR") or (d.getVar("DL_DIR") + "/repo")
|
||||
gitsrcname = "%s%s" % (ud.host, ud.path.replace("/", "."))
|
||||
repodir = d.getVar("REPODIR") or os.path.join(d.getVar("DL_DIR"), "repo")
|
||||
codir = os.path.join(repodir, gitsrcname, ud.manifest)
|
||||
|
||||
if ud.user:
|
||||
@@ -64,11 +72,11 @@ class Repo(FetchMethod):
|
||||
repodir = os.path.join(codir, "repo")
|
||||
bb.utils.mkdirhier(repodir)
|
||||
if not os.path.exists(os.path.join(repodir, ".repo")):
|
||||
bb.fetch2.check_network_access(d, "%s init -m %s -b %s -u %s://%s%s%s" % (ud.basecmd, ud.manifest, ud.branch, ud.proto, username, ud.host, ud.path), ud.url)
|
||||
runfetchcmd("%s init -m %s -b %s -u %s://%s%s%s" % (ud.basecmd, ud.manifest, ud.branch, ud.proto, username, ud.host, ud.path), d, workdir=repodir)
|
||||
bb.fetch2.check_network_access(d, "repo init -m %s -b %s -u %s://%s%s%s" % (ud.manifest, ud.branch, ud.proto, username, ud.host, ud.path), ud.url)
|
||||
runfetchcmd("repo init -m %s -b %s -u %s://%s%s%s" % (ud.manifest, ud.branch, ud.proto, username, ud.host, ud.path), d, workdir=repodir)
|
||||
|
||||
bb.fetch2.check_network_access(d, "%s sync %s" % (ud.basecmd, ud.url), ud.url)
|
||||
runfetchcmd("%s sync" % ud.basecmd, d, workdir=repodir)
|
||||
bb.fetch2.check_network_access(d, "repo sync %s" % ud.url, ud.url)
|
||||
runfetchcmd("repo sync", d, workdir=repodir)
|
||||
|
||||
scmdata = ud.parm.get("scmdata", "")
|
||||
if scmdata == "keep":
|
||||
|
||||
@@ -13,7 +13,18 @@ The aws tool must be correctly installed and configured prior to use.
|
||||
# Based in part on bb.fetch2.wget:
|
||||
# Copyright (C) 2003, 2004 Chris Larson
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# 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
|
||||
|
||||
|
||||
@@ -44,7 +44,18 @@ SRC_URI = "sftp://user@host.example.com/dir/path.file.txt"
|
||||
# Based in part on bb.fetch2.wget:
|
||||
# Copyright (C) 2003, 2004 Chris Larson
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# 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
|
||||
|
||||
|
||||
@@ -29,8 +29,18 @@ IETF secsh internet draft:
|
||||
# Copyright 2003 Holger Schurig
|
||||
#
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License version 2 as
|
||||
# published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
import re, os
|
||||
from bb.fetch2 import FetchMethod
|
||||
|
||||
@@ -8,7 +8,18 @@ BitBake 'Fetch' implementation for svn.
|
||||
# Copyright (C) 2003, 2004 Chris Larson
|
||||
# Copyright (C) 2004 Marcin Juszkiewicz
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# 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
|
||||
|
||||
@@ -38,7 +49,7 @@ class Svn(FetchMethod):
|
||||
if not "module" in ud.parm:
|
||||
raise MissingParameterError('module', ud.url)
|
||||
|
||||
ud.basecmd = d.getVar("FETCHCMD_svn") or "/usr/bin/env svn --non-interactive --trust-server-cert"
|
||||
ud.basecmd = d.getVar('FETCHCMD_svn')
|
||||
|
||||
ud.module = ud.parm["module"]
|
||||
|
||||
@@ -48,13 +59,9 @@ class Svn(FetchMethod):
|
||||
ud.path_spec = ud.parm["path_spec"]
|
||||
|
||||
# Create paths to svn checkouts
|
||||
svndir = d.getVar("SVNDIR") or (d.getVar("DL_DIR") + "/svn")
|
||||
relpath = self._strip_leading_slashes(ud.path)
|
||||
ud.pkgdir = os.path.join(svndir, ud.host, relpath)
|
||||
ud.pkgdir = os.path.join(d.expand('${SVNDIR}'), ud.host, relpath)
|
||||
ud.moddir = os.path.join(ud.pkgdir, ud.module)
|
||||
# Protects the repository from concurrent updates, e.g. from two
|
||||
# recipes fetching different revisions at the same time
|
||||
ud.svnlock = os.path.join(ud.pkgdir, "svn.lock")
|
||||
|
||||
ud.setup_revisions(d)
|
||||
|
||||
@@ -115,40 +122,35 @@ class Svn(FetchMethod):
|
||||
|
||||
logger.debug(2, "Fetch: checking for module directory '" + ud.moddir + "'")
|
||||
|
||||
lf = bb.utils.lockfile(ud.svnlock)
|
||||
if os.access(os.path.join(ud.moddir, '.svn'), os.R_OK):
|
||||
svnupdatecmd = self._buildsvncommand(ud, d, "update")
|
||||
logger.info("Update " + ud.url)
|
||||
# We need to attempt to run svn upgrade first in case its an older working format
|
||||
try:
|
||||
runfetchcmd(ud.basecmd + " upgrade", d, workdir=ud.moddir)
|
||||
except FetchError:
|
||||
pass
|
||||
logger.debug(1, "Running %s", svnupdatecmd)
|
||||
bb.fetch2.check_network_access(d, svnupdatecmd, ud.url)
|
||||
runfetchcmd(svnupdatecmd, d, workdir=ud.moddir)
|
||||
else:
|
||||
svnfetchcmd = self._buildsvncommand(ud, d, "fetch")
|
||||
logger.info("Fetch " + ud.url)
|
||||
# check out sources there
|
||||
bb.utils.mkdirhier(ud.pkgdir)
|
||||
logger.debug(1, "Running %s", svnfetchcmd)
|
||||
bb.fetch2.check_network_access(d, svnfetchcmd, ud.url)
|
||||
runfetchcmd(svnfetchcmd, d, workdir=ud.pkgdir)
|
||||
|
||||
try:
|
||||
if os.access(os.path.join(ud.moddir, '.svn'), os.R_OK):
|
||||
svnupdatecmd = self._buildsvncommand(ud, d, "update")
|
||||
logger.info("Update " + ud.url)
|
||||
# We need to attempt to run svn upgrade first in case its an older working format
|
||||
try:
|
||||
runfetchcmd(ud.basecmd + " upgrade", d, workdir=ud.moddir)
|
||||
except FetchError:
|
||||
pass
|
||||
logger.debug(1, "Running %s", svnupdatecmd)
|
||||
bb.fetch2.check_network_access(d, svnupdatecmd, ud.url)
|
||||
runfetchcmd(svnupdatecmd, d, workdir=ud.moddir)
|
||||
else:
|
||||
svnfetchcmd = self._buildsvncommand(ud, d, "fetch")
|
||||
logger.info("Fetch " + ud.url)
|
||||
# check out sources there
|
||||
bb.utils.mkdirhier(ud.pkgdir)
|
||||
logger.debug(1, "Running %s", svnfetchcmd)
|
||||
bb.fetch2.check_network_access(d, svnfetchcmd, ud.url)
|
||||
runfetchcmd(svnfetchcmd, d, workdir=ud.pkgdir)
|
||||
scmdata = ud.parm.get("scmdata", "")
|
||||
if scmdata == "keep":
|
||||
tar_flags = ""
|
||||
else:
|
||||
tar_flags = "--exclude='.svn'"
|
||||
|
||||
scmdata = ud.parm.get("scmdata", "")
|
||||
if scmdata == "keep":
|
||||
tar_flags = ""
|
||||
else:
|
||||
tar_flags = "--exclude='.svn'"
|
||||
|
||||
# tar them up to a defined filename
|
||||
runfetchcmd("tar %s -czf %s %s" % (tar_flags, ud.localpath, ud.path_spec), d,
|
||||
cleanup=[ud.localpath], workdir=ud.pkgdir)
|
||||
finally:
|
||||
bb.utils.unlockfile(lf)
|
||||
# tar them up to a defined filename
|
||||
runfetchcmd("tar %s -czf %s %s" % (tar_flags, ud.localpath, ud.path_spec), d,
|
||||
cleanup=[ud.localpath], workdir=ud.pkgdir)
|
||||
|
||||
def clean(self, ud, d):
|
||||
""" Clean SVN specific files and dirs """
|
||||
|
||||
@@ -10,7 +10,18 @@ BitBake build tools.
|
||||
|
||||
# Copyright (C) 2003, 2004 Chris Larson
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# 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
|
||||
|
||||
@@ -22,14 +33,11 @@ import logging
|
||||
import errno
|
||||
import bb
|
||||
import bb.progress
|
||||
import socket
|
||||
import http.client
|
||||
import urllib.request, urllib.parse, urllib.error
|
||||
from bb.fetch2 import FetchMethod
|
||||
from bb.fetch2 import FetchError
|
||||
from bb.fetch2 import logger
|
||||
from bb.fetch2 import runfetchcmd
|
||||
from bb.fetch2 import FetchConnectionCache
|
||||
from bb.utils import export_proxies
|
||||
from bs4 import BeautifulSoup
|
||||
from bs4 import SoupStrainer
|
||||
@@ -124,6 +132,10 @@ class Wget(FetchMethod):
|
||||
return True
|
||||
|
||||
def checkstatus(self, fetch, ud, d, try_again=True):
|
||||
import urllib.request, urllib.error, urllib.parse, socket, http.client
|
||||
from urllib.response import addinfourl
|
||||
from bb.fetch2 import FetchConnectionCache
|
||||
|
||||
class HTTPConnectionCache(http.client.HTTPConnection):
|
||||
if fetch.connection_cache:
|
||||
def connect(self):
|
||||
@@ -156,7 +168,7 @@ class Wget(FetchMethod):
|
||||
"""
|
||||
host = req.host
|
||||
if not host:
|
||||
raise urllib.error.URLError('no host given')
|
||||
raise urlllib2.URLError('no host given')
|
||||
|
||||
h = http_class(host, timeout=req.timeout) # will parse host:port
|
||||
h.set_debuglevel(self._debuglevel)
|
||||
@@ -173,7 +185,7 @@ class Wget(FetchMethod):
|
||||
# request.
|
||||
|
||||
# Don't close connection when connection_cache is enabled,
|
||||
if fetch.connection_cache is None:
|
||||
if fetch.connection_cache is None:
|
||||
headers["Connection"] = "close"
|
||||
else:
|
||||
headers["Connection"] = "Keep-Alive" # Works for HTTP/1.0
|
||||
@@ -238,9 +250,8 @@ class Wget(FetchMethod):
|
||||
return ""
|
||||
def close(self):
|
||||
pass
|
||||
closed = False
|
||||
|
||||
resp = urllib.response.addinfourl(fp_dummy(), r.msg, req.get_full_url())
|
||||
resp = addinfourl(fp_dummy(), r.msg, req.get_full_url())
|
||||
resp.code = r.status
|
||||
resp.msg = r.reason
|
||||
|
||||
@@ -259,16 +270,17 @@ class Wget(FetchMethod):
|
||||
fp.read()
|
||||
fp.close()
|
||||
|
||||
newheaders = dict((k, v) for k, v in list(req.headers.items())
|
||||
newheaders = dict((k,v) for k,v in list(req.headers.items())
|
||||
if k.lower() not in ("content-length", "content-type"))
|
||||
return self.parent.open(urllib.request.Request(req.get_full_url(),
|
||||
headers=newheaders,
|
||||
origin_req_host=req.origin_req_host,
|
||||
unverifiable=True))
|
||||
|
||||
|
||||
# Some servers (e.g. GitHub archives, hosted on Amazon S3) return 403
|
||||
# Forbidden when they actually mean 405 Method Not Allowed.
|
||||
"""
|
||||
Some servers (e.g. GitHub archives, hosted on Amazon S3) return 403
|
||||
Forbidden when they actually mean 405 Method Not Allowed.
|
||||
"""
|
||||
http_error_403 = http_error_405
|
||||
|
||||
|
||||
@@ -279,15 +291,15 @@ class Wget(FetchMethod):
|
||||
"""
|
||||
def redirect_request(self, req, fp, code, msg, headers, newurl):
|
||||
newreq = urllib.request.HTTPRedirectHandler.redirect_request(self, req, fp, code, msg, headers, newurl)
|
||||
newreq.get_method = req.get_method
|
||||
newreq.get_method = lambda: req.get_method()
|
||||
return newreq
|
||||
exported_proxies = export_proxies(d)
|
||||
|
||||
handlers = [FixedHTTPRedirectHandler, HTTPMethodFallback]
|
||||
if exported_proxies:
|
||||
if export_proxies:
|
||||
handlers.append(urllib.request.ProxyHandler())
|
||||
handlers.append(CacheHTTPHandler())
|
||||
# Since Python 2.7.9 ssl cert validation is enabled by default
|
||||
# XXX: Since Python 2.7.9 ssl cert validation is enabled by default
|
||||
# see PEP-0476, this causes verification errors on some https servers
|
||||
# so disable by default.
|
||||
import ssl
|
||||
@@ -306,22 +318,21 @@ class Wget(FetchMethod):
|
||||
'''Adds Basic auth to http request, pass in login:password as string'''
|
||||
import base64
|
||||
encodeuser = base64.b64encode(login_str.encode('utf-8')).decode("utf-8")
|
||||
authheader = "Basic %s" % encodeuser
|
||||
authheader = "Basic %s" % encodeuser
|
||||
r.add_header("Authorization", authheader)
|
||||
|
||||
if ud.user and ud.pswd:
|
||||
add_basic_auth(ud.user + ':' + ud.pswd, r)
|
||||
if ud.user:
|
||||
add_basic_auth(ud.user, r)
|
||||
|
||||
try:
|
||||
import netrc
|
||||
import netrc, urllib.parse
|
||||
n = netrc.netrc()
|
||||
login, unused, password = n.authenticators(urllib.parse.urlparse(uri).hostname)
|
||||
add_basic_auth("%s:%s" % (login, password), r)
|
||||
except (TypeError, ImportError, IOError, netrc.NetrcParseError):
|
||||
pass
|
||||
pass
|
||||
|
||||
with opener.open(r) as response:
|
||||
pass
|
||||
opener.open(r)
|
||||
except urllib.error.URLError as e:
|
||||
if try_again:
|
||||
logger.debug(2, "checkstatus: trying again")
|
||||
@@ -383,14 +394,18 @@ class Wget(FetchMethod):
|
||||
(oldpn, oldpv, oldsuffix) = old
|
||||
(newpn, newpv, newsuffix) = new
|
||||
|
||||
# Check for a new suffix type that we have never heard of before
|
||||
if newsuffix:
|
||||
"""
|
||||
Check for a new suffix type that we have never heard of before
|
||||
"""
|
||||
if (newsuffix):
|
||||
m = self.suffix_regex_comp.search(newsuffix)
|
||||
if not m:
|
||||
bb.warn("%s has a possible unknown suffix: %s" % (newpn, newsuffix))
|
||||
return False
|
||||
|
||||
# Not our package so ignore it
|
||||
"""
|
||||
Not our package so ignore it
|
||||
"""
|
||||
if oldpn != newpn:
|
||||
return False
|
||||
|
||||
@@ -456,14 +471,15 @@ class Wget(FetchMethod):
|
||||
|
||||
return ""
|
||||
|
||||
def _check_latest_version_by_dir(self, dirver, package, package_regex, current_version, ud, d):
|
||||
def _check_latest_version_by_dir(self, dirver, package, package_regex,
|
||||
current_version, ud, d):
|
||||
"""
|
||||
Scan every directory in order to get upstream version.
|
||||
Scan every directory in order to get upstream version.
|
||||
"""
|
||||
version_dir = ['', '', '']
|
||||
version = ['', '', '']
|
||||
|
||||
dirver_regex = re.compile(r"(?P<pfx>\D*)(?P<ver>(\d+[\.\-_])+(\d+))")
|
||||
dirver_regex = re.compile("(?P<pfx>\D*)(?P<ver>(\d+[\.\-_])+(\d+))")
|
||||
s = dirver_regex.search(dirver)
|
||||
if s:
|
||||
version_dir[1] = s.group('ver')
|
||||
@@ -523,26 +539,26 @@ class Wget(FetchMethod):
|
||||
gst-fluendo-mp3
|
||||
"""
|
||||
# match most patterns which uses "-" as separator to version digits
|
||||
pn_prefix1 = r"[a-zA-Z][a-zA-Z0-9]*([-_][a-zA-Z]\w+)*\+?[-_]"
|
||||
pn_prefix1 = "[a-zA-Z][a-zA-Z0-9]*([-_][a-zA-Z]\w+)*\+?[-_]"
|
||||
# a loose pattern such as for unzip552.tar.gz
|
||||
pn_prefix2 = r"[a-zA-Z]+"
|
||||
pn_prefix2 = "[a-zA-Z]+"
|
||||
# a loose pattern such as for 80325-quicky-0.4.tar.gz
|
||||
pn_prefix3 = r"[0-9]+[-]?[a-zA-Z]+"
|
||||
pn_prefix3 = "[0-9]+[-]?[a-zA-Z]+"
|
||||
# Save the Package Name (pn) Regex for use later
|
||||
pn_regex = r"(%s|%s|%s)" % (pn_prefix1, pn_prefix2, pn_prefix3)
|
||||
pn_regex = "(%s|%s|%s)" % (pn_prefix1, pn_prefix2, pn_prefix3)
|
||||
|
||||
# match version
|
||||
pver_regex = r"(([A-Z]*\d+[a-zA-Z]*[\.\-_]*)+)"
|
||||
pver_regex = "(([A-Z]*\d+[a-zA-Z]*[\.\-_]*)+)"
|
||||
|
||||
# match arch
|
||||
parch_regex = "-source|_all_"
|
||||
|
||||
# src.rpm extension was added only for rpm package. Can be removed if the rpm
|
||||
# packaged will always be considered as having to be manually upgraded
|
||||
psuffix_regex = r"(tar\.gz|tgz|tar\.bz2|zip|xz|tar\.lz|rpm|bz2|orig\.tar\.gz|tar\.xz|src\.tar\.gz|src\.tgz|svnr\d+\.tar\.bz2|stable\.tar\.gz|src\.rpm)"
|
||||
psuffix_regex = "(tar\.gz|tgz|tar\.bz2|zip|xz|tar\.lz|rpm|bz2|orig\.tar\.gz|tar\.xz|src\.tar\.gz|src\.tgz|svnr\d+\.tar\.bz2|stable\.tar\.gz|src\.rpm)"
|
||||
|
||||
# match name, version and archive type of a package
|
||||
package_regex_comp = re.compile(r"(?P<name>%s?\.?v?)(?P<pver>%s)(?P<arch>%s)?[\.-](?P<type>%s$)"
|
||||
package_regex_comp = re.compile("(?P<name>%s?\.?v?)(?P<pver>%s)(?P<arch>%s)?[\.-](?P<type>%s$)"
|
||||
% (pn_regex, pver_regex, parch_regex, psuffix_regex))
|
||||
self.suffix_regex_comp = re.compile(psuffix_regex)
|
||||
|
||||
@@ -554,7 +570,7 @@ class Wget(FetchMethod):
|
||||
version = self._parse_path(package_regex_comp, package)
|
||||
if version:
|
||||
package_custom_regex_comp = re.compile(
|
||||
r"(?P<name>%s)(?P<pver>%s)(?P<arch>%s)?[\.-](?P<type>%s)" %
|
||||
"(?P<name>%s)(?P<pver>%s)(?P<arch>%s)?[\.-](?P<type>%s)" %
|
||||
(re.escape(version[0]), pver_regex, parch_regex, psuffix_regex))
|
||||
else:
|
||||
package_custom_regex_comp = None
|
||||
@@ -571,7 +587,7 @@ class Wget(FetchMethod):
|
||||
current_version = ['', d.getVar('PV'), '']
|
||||
|
||||
"""possible to have no version in pkg name, such as spectrum-fw"""
|
||||
if not re.search(r"\d+", package):
|
||||
if not re.search("\d+", package):
|
||||
current_version[1] = re.sub('_', '.', current_version[1])
|
||||
current_version[1] = re.sub('-', '.', current_version[1])
|
||||
return (current_version[1], '')
|
||||
@@ -589,13 +605,13 @@ class Wget(FetchMethod):
|
||||
|
||||
# search for version matches on folders inside the path, like:
|
||||
# "5.7" in http://download.gnome.org/sources/${PN}/5.7/${PN}-${PV}.tar.gz
|
||||
dirver_regex = re.compile(r"(?P<dirver>[^/]*(\d+\.)*\d+([-_]r\d+)*)/")
|
||||
dirver_regex = re.compile("(?P<dirver>[^/]*(\d+\.)*\d+([-_]r\d+)*)/")
|
||||
m = dirver_regex.search(path)
|
||||
if m:
|
||||
pn = d.getVar('PN')
|
||||
dirver = m.group('dirver')
|
||||
|
||||
dirver_pn_regex = re.compile(r"%s\d?" % (re.escape(pn)))
|
||||
dirver_pn_regex = re.compile("%s\d?" % (re.escape(pn)))
|
||||
if not dirver_pn_regex.search(dirver):
|
||||
return (self._check_latest_version_by_dir(dirver,
|
||||
package, package_regex, current_version, ud, d), '')
|
||||
|
||||
@@ -9,8 +9,18 @@
|
||||
# Copyright (C) 2005 ROAD GmbH
|
||||
# Copyright (C) 2006 Richard Purdie
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License version 2 as
|
||||
# published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
import os
|
||||
import sys
|
||||
@@ -282,12 +292,8 @@ class BitBakeConfigParameters(cookerdata.ConfigParameters):
|
||||
help="Writes the event log of the build to a bitbake event json file. "
|
||||
"Use '' (empty string) to assign the name automatically.")
|
||||
|
||||
parser.add_option("", "--runall", action="append", dest="runall",
|
||||
help="Run the specified task for any recipe in the taskgraph of the specified target (even if it wouldn't otherwise have run).")
|
||||
|
||||
parser.add_option("", "--runonly", action="append", dest="runonly",
|
||||
help="Run only the specified task within the taskgraph of the specified targets (and any task dependencies those tasks may have).")
|
||||
|
||||
parser.add_option("", "--runall", action="store", dest="runall",
|
||||
help="Run the specified task for all build targets and their dependencies.")
|
||||
|
||||
options, targets = parser.parse_args(argv)
|
||||
|
||||
@@ -395,6 +401,9 @@ def setup_bitbake(configParams, configuration, extrafeatures=None):
|
||||
# In status only mode there are no logs and no UI
|
||||
logger.addHandler(handler)
|
||||
|
||||
# Clear away any spurious environment variables while we stoke up the cooker
|
||||
cleanedvars = bb.utils.clean_environment()
|
||||
|
||||
if configParams.server_only:
|
||||
featureset = []
|
||||
ui_module = None
|
||||
@@ -410,10 +419,6 @@ def setup_bitbake(configParams, configuration, extrafeatures=None):
|
||||
|
||||
server_connection = None
|
||||
|
||||
# Clear away any spurious environment variables while we stoke up the cooker
|
||||
# (done after import_extension_module() above since for example import gi triggers env var usage)
|
||||
cleanedvars = bb.utils.clean_environment()
|
||||
|
||||
if configParams.remote_server:
|
||||
# Connect to a remote XMLRPC server
|
||||
server_connection = bb.server.xmlrpcclient.connectXMLRPC(configParams.remote_server, featureset,
|
||||
@@ -438,7 +443,7 @@ def setup_bitbake(configParams, configuration, extrafeatures=None):
|
||||
else:
|
||||
logger.info("Reconnecting to bitbake server...")
|
||||
if not os.path.exists(sockname):
|
||||
logger.info("Previous bitbake instance shutting down?, waiting to retry...")
|
||||
print("Previous bitbake instance shutting down?, waiting to retry...")
|
||||
i = 0
|
||||
lock = None
|
||||
# Wait for 5s or until we can get the lock
|
||||
@@ -465,11 +470,10 @@ def setup_bitbake(configParams, configuration, extrafeatures=None):
|
||||
if not retries:
|
||||
raise
|
||||
retries -= 1
|
||||
tryno = 8 - retries
|
||||
if isinstance(e, (bb.server.process.ProcessTimeout, BrokenPipeError)):
|
||||
logger.info("Retrying server connection (#%d)..." % tryno)
|
||||
logger.info("Retrying server connection...")
|
||||
else:
|
||||
logger.info("Retrying server connection (#%d)... (%s)" % (tryno, traceback.format_exc()))
|
||||
logger.info("Retrying server connection... (%s)" % traceback.format_exc())
|
||||
if not retries:
|
||||
bb.fatal("Unable to connect to bitbake server, or start one")
|
||||
if retries < 5:
|
||||
|
||||
@@ -4,8 +4,18 @@
|
||||
#
|
||||
# Copyright (C) 2006 Holger Hans Peter Freyther
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# 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.
|
||||
|
||||
from bb.utils import better_compile, better_exec
|
||||
|
||||
|
||||
@@ -4,8 +4,18 @@
|
||||
#
|
||||
# Copyright (C) 2012 Robert Yang
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# 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, logging, re, sys
|
||||
import bb
|
||||
@@ -18,16 +28,16 @@ def convertGMK(unit):
|
||||
|
||||
""" Convert the space unit G, M, K, the unit is case-insensitive """
|
||||
|
||||
unitG = re.match(r'([1-9][0-9]*)[gG]\s?$', unit)
|
||||
unitG = re.match('([1-9][0-9]*)[gG]\s?$', unit)
|
||||
if unitG:
|
||||
return int(unitG.group(1)) * (1024 ** 3)
|
||||
unitM = re.match(r'([1-9][0-9]*)[mM]\s?$', unit)
|
||||
unitM = re.match('([1-9][0-9]*)[mM]\s?$', unit)
|
||||
if unitM:
|
||||
return int(unitM.group(1)) * (1024 ** 2)
|
||||
unitK = re.match(r'([1-9][0-9]*)[kK]\s?$', unit)
|
||||
unitK = re.match('([1-9][0-9]*)[kK]\s?$', unit)
|
||||
if unitK:
|
||||
return int(unitK.group(1)) * 1024
|
||||
unitN = re.match(r'([1-9][0-9]*)\s?$', unit)
|
||||
unitN = re.match('([1-9][0-9]*)\s?$', unit)
|
||||
if unitN:
|
||||
return int(unitN.group(1))
|
||||
else:
|
||||
@@ -73,7 +83,7 @@ def getDiskData(BBDirs, configuration):
|
||||
for pathSpaceInode in BBDirs.split():
|
||||
# The input format is: "dir,space,inode", dir is a must, space
|
||||
# and inode are optional
|
||||
pathSpaceInodeRe = re.match(r'([^,]*),([^,]*),([^,]*),?(.*)', pathSpaceInode)
|
||||
pathSpaceInodeRe = re.match('([^,]*),([^,]*),([^,]*),?(.*)', pathSpaceInode)
|
||||
if not pathSpaceInodeRe:
|
||||
printErr("Invalid value in BB_DISKMON_DIRS: %s" % pathSpaceInode)
|
||||
return None
|
||||
@@ -137,7 +147,7 @@ def getInterval(configuration):
|
||||
else:
|
||||
# The disk space or inode interval is optional, but it should
|
||||
# have a correct value once it is specified
|
||||
intervalRe = re.match(r'([^,]*),?\s*(.*)', interval)
|
||||
intervalRe = re.match('([^,]*),?\s*(.*)', interval)
|
||||
if intervalRe:
|
||||
intervalSpace = intervalRe.group(1)
|
||||
if intervalSpace:
|
||||
|
||||
@@ -9,8 +9,18 @@ Message handling infrastructure for bitbake
|
||||
|
||||
# Copyright (C) 2006 Richard Purdie
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# 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 sys
|
||||
import copy
|
||||
@@ -30,7 +40,6 @@ class BBLogFormatter(logging.Formatter):
|
||||
VERBOSE = logging.INFO - 1
|
||||
NOTE = logging.INFO
|
||||
PLAIN = logging.INFO + 1
|
||||
VERBNOTE = logging.INFO + 2
|
||||
ERROR = logging.ERROR
|
||||
WARNING = logging.WARNING
|
||||
CRITICAL = logging.CRITICAL
|
||||
@@ -42,7 +51,6 @@ class BBLogFormatter(logging.Formatter):
|
||||
VERBOSE: 'NOTE',
|
||||
NOTE : 'NOTE',
|
||||
PLAIN : '',
|
||||
VERBNOTE: 'NOTE',
|
||||
WARNING : 'WARNING',
|
||||
ERROR : 'ERROR',
|
||||
CRITICAL: 'ERROR',
|
||||
@@ -58,7 +66,6 @@ class BBLogFormatter(logging.Formatter):
|
||||
VERBOSE : BASECOLOR,
|
||||
NOTE : BASECOLOR,
|
||||
PLAIN : BASECOLOR,
|
||||
VERBNOTE: BASECOLOR,
|
||||
WARNING : YELLOW,
|
||||
ERROR : RED,
|
||||
CRITICAL: RED,
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
# http://code.activestate.com/recipes/577629-namedtupleabc-abstract-base-class-mix-in-for-named/
|
||||
#!/usr/bin/env python
|
||||
# Copyright (c) 2011 Jan Kaliszewski (zuo). Available under the MIT License.
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
#
|
||||
|
||||
"""
|
||||
namedtuple_with_abc.py:
|
||||
|
||||
@@ -9,10 +9,20 @@ File parsers for the BitBake build tools.
|
||||
# Copyright (C) 2003, 2004 Chris Larson
|
||||
# Copyright (C) 2003, 2004 Phil Blundell
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# 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
|
||||
#
|
||||
|
||||
handlers = []
|
||||
|
||||
@@ -124,9 +134,8 @@ def resolve_file(fn, d):
|
||||
if not newfn:
|
||||
raise IOError(errno.ENOENT, "file %s not found in %s" % (fn, bbpath))
|
||||
fn = newfn
|
||||
else:
|
||||
mark_dependency(d, fn)
|
||||
|
||||
mark_dependency(d, fn)
|
||||
if not os.path.isfile(fn):
|
||||
raise IOError(errno.ENOENT, "file %s not found" % fn)
|
||||
|
||||
|
||||
@@ -8,8 +8,19 @@
|
||||
# Copyright (C) 2003, 2004 Phil Blundell
|
||||
# Copyright (C) 2009 Holger Hans Peter Freyther
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License version 2 as
|
||||
# published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
|
||||
import re
|
||||
import string
|
||||
@@ -167,7 +178,7 @@ class MethodNode(AstNode):
|
||||
funcname = ("__anon_%s_%s" % (self.lineno, self.filename.translate(MethodNode.tr_tbl)))
|
||||
self.python = True
|
||||
text = "def %s(d):\n" % (funcname) + text
|
||||
bb.methodpool.insert_method(funcname, text, self.filename, self.lineno - len(self.body) - 1)
|
||||
bb.methodpool.insert_method(funcname, text, self.filename, self.lineno - len(self.body))
|
||||
anonfuncs = data.getVar('__BBANONFUNCS', False) or []
|
||||
anonfuncs.append(funcname)
|
||||
data.setVar('__BBANONFUNCS', anonfuncs)
|
||||
@@ -324,39 +335,35 @@ def handleInherit(statements, filename, lineno, m):
|
||||
classes = m.group(1)
|
||||
statements.append(InheritNode(filename, lineno, classes))
|
||||
|
||||
def runAnonFuncs(d):
|
||||
def finalize(fn, d, variant = None):
|
||||
saved_handlers = bb.event.get_handlers().copy()
|
||||
|
||||
for var in d.getVar('__BBHANDLERS', False) or []:
|
||||
# try to add the handler
|
||||
handlerfn = d.getVarFlag(var, "filename", False)
|
||||
if not handlerfn:
|
||||
bb.fatal("Undefined event handler function '%s'" % var)
|
||||
handlerln = int(d.getVarFlag(var, "lineno", False))
|
||||
bb.event.register(var, d.getVar(var, False), (d.getVarFlag(var, "eventmask") or "").split(), handlerfn, handlerln)
|
||||
|
||||
bb.event.fire(bb.event.RecipePreFinalise(fn), d)
|
||||
|
||||
bb.data.expandKeys(d)
|
||||
code = []
|
||||
for funcname in d.getVar("__BBANONFUNCS", False) or []:
|
||||
code.append("%s(d)" % funcname)
|
||||
bb.utils.better_exec("\n".join(code), {"d": d})
|
||||
|
||||
def finalize(fn, d, variant = None):
|
||||
saved_handlers = bb.event.get_handlers().copy()
|
||||
try:
|
||||
for var in d.getVar('__BBHANDLERS', False) or []:
|
||||
# try to add the handler
|
||||
handlerfn = d.getVarFlag(var, "filename", False)
|
||||
if not handlerfn:
|
||||
bb.fatal("Undefined event handler function '%s'" % var)
|
||||
handlerln = int(d.getVarFlag(var, "lineno", False))
|
||||
bb.event.register(var, d.getVar(var, False), (d.getVarFlag(var, "eventmask") or "").split(), handlerfn, handlerln)
|
||||
tasklist = d.getVar('__BBTASKS', False) or []
|
||||
bb.event.fire(bb.event.RecipeTaskPreProcess(fn, list(tasklist)), d)
|
||||
bb.build.add_tasks(tasklist, d)
|
||||
|
||||
bb.event.fire(bb.event.RecipePreFinalise(fn), d)
|
||||
bb.parse.siggen.finalise(fn, d, variant)
|
||||
|
||||
bb.data.expandKeys(d)
|
||||
runAnonFuncs(d)
|
||||
d.setVar('BBINCLUDED', bb.parse.get_file_depends(d))
|
||||
|
||||
tasklist = d.getVar('__BBTASKS', False) or []
|
||||
bb.event.fire(bb.event.RecipeTaskPreProcess(fn, list(tasklist)), d)
|
||||
bb.build.add_tasks(tasklist, d)
|
||||
|
||||
bb.parse.siggen.finalise(fn, d, variant)
|
||||
|
||||
d.setVar('BBINCLUDED', bb.parse.get_file_depends(d))
|
||||
|
||||
bb.event.fire(bb.event.RecipeParsed(fn), d)
|
||||
finally:
|
||||
bb.event.set_handlers(saved_handlers)
|
||||
bb.event.fire(bb.event.RecipeParsed(fn), d)
|
||||
bb.event.set_handlers(saved_handlers)
|
||||
|
||||
def _create_variants(datastores, names, function, onlyfinalise):
|
||||
def create_variant(name, orig_d, arg = None):
|
||||
|
||||
@@ -12,8 +12,19 @@
|
||||
# Copyright (C) 2003, 2004 Chris Larson
|
||||
# Copyright (C) 2003, 2004 Phil Blundell
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License version 2 as
|
||||
# published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
|
||||
import re, bb, os
|
||||
import logging
|
||||
@@ -27,15 +38,14 @@ from .ConfHandler import include, init
|
||||
# For compatibility
|
||||
bb.deprecate_import(__name__, "bb.parse", ["vars_from_file"])
|
||||
|
||||
__func_start_regexp__ = re.compile(r"(((?P<py>python)|(?P<fr>fakeroot))\s*)*(?P<func>[\w\.\-\+\{\}\$]+)?\s*\(\s*\)\s*{$" )
|
||||
__inherit_regexp__ = re.compile(r"inherit\s+(.+)" )
|
||||
__export_func_regexp__ = re.compile(r"EXPORT_FUNCTIONS\s+(.+)" )
|
||||
__addtask_regexp__ = re.compile(r"addtask\s+(?P<func>\w+)\s*((before\s*(?P<before>((.*(?=after))|(.*))))|(after\s*(?P<after>((.*(?=before))|(.*)))))*")
|
||||
__deltask_regexp__ = re.compile(r"deltask\s+(?P<func>\w+)")
|
||||
__addhandler_regexp__ = re.compile(r"addhandler\s+(.+)" )
|
||||
__def_regexp__ = re.compile(r"def\s+(\w+).*:" )
|
||||
__python_func_regexp__ = re.compile(r"(\s+.*)|(^$)|(^#)" )
|
||||
__python_tab_regexp__ = re.compile(r" *\t")
|
||||
__func_start_regexp__ = re.compile( r"(((?P<py>python)|(?P<fr>fakeroot))\s*)*(?P<func>[\w\.\-\+\{\}\$]+)?\s*\(\s*\)\s*{$" )
|
||||
__inherit_regexp__ = re.compile( r"inherit\s+(.+)" )
|
||||
__export_func_regexp__ = re.compile( r"EXPORT_FUNCTIONS\s+(.+)" )
|
||||
__addtask_regexp__ = re.compile("addtask\s+(?P<func>\w+)\s*((before\s*(?P<before>((.*(?=after))|(.*))))|(after\s*(?P<after>((.*(?=before))|(.*)))))*")
|
||||
__deltask_regexp__ = re.compile("deltask\s+(?P<func>\w+)")
|
||||
__addhandler_regexp__ = re.compile( r"addhandler\s+(.+)" )
|
||||
__def_regexp__ = re.compile( r"def\s+(\w+).*:" )
|
||||
__python_func_regexp__ = re.compile( r"(\s+.*)|(^$)" )
|
||||
|
||||
__infunc__ = []
|
||||
__inpython__ = False
|
||||
@@ -121,6 +131,9 @@ def handle(fn, d, include):
|
||||
|
||||
abs_fn = resolve_file(fn, d)
|
||||
|
||||
if include:
|
||||
bb.parse.mark_dependency(d, abs_fn)
|
||||
|
||||
# actual loading
|
||||
statements = get_statements(fn, abs_fn, base_name)
|
||||
|
||||
@@ -150,16 +163,6 @@ def handle(fn, d, include):
|
||||
|
||||
def feeder(lineno, s, fn, root, statements, eof=False):
|
||||
global __func_start_regexp__, __inherit_regexp__, __export_func_regexp__, __addtask_regexp__, __addhandler_regexp__, __def_regexp__, __python_func_regexp__, __inpython__, __infunc__, __body__, bb, __residue__, __classname__
|
||||
|
||||
# Check tabs in python functions:
|
||||
# - def py_funcname(): covered by __inpython__
|
||||
# - python(): covered by '__anonymous' == __infunc__[0]
|
||||
# - python funcname(): covered by __infunc__[3]
|
||||
if __inpython__ or (__infunc__ and ('__anonymous' == __infunc__[0] or __infunc__[3])):
|
||||
tab = __python_tab_regexp__.match(s)
|
||||
if tab:
|
||||
bb.warn('python should use 4 spaces indentation, but found tabs in %s, line %s' % (root, lineno))
|
||||
|
||||
if __infunc__:
|
||||
if s == '}':
|
||||
__body__.append('')
|
||||
|
||||
@@ -11,8 +11,18 @@
|
||||
# Copyright (C) 2003, 2004 Chris Larson
|
||||
# Copyright (C) 2003, 2004 Phil Blundell
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# 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 errno
|
||||
import re
|
||||
@@ -124,6 +134,9 @@ def handle(fn, data, include):
|
||||
abs_fn = resolve_file(fn, data)
|
||||
f = open(abs_fn, 'r')
|
||||
|
||||
if include:
|
||||
bb.parse.mark_dependency(data, abs_fn)
|
||||
|
||||
statements = ast.StatementGroup()
|
||||
lineno = 0
|
||||
while True:
|
||||
@@ -137,7 +150,7 @@ def handle(fn, data, include):
|
||||
continue
|
||||
s = s.rstrip()
|
||||
while s[-1] == '\\':
|
||||
s2 = f.readline().rstrip()
|
||||
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))
|
||||
|
||||
@@ -11,10 +11,20 @@ File parsers for the BitBake build tools.
|
||||
# Copyright (C) 2003, 2004 Chris Larson
|
||||
# Copyright (C) 2003, 2004 Phil Blundell
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License version 2 as
|
||||
# published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
# Based on functions from the base bb module, Copyright 2003 Holger Schurig
|
||||
#
|
||||
|
||||
from __future__ import absolute_import
|
||||
from . import ConfHandler
|
||||
|
||||
@@ -8,8 +8,18 @@ currently, providing a key/value store accessed by 'domain'.
|
||||
# Copyright (C) 2007 Richard Purdie
|
||||
# Copyright (C) 2010 Chris Larson <chris_larson@mentor.com>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# 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 collections
|
||||
import logging
|
||||
@@ -19,7 +29,6 @@ import warnings
|
||||
from bb.compat import total_ordering
|
||||
from collections import Mapping
|
||||
import sqlite3
|
||||
import contextlib
|
||||
|
||||
sqlversion = sqlite3.sqlite_version_info
|
||||
if sqlversion[0] < 3 or (sqlversion[0] == 3 and sqlversion[1] < 3):
|
||||
@@ -27,181 +36,84 @@ if sqlversion[0] < 3 or (sqlversion[0] == 3 and sqlversion[1] < 3):
|
||||
|
||||
|
||||
logger = logging.getLogger("BitBake.PersistData")
|
||||
if hasattr(sqlite3, 'enable_shared_cache'):
|
||||
try:
|
||||
sqlite3.enable_shared_cache(True)
|
||||
except sqlite3.OperationalError:
|
||||
pass
|
||||
|
||||
|
||||
@total_ordering
|
||||
class SQLTable(collections.MutableMapping):
|
||||
class _Decorators(object):
|
||||
@staticmethod
|
||||
def retry(*, reconnect=True):
|
||||
"""
|
||||
Decorator that restarts a function if a database locked sqlite
|
||||
exception occurs. If reconnect is True, the database connection
|
||||
will be closed and reopened each time a failure occurs
|
||||
"""
|
||||
def retry_wrapper(f):
|
||||
def wrap_func(self, *args, **kwargs):
|
||||
# Reconnect if necessary
|
||||
if self.connection is None and reconnect:
|
||||
self.reconnect()
|
||||
|
||||
count = 0
|
||||
while True:
|
||||
try:
|
||||
return f(self, *args, **kwargs)
|
||||
except sqlite3.OperationalError as exc:
|
||||
if count < 500 and ('is locked' in str(exc) or 'locking protocol' in str(exc)):
|
||||
count = count + 1
|
||||
if reconnect:
|
||||
self.reconnect()
|
||||
continue
|
||||
raise
|
||||
return wrap_func
|
||||
return retry_wrapper
|
||||
|
||||
@staticmethod
|
||||
def transaction(f):
|
||||
"""
|
||||
Decorator that starts a database transaction and creates a database
|
||||
cursor for performing queries. If no exception is thrown, the
|
||||
database results are commited. If an exception occurs, the database
|
||||
is rolled back. In all cases, the cursor is closed after the
|
||||
function ends.
|
||||
|
||||
Note that the cursor is passed as an extra argument to the function
|
||||
after `self` and before any of the normal arguments
|
||||
"""
|
||||
def wrap_func(self, *args, **kwargs):
|
||||
# Context manager will COMMIT the database on success,
|
||||
# or ROLLBACK on an exception
|
||||
with self.connection:
|
||||
# Automatically close the cursor when done
|
||||
with contextlib.closing(self.connection.cursor()) as cursor:
|
||||
return f(self, cursor, *args, **kwargs)
|
||||
return wrap_func
|
||||
|
||||
"""Object representing a table/domain in the database"""
|
||||
def __init__(self, cachefile, table):
|
||||
self.cachefile = cachefile
|
||||
self.table = table
|
||||
self.cursor = connect(self.cachefile)
|
||||
|
||||
self.connection = None
|
||||
self._execute_single("CREATE TABLE IF NOT EXISTS %s(key TEXT PRIMARY KEY NOT NULL, value TEXT);" % table)
|
||||
self._execute("CREATE TABLE IF NOT EXISTS %s(key TEXT, value TEXT);"
|
||||
% table)
|
||||
|
||||
@_Decorators.retry(reconnect=False)
|
||||
@_Decorators.transaction
|
||||
def _setup_database(self, cursor):
|
||||
cursor.execute("pragma synchronous = off;")
|
||||
# Enable WAL and keep the autocheckpoint length small (the default is
|
||||
# usually 1000). Persistent caches are usually read-mostly, so keeping
|
||||
# this short will keep readers running quickly
|
||||
cursor.execute("pragma journal_mode = WAL;")
|
||||
cursor.execute("pragma wal_autocheckpoint = 100;")
|
||||
|
||||
def reconnect(self):
|
||||
if self.connection is not None:
|
||||
self.connection.close()
|
||||
self.connection = sqlite3.connect(self.cachefile, timeout=5)
|
||||
self.connection.text_factory = str
|
||||
self._setup_database()
|
||||
|
||||
@_Decorators.retry()
|
||||
@_Decorators.transaction
|
||||
def _execute_single(self, cursor, *query):
|
||||
"""
|
||||
Executes a single query and discards the results. This correctly closes
|
||||
the database cursor when finished
|
||||
"""
|
||||
cursor.execute(*query)
|
||||
|
||||
@_Decorators.retry()
|
||||
def _row_iter(self, f, *query):
|
||||
"""
|
||||
Helper function that returns a row iterator. Each time __next__ is
|
||||
called on the iterator, the provided function is evaluated to determine
|
||||
the return value
|
||||
"""
|
||||
class CursorIter(object):
|
||||
def __init__(self, cursor):
|
||||
self.cursor = cursor
|
||||
|
||||
def __iter__(self):
|
||||
return self
|
||||
|
||||
def __next__(self):
|
||||
row = self.cursor.fetchone()
|
||||
if row is None:
|
||||
def _execute(self, *query):
|
||||
"""Execute a query, waiting to acquire a lock if necessary"""
|
||||
count = 0
|
||||
while True:
|
||||
try:
|
||||
return self.cursor.execute(*query)
|
||||
except sqlite3.OperationalError as exc:
|
||||
if 'database is locked' in str(exc) and count < 500:
|
||||
count = count + 1
|
||||
self.cursor.close()
|
||||
raise StopIteration
|
||||
return f(row)
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(self, typ, value, traceback):
|
||||
self.cursor.close()
|
||||
return False
|
||||
|
||||
cursor = self.connection.cursor()
|
||||
try:
|
||||
cursor.execute(*query)
|
||||
return CursorIter(cursor)
|
||||
except:
|
||||
cursor.close()
|
||||
self.cursor = connect(self.cachefile)
|
||||
continue
|
||||
raise
|
||||
|
||||
def __enter__(self):
|
||||
self.connection.__enter__()
|
||||
self.cursor.__enter__()
|
||||
return self
|
||||
|
||||
def __exit__(self, *excinfo):
|
||||
self.connection.__exit__(*excinfo)
|
||||
self.cursor.__exit__(*excinfo)
|
||||
|
||||
@_Decorators.retry()
|
||||
@_Decorators.transaction
|
||||
def __getitem__(self, cursor, key):
|
||||
cursor.execute("SELECT * from %s where key=?;" % self.table, [key])
|
||||
row = cursor.fetchone()
|
||||
if row is not None:
|
||||
def __getitem__(self, key):
|
||||
data = self._execute("SELECT * from %s where key=?;" %
|
||||
self.table, [key])
|
||||
for row in data:
|
||||
return row[1]
|
||||
raise KeyError(key)
|
||||
|
||||
@_Decorators.retry()
|
||||
@_Decorators.transaction
|
||||
def __delitem__(self, cursor, key):
|
||||
def __delitem__(self, key):
|
||||
if key not in self:
|
||||
raise KeyError(key)
|
||||
cursor.execute("DELETE from %s where key=?;" % self.table, [key])
|
||||
self._execute("DELETE from %s where key=?;" % self.table, [key])
|
||||
|
||||
@_Decorators.retry()
|
||||
@_Decorators.transaction
|
||||
def __setitem__(self, cursor, key, value):
|
||||
def __setitem__(self, key, value):
|
||||
if not isinstance(key, str):
|
||||
raise TypeError('Only string keys are supported')
|
||||
elif not isinstance(value, str):
|
||||
raise TypeError('Only string values are supported')
|
||||
|
||||
cursor.execute("SELECT * from %s where key=?;" % self.table, [key])
|
||||
row = cursor.fetchone()
|
||||
if row is not None:
|
||||
cursor.execute("UPDATE %s SET value=? WHERE key=?;" % self.table, [value, key])
|
||||
data = self._execute("SELECT * from %s where key=?;" %
|
||||
self.table, [key])
|
||||
exists = len(list(data))
|
||||
if exists:
|
||||
self._execute("UPDATE %s SET value=? WHERE key=?;" % self.table,
|
||||
[value, key])
|
||||
else:
|
||||
cursor.execute("INSERT into %s(key, value) values (?, ?);" % self.table, [key, value])
|
||||
self._execute("INSERT into %s(key, value) values (?, ?);" %
|
||||
self.table, [key, value])
|
||||
|
||||
@_Decorators.retry()
|
||||
@_Decorators.transaction
|
||||
def __contains__(self, cursor, key):
|
||||
cursor.execute('SELECT * from %s where key=?;' % self.table, [key])
|
||||
return cursor.fetchone() is not None
|
||||
def __contains__(self, key):
|
||||
return key in set(self)
|
||||
|
||||
@_Decorators.retry()
|
||||
@_Decorators.transaction
|
||||
def __len__(self, cursor):
|
||||
cursor.execute("SELECT COUNT(key) FROM %s;" % self.table)
|
||||
row = cursor.fetchone()
|
||||
if row is not None:
|
||||
def __len__(self):
|
||||
data = self._execute("SELECT COUNT(key) FROM %s;" % self.table)
|
||||
for row in data:
|
||||
return row[0]
|
||||
|
||||
def __iter__(self):
|
||||
return self._row_iter(lambda row: row[0], "SELECT key from %s;" % self.table)
|
||||
data = self._execute("SELECT key FROM %s;" % self.table)
|
||||
return (row[0] for row in data)
|
||||
|
||||
def __lt__(self, other):
|
||||
if not isinstance(other, Mapping):
|
||||
@@ -210,27 +122,25 @@ class SQLTable(collections.MutableMapping):
|
||||
return len(self) < len(other)
|
||||
|
||||
def get_by_pattern(self, pattern):
|
||||
return self._row_iter(lambda row: row[1], "SELECT * FROM %s WHERE key LIKE ?;" %
|
||||
self.table, [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())
|
||||
|
||||
def itervalues(self):
|
||||
return self._row_iter(lambda row: row[0], "SELECT value FROM %s;" %
|
||||
self.table)
|
||||
data = self._execute("SELECT value FROM %s;" % self.table)
|
||||
return (row[0] for row in data)
|
||||
|
||||
def items(self):
|
||||
return list(self.iteritems())
|
||||
|
||||
def iteritems(self):
|
||||
return self._row_iter(lambda row: (row[0], row[1]), "SELECT * FROM %s;" %
|
||||
self.table)
|
||||
return self._execute("SELECT * FROM %s;" % self.table)
|
||||
|
||||
@_Decorators.retry()
|
||||
@_Decorators.transaction
|
||||
def clear(self, cursor):
|
||||
cursor.execute("DELETE FROM %s;" % self.table)
|
||||
def clear(self):
|
||||
self._execute("DELETE FROM %s;" % self.table)
|
||||
|
||||
def has_key(self, key):
|
||||
return key in self
|
||||
@@ -284,6 +194,12 @@ class PersistData(object):
|
||||
"""
|
||||
del self.data[domain][key]
|
||||
|
||||
def connect(database):
|
||||
connection = sqlite3.connect(database, timeout=5, isolation_level=None)
|
||||
connection.execute("pragma synchronous = off;")
|
||||
connection.text_factory = str
|
||||
return connection
|
||||
|
||||
def persist(domain, d):
|
||||
"""Convenience factory for SQLTable objects based upon metadata"""
|
||||
import bb.utils
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
#
|
||||
|
||||
import logging
|
||||
import signal
|
||||
import subprocess
|
||||
|
||||
@@ -4,8 +4,18 @@ BitBake progress handling code
|
||||
|
||||
# Copyright (C) 2016 Intel Corporation
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# 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 sys
|
||||
import re
|
||||
|
||||
@@ -8,8 +8,18 @@
|
||||
# Copyright (C) 2005 ROAD GmbH
|
||||
# Copyright (C) 2006 Richard Purdie
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License version 2 as
|
||||
# published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
import re
|
||||
import logging
|
||||
@@ -119,7 +129,7 @@ def findPreferredProvider(pn, cfgData, dataCache, pkg_pn = None, item = None):
|
||||
preferred_v = cfgData.getVar("PREFERRED_VERSION")
|
||||
|
||||
if preferred_v:
|
||||
m = re.match(r'(\d+:)*(.*)(_.*)*', preferred_v)
|
||||
m = re.match('(\d+:)*(.*)(_.*)*', preferred_v)
|
||||
if m:
|
||||
if m.group(1):
|
||||
preferred_e = m.group(1)[:-1]
|
||||
@@ -234,17 +244,17 @@ def _filterProviders(providers, item, cfgData, dataCache):
|
||||
pkg_pn[pn] = []
|
||||
pkg_pn[pn].append(p)
|
||||
|
||||
logger.debug(1, "providers for %s are: %s", item, list(sorted(pkg_pn.keys())))
|
||||
logger.debug(1, "providers for %s are: %s", item, list(pkg_pn.keys()))
|
||||
|
||||
# First add PREFERRED_VERSIONS
|
||||
for pn in sorted(pkg_pn):
|
||||
for pn in pkg_pn:
|
||||
sortpkg_pn[pn] = sortPriorities(pn, dataCache, pkg_pn)
|
||||
preferred_versions[pn] = findPreferredProvider(pn, cfgData, dataCache, sortpkg_pn[pn], item)
|
||||
if preferred_versions[pn][1]:
|
||||
eligible.append(preferred_versions[pn][1])
|
||||
|
||||
# Now add latest versions
|
||||
for pn in sorted(sortpkg_pn):
|
||||
for pn in sortpkg_pn:
|
||||
if pn in preferred_versions and preferred_versions[pn][1]:
|
||||
continue
|
||||
preferred_versions[pn] = findLatestProvider(pn, cfgData, dataCache, sortpkg_pn[pn][0])
|
||||
@@ -374,7 +384,7 @@ def getRuntimeProviders(dataCache, rdepend):
|
||||
|
||||
# Only search dynamic packages if we can't find anything in other variables
|
||||
for pattern in dataCache.packages_dynamic:
|
||||
pattern = pattern.replace(r'+', r"\+")
|
||||
pattern = pattern.replace('+', "\+")
|
||||
if pattern in regexp_cache:
|
||||
regexp = regexp_cache[pattern]
|
||||
else:
|
||||
|
||||
710
bitbake/lib/bb/pysh/builtin.py
Normal file
710
bitbake/lib/bb/pysh/builtin.py
Normal file
@@ -0,0 +1,710 @@
|
||||
# builtin.py - builtins and utilities definitions for pysh.
|
||||
#
|
||||
# Copyright 2007 Patrick Mezard
|
||||
#
|
||||
# This software may be used and distributed according to the terms
|
||||
# of the GNU General Public License, incorporated herein by reference.
|
||||
|
||||
"""Builtin and internal utilities implementations.
|
||||
|
||||
- Beware not to use python interpreter environment as if it were the shell
|
||||
environment. For instance, commands working directory must be explicitely handled
|
||||
through env['PWD'] instead of relying on python working directory.
|
||||
"""
|
||||
import errno
|
||||
import optparse
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
|
||||
def has_subprocess_bug():
|
||||
return getattr(subprocess, 'list2cmdline') and \
|
||||
( subprocess.list2cmdline(['']) == '' or \
|
||||
subprocess.list2cmdline(['foo|bar']) == 'foo|bar')
|
||||
|
||||
# Detect python bug 1634343: "subprocess swallows empty arguments under win32"
|
||||
# <http://sourceforge.net/tracker/index.php?func=detail&aid=1634343&group_id=5470&atid=105470>
|
||||
# Also detect: "[ 1710802 ] subprocess must escape redirection characters under win32"
|
||||
# <http://sourceforge.net/tracker/index.php?func=detail&aid=1710802&group_id=5470&atid=105470>
|
||||
if has_subprocess_bug():
|
||||
import subprocess_fix
|
||||
subprocess.list2cmdline = subprocess_fix.list2cmdline
|
||||
|
||||
from sherrors import *
|
||||
|
||||
class NonExitingParser(optparse.OptionParser):
|
||||
"""OptionParser default behaviour upon error is to print the error message and
|
||||
exit. Raise a utility error instead.
|
||||
"""
|
||||
def error(self, msg):
|
||||
raise UtilityError(msg)
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# set special builtin
|
||||
#-------------------------------------------------------------------------------
|
||||
OPT_SET = NonExitingParser(usage="set - set or unset options and positional parameters")
|
||||
OPT_SET.add_option( '-f', action='store_true', dest='has_f', default=False,
|
||||
help='The shell shall disable pathname expansion.')
|
||||
OPT_SET.add_option('-e', action='store_true', dest='has_e', default=False,
|
||||
help="""When this option is on, if a simple command fails for any of the \
|
||||
reasons listed in Consequences of Shell Errors or returns an exit status \
|
||||
value >0, and is not part of the compound list following a while, until, \
|
||||
or if keyword, and is not a part of an AND or OR list, and is not a \
|
||||
pipeline preceded by the ! reserved word, then the shell shall immediately \
|
||||
exit.""")
|
||||
OPT_SET.add_option('-x', action='store_true', dest='has_x', default=False,
|
||||
help="""The shell shall write to standard error a trace for each command \
|
||||
after it expands the command and before it executes it. It is unspecified \
|
||||
whether the command that turns tracing off is traced.""")
|
||||
|
||||
def builtin_set(name, args, interp, env, stdin, stdout, stderr, debugflags):
|
||||
if 'debug-utility' in debugflags:
|
||||
print interp.log(' '.join([name, str(args), interp['PWD']]) + '\n')
|
||||
|
||||
option, args = OPT_SET.parse_args(args)
|
||||
env = interp.get_env()
|
||||
|
||||
if option.has_f:
|
||||
env.set_opt('-f')
|
||||
if option.has_e:
|
||||
env.set_opt('-e')
|
||||
if option.has_x:
|
||||
env.set_opt('-x')
|
||||
return 0
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# shift special builtin
|
||||
#-------------------------------------------------------------------------------
|
||||
def builtin_shift(name, args, interp, env, stdin, stdout, stderr, debugflags):
|
||||
if 'debug-utility' in debugflags:
|
||||
print interp.log(' '.join([name, str(args), interp['PWD']]) + '\n')
|
||||
|
||||
params = interp.get_env().get_positional_args()
|
||||
if args:
|
||||
try:
|
||||
n = int(args[0])
|
||||
if n > len(params):
|
||||
raise ValueError()
|
||||
except ValueError:
|
||||
return 1
|
||||
else:
|
||||
n = 1
|
||||
|
||||
params[:n] = []
|
||||
interp.get_env().set_positional_args(params)
|
||||
return 0
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# export special builtin
|
||||
#-------------------------------------------------------------------------------
|
||||
OPT_EXPORT = NonExitingParser(usage="set - set or unset options and positional parameters")
|
||||
OPT_EXPORT.add_option('-p', action='store_true', dest='has_p', default=False)
|
||||
|
||||
def builtin_export(name, args, interp, env, stdin, stdout, stderr, debugflags):
|
||||
if 'debug-utility' in debugflags:
|
||||
print interp.log(' '.join([name, str(args), interp['PWD']]) + '\n')
|
||||
|
||||
option, args = OPT_EXPORT.parse_args(args)
|
||||
if option.has_p:
|
||||
raise NotImplementedError()
|
||||
|
||||
for arg in args:
|
||||
try:
|
||||
name, value = arg.split('=', 1)
|
||||
except ValueError:
|
||||
name, value = arg, None
|
||||
env = interp.get_env().export(name, value)
|
||||
|
||||
return 0
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# return special builtin
|
||||
#-------------------------------------------------------------------------------
|
||||
def builtin_return(name, args, interp, env, stdin, stdout, stderr, debugflags):
|
||||
if 'debug-utility' in debugflags:
|
||||
print interp.log(' '.join([name, str(args), interp['PWD']]) + '\n')
|
||||
res = 0
|
||||
if args:
|
||||
try:
|
||||
res = int(args[0])
|
||||
except ValueError:
|
||||
res = 0
|
||||
if not 0<=res<=255:
|
||||
res = 0
|
||||
|
||||
# BUG: should be last executed command exit code
|
||||
raise ReturnSignal(res)
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# trap special builtin
|
||||
#-------------------------------------------------------------------------------
|
||||
def builtin_trap(name, args, interp, env, stdin, stdout, stderr, debugflags):
|
||||
if 'debug-utility' in debugflags:
|
||||
print interp.log(' '.join([name, str(args), interp['PWD']]) + '\n')
|
||||
if len(args) < 2:
|
||||
stderr.write('trap: usage: trap [[arg] signal_spec ...]\n')
|
||||
return 2
|
||||
|
||||
action = args[0]
|
||||
for sig in args[1:]:
|
||||
try:
|
||||
env.traps[sig] = action
|
||||
except Exception as e:
|
||||
stderr.write('trap: %s\n' % str(e))
|
||||
return 0
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# unset special builtin
|
||||
#-------------------------------------------------------------------------------
|
||||
OPT_UNSET = NonExitingParser("unset - unset values and attributes of variables and functions")
|
||||
OPT_UNSET.add_option( '-f', action='store_true', dest='has_f', default=False)
|
||||
OPT_UNSET.add_option( '-v', action='store_true', dest='has_v', default=False)
|
||||
|
||||
def builtin_unset(name, args, interp, env, stdin, stdout, stderr, debugflags):
|
||||
if 'debug-utility' in debugflags:
|
||||
print interp.log(' '.join([name, str(args), interp['PWD']]) + '\n')
|
||||
|
||||
option, args = OPT_UNSET.parse_args(args)
|
||||
|
||||
status = 0
|
||||
env = interp.get_env()
|
||||
for arg in args:
|
||||
try:
|
||||
if option.has_f:
|
||||
env.remove_function(arg)
|
||||
else:
|
||||
del env[arg]
|
||||
except KeyError:
|
||||
pass
|
||||
except VarAssignmentError:
|
||||
status = 1
|
||||
|
||||
return status
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# wait special builtin
|
||||
#-------------------------------------------------------------------------------
|
||||
def builtin_wait(name, args, interp, env, stdin, stdout, stderr, debugflags):
|
||||
if 'debug-utility' in debugflags:
|
||||
print interp.log(' '.join([name, str(args), interp['PWD']]) + '\n')
|
||||
|
||||
return interp.wait([int(arg) for arg in args])
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# cat utility
|
||||
#-------------------------------------------------------------------------------
|
||||
def utility_cat(name, args, interp, env, stdin, stdout, stderr, debugflags):
|
||||
if 'debug-utility' in debugflags:
|
||||
print interp.log(' '.join([name, str(args), interp['PWD']]) + '\n')
|
||||
|
||||
if not args:
|
||||
args = ['-']
|
||||
|
||||
status = 0
|
||||
for arg in args:
|
||||
if arg == '-':
|
||||
data = stdin.read()
|
||||
else:
|
||||
path = os.path.join(env['PWD'], arg)
|
||||
try:
|
||||
f = file(path, 'rb')
|
||||
try:
|
||||
data = f.read()
|
||||
finally:
|
||||
f.close()
|
||||
except IOError as e:
|
||||
if e.errno != errno.ENOENT:
|
||||
raise
|
||||
status = 1
|
||||
continue
|
||||
stdout.write(data)
|
||||
stdout.flush()
|
||||
return status
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# cd utility
|
||||
#-------------------------------------------------------------------------------
|
||||
OPT_CD = NonExitingParser("cd - change the working directory")
|
||||
|
||||
def utility_cd(name, args, interp, env, stdin, stdout, stderr, debugflags):
|
||||
if 'debug-utility' in debugflags:
|
||||
print interp.log(' '.join([name, str(args), interp['PWD']]) + '\n')
|
||||
|
||||
option, args = OPT_CD.parse_args(args)
|
||||
env = interp.get_env()
|
||||
|
||||
directory = None
|
||||
printdir = False
|
||||
if not args:
|
||||
home = env.get('HOME')
|
||||
if home:
|
||||
# Unspecified, do nothing
|
||||
return 0
|
||||
else:
|
||||
directory = home
|
||||
elif len(args)==1:
|
||||
directory = args[0]
|
||||
if directory=='-':
|
||||
if 'OLDPWD' not in env:
|
||||
raise UtilityError("OLDPWD not set")
|
||||
printdir = True
|
||||
directory = env['OLDPWD']
|
||||
else:
|
||||
raise UtilityError("too many arguments")
|
||||
|
||||
curpath = None
|
||||
# Absolute directories will be handled correctly by the os.path.join call.
|
||||
if not directory.startswith('.') and not directory.startswith('..'):
|
||||
cdpaths = env.get('CDPATH', '.').split(';')
|
||||
for cdpath in cdpaths:
|
||||
p = os.path.join(cdpath, directory)
|
||||
if os.path.isdir(p):
|
||||
curpath = p
|
||||
break
|
||||
|
||||
if curpath is None:
|
||||
curpath = directory
|
||||
curpath = os.path.join(env['PWD'], directory)
|
||||
|
||||
env['OLDPWD'] = env['PWD']
|
||||
env['PWD'] = curpath
|
||||
if printdir:
|
||||
stdout.write('%s\n' % curpath)
|
||||
return 0
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# colon utility
|
||||
#-------------------------------------------------------------------------------
|
||||
def utility_colon(name, args, interp, env, stdin, stdout, stderr, debugflags):
|
||||
if 'debug-utility' in debugflags:
|
||||
print interp.log(' '.join([name, str(args), interp['PWD']]) + '\n')
|
||||
return 0
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# echo utility
|
||||
#-------------------------------------------------------------------------------
|
||||
def utility_echo(name, args, interp, env, stdin, stdout, stderr, debugflags):
|
||||
if 'debug-utility' in debugflags:
|
||||
print interp.log(' '.join([name, str(args), interp['PWD']]) + '\n')
|
||||
|
||||
# Echo only takes arguments, no options. Use printf if you need fancy stuff.
|
||||
output = ' '.join(args) + '\n'
|
||||
stdout.write(output)
|
||||
stdout.flush()
|
||||
return 0
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# egrep utility
|
||||
#-------------------------------------------------------------------------------
|
||||
# egrep is usually a shell script.
|
||||
# Unfortunately, pysh does not support shell scripts *with arguments* right now,
|
||||
# so the redirection is implemented here, assuming grep is available.
|
||||
def utility_egrep(name, args, interp, env, stdin, stdout, stderr, debugflags):
|
||||
if 'debug-utility' in debugflags:
|
||||
print interp.log(' '.join([name, str(args), interp['PWD']]) + '\n')
|
||||
|
||||
return run_command('grep', ['-E'] + args, interp, env, stdin, stdout,
|
||||
stderr, debugflags)
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# env utility
|
||||
#-------------------------------------------------------------------------------
|
||||
def utility_env(name, args, interp, env, stdin, stdout, stderr, debugflags):
|
||||
if 'debug-utility' in debugflags:
|
||||
print interp.log(' '.join([name, str(args), interp['PWD']]) + '\n')
|
||||
|
||||
if args and args[0]=='-i':
|
||||
raise NotImplementedError('env: -i option is not implemented')
|
||||
|
||||
i = 0
|
||||
for arg in args:
|
||||
if '=' not in arg:
|
||||
break
|
||||
# Update the current environment
|
||||
name, value = arg.split('=', 1)
|
||||
env[name] = value
|
||||
i += 1
|
||||
|
||||
if args[i:]:
|
||||
# Find then execute the specified interpreter
|
||||
utility = env.find_in_path(args[i])
|
||||
if not utility:
|
||||
return 127
|
||||
args[i:i+1] = utility
|
||||
name = args[i]
|
||||
args = args[i+1:]
|
||||
try:
|
||||
return run_command(name, args, interp, env, stdin, stdout, stderr,
|
||||
debugflags)
|
||||
except UtilityError:
|
||||
stderr.write('env: failed to execute %s' % ' '.join([name]+args))
|
||||
return 126
|
||||
else:
|
||||
for pair in env.get_variables().iteritems():
|
||||
stdout.write('%s=%s\n' % pair)
|
||||
return 0
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# exit utility
|
||||
#-------------------------------------------------------------------------------
|
||||
def utility_exit(name, args, interp, env, stdin, stdout, stderr, debugflags):
|
||||
if 'debug-utility' in debugflags:
|
||||
print interp.log(' '.join([name, str(args), interp['PWD']]) + '\n')
|
||||
|
||||
res = None
|
||||
if args:
|
||||
try:
|
||||
res = int(args[0])
|
||||
except ValueError:
|
||||
res = None
|
||||
if not 0<=res<=255:
|
||||
res = None
|
||||
|
||||
if res is None:
|
||||
# BUG: should be last executed command exit code
|
||||
res = 0
|
||||
|
||||
raise ExitSignal(res)
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# fgrep utility
|
||||
#-------------------------------------------------------------------------------
|
||||
# see egrep
|
||||
def utility_fgrep(name, args, interp, env, stdin, stdout, stderr, debugflags):
|
||||
if 'debug-utility' in debugflags:
|
||||
print interp.log(' '.join([name, str(args), interp['PWD']]) + '\n')
|
||||
|
||||
return run_command('grep', ['-F'] + args, interp, env, stdin, stdout,
|
||||
stderr, debugflags)
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# gunzip utility
|
||||
#-------------------------------------------------------------------------------
|
||||
# see egrep
|
||||
def utility_gunzip(name, args, interp, env, stdin, stdout, stderr, debugflags):
|
||||
if 'debug-utility' in debugflags:
|
||||
print interp.log(' '.join([name, str(args), interp['PWD']]) + '\n')
|
||||
|
||||
return run_command('gzip', ['-d'] + args, interp, env, stdin, stdout,
|
||||
stderr, debugflags)
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# kill utility
|
||||
#-------------------------------------------------------------------------------
|
||||
def utility_kill(name, args, interp, env, stdin, stdout, stderr, debugflags):
|
||||
if 'debug-utility' in debugflags:
|
||||
print interp.log(' '.join([name, str(args), interp['PWD']]) + '\n')
|
||||
|
||||
for arg in args:
|
||||
pid = int(arg)
|
||||
status = subprocess.call(['pskill', '/T', str(pid)],
|
||||
shell=True,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE)
|
||||
# pskill is asynchronous, hence the stupid polling loop
|
||||
while 1:
|
||||
p = subprocess.Popen(['pslist', str(pid)],
|
||||
shell=True,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT)
|
||||
output = p.communicate()[0]
|
||||
if ('process %d was not' % pid) in output:
|
||||
break
|
||||
time.sleep(1)
|
||||
return status
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# mkdir utility
|
||||
#-------------------------------------------------------------------------------
|
||||
OPT_MKDIR = NonExitingParser("mkdir - make directories.")
|
||||
OPT_MKDIR.add_option('-p', action='store_true', dest='has_p', default=False)
|
||||
|
||||
def utility_mkdir(name, args, interp, env, stdin, stdout, stderr, debugflags):
|
||||
if 'debug-utility' in debugflags:
|
||||
print interp.log(' '.join([name, str(args), interp['PWD']]) + '\n')
|
||||
|
||||
# TODO: implement umask
|
||||
# TODO: implement proper utility error report
|
||||
option, args = OPT_MKDIR.parse_args(args)
|
||||
for arg in args:
|
||||
path = os.path.join(env['PWD'], arg)
|
||||
if option.has_p:
|
||||
try:
|
||||
os.makedirs(path)
|
||||
except IOError as e:
|
||||
if e.errno != errno.EEXIST:
|
||||
raise
|
||||
else:
|
||||
os.mkdir(path)
|
||||
return 0
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# netstat utility
|
||||
#-------------------------------------------------------------------------------
|
||||
def utility_netstat(name, args, interp, env, stdin, stdout, stderr, debugflags):
|
||||
# Do you really expect me to implement netstat ?
|
||||
# This empty form is enough for Mercurial tests since it's
|
||||
# supposed to generate nothing upon success. Faking this test
|
||||
# is not a big deal either.
|
||||
if 'debug-utility' in debugflags:
|
||||
print interp.log(' '.join([name, str(args), interp['PWD']]) + '\n')
|
||||
return 0
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# pwd utility
|
||||
#-------------------------------------------------------------------------------
|
||||
OPT_PWD = NonExitingParser("pwd - return working directory name")
|
||||
OPT_PWD.add_option('-L', action='store_true', dest='has_L', default=True,
|
||||
help="""If the PWD environment variable contains an absolute pathname of \
|
||||
the current directory that does not contain the filenames dot or dot-dot, \
|
||||
pwd shall write this pathname to standard output. Otherwise, the -L option \
|
||||
shall behave as the -P option.""")
|
||||
OPT_PWD.add_option('-P', action='store_true', dest='has_L', default=False,
|
||||
help="""The absolute pathname written shall not contain filenames that, in \
|
||||
the context of the pathname, refer to files of type symbolic link.""")
|
||||
|
||||
def utility_pwd(name, args, interp, env, stdin, stdout, stderr, debugflags):
|
||||
if 'debug-utility' in debugflags:
|
||||
print interp.log(' '.join([name, str(args), interp['PWD']]) + '\n')
|
||||
|
||||
option, args = OPT_PWD.parse_args(args)
|
||||
stdout.write('%s\n' % env['PWD'])
|
||||
return 0
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# printf utility
|
||||
#-------------------------------------------------------------------------------
|
||||
RE_UNESCAPE = re.compile(r'(\\x[a-zA-Z0-9]{2}|\\[0-7]{1,3}|\\.)')
|
||||
|
||||
def utility_printf(name, args, interp, env, stdin, stdout, stderr, debugflags):
|
||||
if 'debug-utility' in debugflags:
|
||||
print interp.log(' '.join([name, str(args), interp['PWD']]) + '\n')
|
||||
|
||||
def replace(m):
|
||||
assert m.group()
|
||||
g = m.group()[1:]
|
||||
if g.startswith('x'):
|
||||
return chr(int(g[1:], 16))
|
||||
if len(g) <= 3 and len([c for c in g if c in '01234567']) == len(g):
|
||||
# Yay, an octal number
|
||||
return chr(int(g, 8))
|
||||
return {
|
||||
'a': '\a',
|
||||
'b': '\b',
|
||||
'f': '\f',
|
||||
'n': '\n',
|
||||
'r': '\r',
|
||||
't': '\t',
|
||||
'v': '\v',
|
||||
'\\': '\\',
|
||||
}.get(g)
|
||||
|
||||
# Convert escape sequences
|
||||
format = re.sub(RE_UNESCAPE, replace, args[0])
|
||||
stdout.write(format % tuple(args[1:]))
|
||||
return 0
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# true utility
|
||||
#-------------------------------------------------------------------------------
|
||||
def utility_true(name, args, interp, env, stdin, stdout, stderr, debugflags):
|
||||
if 'debug-utility' in debugflags:
|
||||
print interp.log(' '.join([name, str(args), interp['PWD']]) + '\n')
|
||||
return 0
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# sed utility
|
||||
#-------------------------------------------------------------------------------
|
||||
RE_SED = re.compile(r'^s(.).*\1[a-zA-Z]*$')
|
||||
|
||||
# cygwin sed fails with some expressions when they do not end with a single space.
|
||||
# see unit tests for details. Interestingly, the same expressions works perfectly
|
||||
# in cygwin shell.
|
||||
def utility_sed(name, args, interp, env, stdin, stdout, stderr, debugflags):
|
||||
if 'debug-utility' in debugflags:
|
||||
print interp.log(' '.join([name, str(args), interp['PWD']]) + '\n')
|
||||
|
||||
# Scan pattern arguments and append a space if necessary
|
||||
for i in range(len(args)):
|
||||
if not RE_SED.search(args[i]):
|
||||
continue
|
||||
args[i] = args[i] + ' '
|
||||
|
||||
return run_command(name, args, interp, env, stdin, stdout,
|
||||
stderr, debugflags)
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# sleep utility
|
||||
#-------------------------------------------------------------------------------
|
||||
def utility_sleep(name, args, interp, env, stdin, stdout, stderr, debugflags):
|
||||
if 'debug-utility' in debugflags:
|
||||
print interp.log(' '.join([name, str(args), interp['PWD']]) + '\n')
|
||||
time.sleep(int(args[0]))
|
||||
return 0
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# sort utility
|
||||
#-------------------------------------------------------------------------------
|
||||
OPT_SORT = NonExitingParser("sort - sort, merge, or sequence check text files")
|
||||
|
||||
def utility_sort(name, args, interp, env, stdin, stdout, stderr, debugflags):
|
||||
|
||||
def sort(path):
|
||||
if path == '-':
|
||||
lines = stdin.readlines()
|
||||
else:
|
||||
try:
|
||||
f = file(path)
|
||||
try:
|
||||
lines = f.readlines()
|
||||
finally:
|
||||
f.close()
|
||||
except IOError as e:
|
||||
stderr.write(str(e) + '\n')
|
||||
return 1
|
||||
|
||||
if lines and lines[-1][-1]!='\n':
|
||||
lines[-1] = lines[-1] + '\n'
|
||||
return lines
|
||||
|
||||
if 'debug-utility' in debugflags:
|
||||
print interp.log(' '.join([name, str(args), interp['PWD']]) + '\n')
|
||||
|
||||
option, args = OPT_SORT.parse_args(args)
|
||||
alllines = []
|
||||
|
||||
if len(args)<=0:
|
||||
args += ['-']
|
||||
|
||||
# Load all files lines
|
||||
curdir = os.getcwd()
|
||||
try:
|
||||
os.chdir(env['PWD'])
|
||||
for path in args:
|
||||
alllines += sort(path)
|
||||
finally:
|
||||
os.chdir(curdir)
|
||||
|
||||
alllines.sort()
|
||||
for line in alllines:
|
||||
stdout.write(line)
|
||||
return 0
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# hg utility
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
hgcommands = [
|
||||
'add',
|
||||
'addremove',
|
||||
'commit', 'ci',
|
||||
'debugrename',
|
||||
'debugwalk',
|
||||
'falabala', # Dummy command used in a mercurial test
|
||||
'incoming',
|
||||
'locate',
|
||||
'pull',
|
||||
'push',
|
||||
'qinit',
|
||||
'remove', 'rm',
|
||||
'rename', 'mv',
|
||||
'revert',
|
||||
'showconfig',
|
||||
'status', 'st',
|
||||
'strip',
|
||||
]
|
||||
|
||||
def rewriteslashes(name, args):
|
||||
# Several hg commands output file paths, rewrite the separators
|
||||
if len(args) > 1 and name.lower().endswith('python') \
|
||||
and args[0].endswith('hg'):
|
||||
for cmd in hgcommands:
|
||||
if cmd in args[1:]:
|
||||
return True
|
||||
|
||||
# svn output contains many paths with OS specific separators.
|
||||
# Normalize these to unix paths.
|
||||
base = os.path.basename(name)
|
||||
if base.startswith('svn'):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def rewritehg(output):
|
||||
if not output:
|
||||
return output
|
||||
# Rewrite os specific messages
|
||||
output = output.replace(': The system cannot find the file specified',
|
||||
': No such file or directory')
|
||||
output = re.sub(': Access is denied.*$', ': Permission denied', output)
|
||||
output = output.replace(': No connection could be made because the target machine actively refused it',
|
||||
': Connection refused')
|
||||
return output
|
||||
|
||||
|
||||
def run_command(name, args, interp, env, stdin, stdout,
|
||||
stderr, debugflags):
|
||||
# Execute the command
|
||||
if 'debug-utility' in debugflags:
|
||||
print interp.log(' '.join([name, str(args), interp['PWD']]) + '\n')
|
||||
|
||||
hgbin = interp.options().hgbinary
|
||||
ishg = hgbin and ('hg' in name or args and 'hg' in args[0])
|
||||
unixoutput = 'cygwin' in name or ishg
|
||||
|
||||
exec_env = env.get_variables()
|
||||
try:
|
||||
# BUG: comparing file descriptor is clearly not a reliable way to tell
|
||||
# whether they point on the same underlying object. But in pysh limited
|
||||
# scope this is usually right, we do not expect complicated redirections
|
||||
# besides usual 2>&1.
|
||||
# Still there is one case we have but cannot deal with is when stdout
|
||||
# and stderr are redirected *by pysh caller*. This the reason for the
|
||||
# --redirect pysh() option.
|
||||
# Now, we want to know they are the same because we sometimes need to
|
||||
# transform the command output, mostly remove CR-LF to ensure that
|
||||
# command output is unix-like. Cygwin utilies are a special case because
|
||||
# they explicitely set their output streams to binary mode, so we have
|
||||
# nothing to do. For all others commands, we have to guess whether they
|
||||
# are sending text data, in which case the transformation must be done.
|
||||
# Again, the NUL character test is unreliable but should be enough for
|
||||
# hg tests.
|
||||
redirected = stdout.fileno()==stderr.fileno()
|
||||
if not redirected:
|
||||
p = subprocess.Popen([name] + args, cwd=env['PWD'], env=exec_env,
|
||||
stdin=stdin, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
else:
|
||||
p = subprocess.Popen([name] + args, cwd=env['PWD'], env=exec_env,
|
||||
stdin=stdin, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||
out, err = p.communicate()
|
||||
except WindowsError as e:
|
||||
raise UtilityError(str(e))
|
||||
|
||||
if not unixoutput:
|
||||
def encode(s):
|
||||
if '\0' in s:
|
||||
return s
|
||||
return s.replace('\r\n', '\n')
|
||||
else:
|
||||
encode = lambda s: s
|
||||
|
||||
if rewriteslashes(name, args):
|
||||
encode1_ = encode
|
||||
def encode(s):
|
||||
s = encode1_(s)
|
||||
s = s.replace('\\\\', '\\')
|
||||
s = s.replace('\\', '/')
|
||||
return s
|
||||
|
||||
if ishg:
|
||||
encode2_ = encode
|
||||
def encode(s):
|
||||
return rewritehg(encode2_(s))
|
||||
|
||||
stdout.write(encode(out))
|
||||
if not redirected:
|
||||
stderr.write(encode(err))
|
||||
return p.returncode
|
||||
|
||||
1367
bitbake/lib/bb/pysh/interp.py
Normal file
1367
bitbake/lib/bb/pysh/interp.py
Normal file
File diff suppressed because it is too large
Load Diff
116
bitbake/lib/bb/pysh/lsprof.py
Normal file
116
bitbake/lib/bb/pysh/lsprof.py
Normal file
@@ -0,0 +1,116 @@
|
||||
#! /usr/bin/env python
|
||||
|
||||
import sys
|
||||
from _lsprof import Profiler, profiler_entry
|
||||
|
||||
__all__ = ['profile', 'Stats']
|
||||
|
||||
def profile(f, *args, **kwds):
|
||||
"""XXX docstring"""
|
||||
p = Profiler()
|
||||
p.enable(subcalls=True, builtins=True)
|
||||
try:
|
||||
f(*args, **kwds)
|
||||
finally:
|
||||
p.disable()
|
||||
return Stats(p.getstats())
|
||||
|
||||
|
||||
class Stats(object):
|
||||
"""XXX docstring"""
|
||||
|
||||
def __init__(self, data):
|
||||
self.data = data
|
||||
|
||||
def sort(self, crit="inlinetime"):
|
||||
"""XXX docstring"""
|
||||
if crit not in profiler_entry.__dict__:
|
||||
raise ValueError("Can't sort by %s" % crit)
|
||||
self.data.sort(lambda b, a: cmp(getattr(a, crit),
|
||||
getattr(b, crit)))
|
||||
for e in self.data:
|
||||
if e.calls:
|
||||
e.calls.sort(lambda b, a: cmp(getattr(a, crit),
|
||||
getattr(b, crit)))
|
||||
|
||||
def pprint(self, top=None, file=None, limit=None, climit=None):
|
||||
"""XXX docstring"""
|
||||
if file is None:
|
||||
file = sys.stdout
|
||||
d = self.data
|
||||
if top is not None:
|
||||
d = d[:top]
|
||||
cols = "% 12s %12s %11.4f %11.4f %s\n"
|
||||
hcols = "% 12s %12s %12s %12s %s\n"
|
||||
cols2 = "+%12s %12s %11.4f %11.4f + %s\n"
|
||||
file.write(hcols % ("CallCount", "Recursive", "Total(ms)",
|
||||
"Inline(ms)", "module:lineno(function)"))
|
||||
count = 0
|
||||
for e in d:
|
||||
file.write(cols % (e.callcount, e.reccallcount, e.totaltime,
|
||||
e.inlinetime, label(e.code)))
|
||||
count += 1
|
||||
if limit is not None and count == limit:
|
||||
return
|
||||
ccount = 0
|
||||
if e.calls:
|
||||
for se in e.calls:
|
||||
file.write(cols % ("+%s" % se.callcount, se.reccallcount,
|
||||
se.totaltime, se.inlinetime,
|
||||
"+%s" % label(se.code)))
|
||||
count += 1
|
||||
ccount += 1
|
||||
if limit is not None and count == limit:
|
||||
return
|
||||
if climit is not None and ccount == climit:
|
||||
break
|
||||
|
||||
def freeze(self):
|
||||
"""Replace all references to code objects with string
|
||||
descriptions; this makes it possible to pickle the instance."""
|
||||
|
||||
# this code is probably rather ickier than it needs to be!
|
||||
for i in range(len(self.data)):
|
||||
e = self.data[i]
|
||||
if not isinstance(e.code, str):
|
||||
self.data[i] = type(e)((label(e.code),) + e[1:])
|
||||
if e.calls:
|
||||
for j in range(len(e.calls)):
|
||||
se = e.calls[j]
|
||||
if not isinstance(se.code, str):
|
||||
e.calls[j] = type(se)((label(se.code),) + se[1:])
|
||||
|
||||
_fn2mod = {}
|
||||
|
||||
def label(code):
|
||||
if isinstance(code, str):
|
||||
return code
|
||||
try:
|
||||
mname = _fn2mod[code.co_filename]
|
||||
except KeyError:
|
||||
for k, v in sys.modules.items():
|
||||
if v is None:
|
||||
continue
|
||||
if not hasattr(v, '__file__'):
|
||||
continue
|
||||
if not isinstance(v.__file__, str):
|
||||
continue
|
||||
if v.__file__.startswith(code.co_filename):
|
||||
mname = _fn2mod[code.co_filename] = k
|
||||
break
|
||||
else:
|
||||
mname = _fn2mod[code.co_filename] = '<%s>'%code.co_filename
|
||||
|
||||
return '%s:%d(%s)' % (mname, code.co_firstlineno, code.co_name)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import os
|
||||
sys.argv = sys.argv[1:]
|
||||
if not sys.argv:
|
||||
print >> sys.stderr, "usage: lsprof.py <script> <arguments...>"
|
||||
sys.exit(2)
|
||||
sys.path.insert(0, os.path.abspath(os.path.dirname(sys.argv[0])))
|
||||
stats = profile(execfile, sys.argv[0], globals(), locals())
|
||||
stats.sort()
|
||||
stats.pprint()
|
||||
167
bitbake/lib/bb/pysh/pysh.py
Normal file
167
bitbake/lib/bb/pysh/pysh.py
Normal file
@@ -0,0 +1,167 @@
|
||||
# pysh.py - command processing for pysh.
|
||||
#
|
||||
# Copyright 2007 Patrick Mezard
|
||||
#
|
||||
# This software may be used and distributed according to the terms
|
||||
# of the GNU General Public License, incorporated herein by reference.
|
||||
|
||||
import optparse
|
||||
import os
|
||||
import sys
|
||||
|
||||
import interp
|
||||
|
||||
SH_OPT = optparse.OptionParser(prog='pysh', usage="%prog [OPTIONS]", version='0.1')
|
||||
SH_OPT.add_option('-c', action='store_true', dest='command_string', default=None,
|
||||
help='A string that shall be interpreted by the shell as one or more commands')
|
||||
SH_OPT.add_option('--redirect-to', dest='redirect_to', default=None,
|
||||
help='Redirect script commands stdout and stderr to the specified file')
|
||||
# See utility_command in builtin.py about the reason for this flag.
|
||||
SH_OPT.add_option('--redirected', dest='redirected', action='store_true', default=False,
|
||||
help='Tell the interpreter that stdout and stderr are actually the same objects, which is really stdout')
|
||||
SH_OPT.add_option('--debug-parsing', action='store_true', dest='debug_parsing', default=False,
|
||||
help='Trace PLY execution')
|
||||
SH_OPT.add_option('--debug-tree', action='store_true', dest='debug_tree', default=False,
|
||||
help='Display the generated syntax tree.')
|
||||
SH_OPT.add_option('--debug-cmd', action='store_true', dest='debug_cmd', default=False,
|
||||
help='Trace command execution before parameters expansion and exit status.')
|
||||
SH_OPT.add_option('--debug-utility', action='store_true', dest='debug_utility', default=False,
|
||||
help='Trace utility calls, after parameters expansions')
|
||||
SH_OPT.add_option('--ast', action='store_true', dest='ast', default=False,
|
||||
help='Encoded commands to execute in a subprocess')
|
||||
SH_OPT.add_option('--profile', action='store_true', default=False,
|
||||
help='Profile pysh run')
|
||||
|
||||
|
||||
def split_args(args):
|
||||
# Separate shell arguments from command ones
|
||||
# Just stop at the first argument not starting with a dash. I know, this is completely broken,
|
||||
# it ignores files starting with a dash or may take option values for command file. This is not
|
||||
# supposed to happen for now
|
||||
command_index = len(args)
|
||||
for i,arg in enumerate(args):
|
||||
if not arg.startswith('-'):
|
||||
command_index = i
|
||||
break
|
||||
|
||||
return args[:command_index], args[command_index:]
|
||||
|
||||
|
||||
def fixenv(env):
|
||||
path = env.get('PATH')
|
||||
if path is not None:
|
||||
parts = path.split(os.pathsep)
|
||||
# Remove Windows utilities from PATH, they are useless at best and
|
||||
# some of them (find) may be confused with other utilities.
|
||||
parts = [p for p in parts if 'system32' not in p.lower()]
|
||||
env['PATH'] = os.pathsep.join(parts)
|
||||
if env.get('HOME') is None:
|
||||
# Several utilities, including cvsps, cannot work without
|
||||
# a defined HOME directory.
|
||||
env['HOME'] = os.path.expanduser('~')
|
||||
return env
|
||||
|
||||
def _sh(cwd, shargs, cmdargs, options, debugflags=None, env=None):
|
||||
if os.environ.get('PYSH_TEXT') != '1':
|
||||
import msvcrt
|
||||
for fp in (sys.stdin, sys.stdout, sys.stderr):
|
||||
msvcrt.setmode(fp.fileno(), os.O_BINARY)
|
||||
|
||||
hgbin = os.environ.get('PYSH_HGTEXT') != '1'
|
||||
|
||||
if debugflags is None:
|
||||
debugflags = []
|
||||
if options.debug_parsing: debugflags.append('debug-parsing')
|
||||
if options.debug_utility: debugflags.append('debug-utility')
|
||||
if options.debug_cmd: debugflags.append('debug-cmd')
|
||||
if options.debug_tree: debugflags.append('debug-tree')
|
||||
|
||||
if env is None:
|
||||
env = fixenv(dict(os.environ))
|
||||
if cwd is None:
|
||||
cwd = os.getcwd()
|
||||
|
||||
if not cmdargs:
|
||||
# Nothing to do
|
||||
return 0
|
||||
|
||||
ast = None
|
||||
command_file = None
|
||||
if options.command_string:
|
||||
input = cmdargs[0]
|
||||
if not options.ast:
|
||||
input += '\n'
|
||||
else:
|
||||
args, input = interp.decodeargs(input), None
|
||||
env, ast = args
|
||||
cwd = env.get('PWD', cwd)
|
||||
else:
|
||||
command_file = cmdargs[0]
|
||||
arguments = cmdargs[1:]
|
||||
|
||||
prefix = interp.resolve_shebang(command_file, ignoreshell=True)
|
||||
if prefix:
|
||||
input = ' '.join(prefix + [command_file] + arguments)
|
||||
else:
|
||||
# Read commands from file
|
||||
f = file(command_file)
|
||||
try:
|
||||
# Trailing newline to help the parser
|
||||
input = f.read() + '\n'
|
||||
finally:
|
||||
f.close()
|
||||
|
||||
redirect = None
|
||||
try:
|
||||
if options.redirected:
|
||||
stdout = sys.stdout
|
||||
stderr = stdout
|
||||
elif options.redirect_to:
|
||||
redirect = open(options.redirect_to, 'wb')
|
||||
stdout = redirect
|
||||
stderr = redirect
|
||||
else:
|
||||
stdout = sys.stdout
|
||||
stderr = sys.stderr
|
||||
|
||||
# TODO: set arguments to environment variables
|
||||
opts = interp.Options()
|
||||
opts.hgbinary = hgbin
|
||||
ip = interp.Interpreter(cwd, debugflags, stdout=stdout, stderr=stderr,
|
||||
opts=opts)
|
||||
try:
|
||||
# Export given environment in shell object
|
||||
for k,v in env.iteritems():
|
||||
ip.get_env().export(k,v)
|
||||
return ip.execute_script(input, ast, scriptpath=command_file)
|
||||
finally:
|
||||
ip.close()
|
||||
finally:
|
||||
if redirect is not None:
|
||||
redirect.close()
|
||||
|
||||
def sh(cwd=None, args=None, debugflags=None, env=None):
|
||||
if args is None:
|
||||
args = sys.argv[1:]
|
||||
shargs, cmdargs = split_args(args)
|
||||
options, shargs = SH_OPT.parse_args(shargs)
|
||||
|
||||
if options.profile:
|
||||
import lsprof
|
||||
p = lsprof.Profiler()
|
||||
p.enable(subcalls=True)
|
||||
try:
|
||||
return _sh(cwd, shargs, cmdargs, options, debugflags, env)
|
||||
finally:
|
||||
p.disable()
|
||||
stats = lsprof.Stats(p.getstats())
|
||||
stats.sort()
|
||||
stats.pprint(top=10, file=sys.stderr, climit=5)
|
||||
else:
|
||||
return _sh(cwd, shargs, cmdargs, options, debugflags, env)
|
||||
|
||||
def main():
|
||||
sys.exit(sh())
|
||||
|
||||
if __name__=='__main__':
|
||||
main()
|
||||
@@ -13,6 +13,11 @@
|
||||
# PLY in pull mode. It was designed to work incrementally and it would not be
|
||||
# that hard to enable pull mode.
|
||||
import re
|
||||
try:
|
||||
s = set()
|
||||
del s
|
||||
except NameError:
|
||||
from Set import Set as set
|
||||
|
||||
from ply import lex
|
||||
from bb.pysh.sherrors import *
|
||||
|
||||
@@ -636,16 +636,13 @@ def p_empty(p):
|
||||
def p_error(p):
|
||||
msg = []
|
||||
w = msg.append
|
||||
if p:
|
||||
w('%r\n' % p)
|
||||
w('followed by:\n')
|
||||
for i in range(5):
|
||||
n = yacc.token()
|
||||
if not n:
|
||||
break
|
||||
w(' %r\n' % n)
|
||||
else:
|
||||
w('Unexpected EOF')
|
||||
w('%r\n' % p)
|
||||
w('followed by:\n')
|
||||
for i in range(5):
|
||||
n = yacc.token()
|
||||
if not n:
|
||||
break
|
||||
w(' %r\n' % n)
|
||||
raise sherrors.ShellSyntaxError(''.join(msg))
|
||||
|
||||
# Build the parser
|
||||
|
||||
@@ -13,3 +13,29 @@ class ShellError(Exception):
|
||||
|
||||
class ShellSyntaxError(ShellError):
|
||||
pass
|
||||
|
||||
class UtilityError(ShellError):
|
||||
"""Raised upon utility syntax error (option or operand error)."""
|
||||
pass
|
||||
|
||||
class ExpansionError(ShellError):
|
||||
pass
|
||||
|
||||
class CommandNotFound(ShellError):
|
||||
"""Specified command was not found."""
|
||||
pass
|
||||
|
||||
class RedirectionError(ShellError):
|
||||
pass
|
||||
|
||||
class VarAssignmentError(ShellError):
|
||||
"""Variable assignment error."""
|
||||
pass
|
||||
|
||||
class ExitSignal(ShellError):
|
||||
"""Exit signal."""
|
||||
pass
|
||||
|
||||
class ReturnSignal(ShellError):
|
||||
"""Exit signal."""
|
||||
pass
|
||||
|
||||
77
bitbake/lib/bb/pysh/subprocess_fix.py
Normal file
77
bitbake/lib/bb/pysh/subprocess_fix.py
Normal file
@@ -0,0 +1,77 @@
|
||||
# subprocess - Subprocesses with accessible I/O streams
|
||||
#
|
||||
# For more information about this module, see PEP 324.
|
||||
#
|
||||
# This module should remain compatible with Python 2.2, see PEP 291.
|
||||
#
|
||||
# Copyright (c) 2003-2005 by Peter Astrand <astrand@lysator.liu.se>
|
||||
#
|
||||
# Licensed to PSF under a Contributor Agreement.
|
||||
# See http://www.python.org/2.4/license for licensing details.
|
||||
|
||||
def list2cmdline(seq):
|
||||
"""
|
||||
Translate a sequence of arguments into a command line
|
||||
string, using the same rules as the MS C runtime:
|
||||
|
||||
1) Arguments are delimited by white space, which is either a
|
||||
space or a tab.
|
||||
|
||||
2) A string surrounded by double quotation marks is
|
||||
interpreted as a single argument, regardless of white space
|
||||
contained within. A quoted string can be embedded in an
|
||||
argument.
|
||||
|
||||
3) A double quotation mark preceded by a backslash is
|
||||
interpreted as a literal double quotation mark.
|
||||
|
||||
4) Backslashes are interpreted literally, unless they
|
||||
immediately precede a double quotation mark.
|
||||
|
||||
5) If backslashes immediately precede a double quotation mark,
|
||||
every pair of backslashes is interpreted as a literal
|
||||
backslash. If the number of backslashes is odd, the last
|
||||
backslash escapes the next double quotation mark as
|
||||
described in rule 3.
|
||||
"""
|
||||
|
||||
# See
|
||||
# http://msdn.microsoft.com/library/en-us/vccelng/htm/progs_12.asp
|
||||
result = []
|
||||
needquote = False
|
||||
for arg in seq:
|
||||
bs_buf = []
|
||||
|
||||
# Add a space to separate this argument from the others
|
||||
if result:
|
||||
result.append(' ')
|
||||
|
||||
needquote = (" " in arg) or ("\t" in arg) or ("|" in arg) or arg == ""
|
||||
if needquote:
|
||||
result.append('"')
|
||||
|
||||
for c in arg:
|
||||
if c == '\\':
|
||||
# Don't know if we need to double yet.
|
||||
bs_buf.append(c)
|
||||
elif c == '"':
|
||||
# Double backspaces.
|
||||
result.append('\\' * len(bs_buf)*2)
|
||||
bs_buf = []
|
||||
result.append('\\"')
|
||||
else:
|
||||
# Normal char
|
||||
if bs_buf:
|
||||
result.extend(bs_buf)
|
||||
bs_buf = []
|
||||
result.append(c)
|
||||
|
||||
# Add remaining backspaces, if any.
|
||||
if bs_buf:
|
||||
result.extend(bs_buf)
|
||||
|
||||
if needquote:
|
||||
result.extend(bs_buf)
|
||||
result.append('"')
|
||||
|
||||
return ''.join(result)
|
||||
@@ -6,8 +6,18 @@ Provides support for using a datastore from the bitbake client
|
||||
|
||||
# Copyright (C) 2016 Intel Corporation
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# 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 bb.data
|
||||
|
||||
|
||||
@@ -9,8 +9,18 @@ Handles preparation and execution of a queue of tasks
|
||||
|
||||
# Copyright (C) 2006-2007 Richard Purdie
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# 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 copy
|
||||
import os
|
||||
@@ -27,12 +37,11 @@ from bb import monitordisk
|
||||
import subprocess
|
||||
import pickle
|
||||
from multiprocessing import Process
|
||||
import shlex
|
||||
|
||||
bblogger = logging.getLogger("BitBake")
|
||||
logger = logging.getLogger("BitBake.RunQueue")
|
||||
|
||||
__find_sha256__ = re.compile( r'(?i)(?<![a-z0-9])[a-f0-9]{64}(?![a-z0-9])' )
|
||||
__find_md5__ = re.compile( r'(?i)(?<![a-z0-9])[a-f0-9]{32}(?![a-z0-9])' )
|
||||
|
||||
def fn_from_tid(tid):
|
||||
return tid.rsplit(":", 1)[0]
|
||||
@@ -40,11 +49,6 @@ def fn_from_tid(tid):
|
||||
def taskname_from_tid(tid):
|
||||
return tid.rsplit(":", 1)[1]
|
||||
|
||||
def mc_from_tid(tid):
|
||||
if tid.startswith('multiconfig:'):
|
||||
return tid.split(':')[1]
|
||||
return ""
|
||||
|
||||
def split_tid(tid):
|
||||
(mc, fn, taskname, _) = split_tid_mcfn(tid)
|
||||
return (mc, fn, taskname)
|
||||
@@ -90,13 +94,13 @@ class RunQueueStats:
|
||||
self.active = self.active - 1
|
||||
self.failed = self.failed + 1
|
||||
|
||||
def taskCompleted(self):
|
||||
self.active = self.active - 1
|
||||
self.completed = self.completed + 1
|
||||
def taskCompleted(self, number = 1):
|
||||
self.active = self.active - number
|
||||
self.completed = self.completed + number
|
||||
|
||||
def taskSkipped(self):
|
||||
self.active = self.active + 1
|
||||
self.skipped = self.skipped + 1
|
||||
def taskSkipped(self, number = 1):
|
||||
self.active = self.active + number
|
||||
self.skipped = self.skipped + number
|
||||
|
||||
def taskActive(self):
|
||||
self.active = self.active + 1
|
||||
@@ -130,7 +134,6 @@ class RunQueueScheduler(object):
|
||||
self.prio_map = [self.rqdata.runtaskentries.keys()]
|
||||
|
||||
self.buildable = []
|
||||
self.skip_maxthread = {}
|
||||
self.stamps = {}
|
||||
for tid in self.rqdata.runtaskentries:
|
||||
(mc, fn, taskname, taskfn) = split_tid_mcfn(tid)
|
||||
@@ -147,25 +150,8 @@ class RunQueueScheduler(object):
|
||||
self.buildable = [x for x in self.buildable if x not in self.rq.runq_running]
|
||||
if not self.buildable:
|
||||
return None
|
||||
|
||||
# Filter out tasks that have a max number of threads that have been exceeded
|
||||
skip_buildable = {}
|
||||
for running in self.rq.runq_running.difference(self.rq.runq_complete):
|
||||
rtaskname = taskname_from_tid(running)
|
||||
if rtaskname not in self.skip_maxthread:
|
||||
self.skip_maxthread[rtaskname] = self.rq.cfgData.getVarFlag(rtaskname, "number_threads")
|
||||
if not self.skip_maxthread[rtaskname]:
|
||||
continue
|
||||
if rtaskname in skip_buildable:
|
||||
skip_buildable[rtaskname] += 1
|
||||
else:
|
||||
skip_buildable[rtaskname] = 1
|
||||
|
||||
if len(self.buildable) == 1:
|
||||
tid = self.buildable[0]
|
||||
taskname = taskname_from_tid(tid)
|
||||
if taskname in skip_buildable and skip_buildable[taskname] >= int(self.skip_maxthread[taskname]):
|
||||
return None
|
||||
stamp = self.stamps[tid]
|
||||
if stamp not in self.rq.build_stamps.values():
|
||||
return tid
|
||||
@@ -178,9 +164,6 @@ class RunQueueScheduler(object):
|
||||
best = None
|
||||
bestprio = None
|
||||
for tid in self.buildable:
|
||||
taskname = taskname_from_tid(tid)
|
||||
if taskname in skip_buildable and skip_buildable[taskname] >= int(self.skip_maxthread[taskname]):
|
||||
continue
|
||||
prio = self.rev_prio_map[tid]
|
||||
if bestprio is None or bestprio > prio:
|
||||
stamp = self.stamps[tid]
|
||||
@@ -195,10 +178,10 @@ class RunQueueScheduler(object):
|
||||
"""
|
||||
Return the id of the task we should build next
|
||||
"""
|
||||
if self.rq.can_start_task():
|
||||
if self.rq.stats.active < self.rq.number_tasks:
|
||||
return self.next_buildable_task()
|
||||
|
||||
def newbuildable(self, task):
|
||||
def newbuilable(self, task):
|
||||
self.buildable.append(task)
|
||||
|
||||
def describe_task(self, taskid):
|
||||
@@ -342,7 +325,6 @@ class RunTaskEntry(object):
|
||||
self.depends = set()
|
||||
self.revdeps = set()
|
||||
self.hash = None
|
||||
self.unihash = None
|
||||
self.task = None
|
||||
self.weight = 1
|
||||
|
||||
@@ -382,9 +364,6 @@ class RunQueueData:
|
||||
def get_task_hash(self, tid):
|
||||
return self.runtaskentries[tid].hash
|
||||
|
||||
def get_task_unihash(self, tid):
|
||||
return self.runtaskentries[tid].unihash
|
||||
|
||||
def get_user_idstring(self, tid, task_name_suffix = ""):
|
||||
return tid + task_name_suffix
|
||||
|
||||
@@ -405,9 +384,6 @@ class RunQueueData:
|
||||
explored_deps = {}
|
||||
msgs = []
|
||||
|
||||
class TooManyLoops(Exception):
|
||||
pass
|
||||
|
||||
def chain_reorder(chain):
|
||||
"""
|
||||
Reorder a dependency chain so the lowest task id is first
|
||||
@@ -460,7 +436,7 @@ class RunQueueData:
|
||||
msgs.append("\n")
|
||||
if len(valid_chains) > 10:
|
||||
msgs.append("Aborted dependency loops search after 10 matches.\n")
|
||||
raise TooManyLoops
|
||||
return msgs
|
||||
continue
|
||||
scan = False
|
||||
if revdep not in explored_deps:
|
||||
@@ -479,11 +455,8 @@ class RunQueueData:
|
||||
|
||||
explored_deps[tid] = total_deps
|
||||
|
||||
try:
|
||||
for task in tasks:
|
||||
find_chains(task, [])
|
||||
except TooManyLoops:
|
||||
pass
|
||||
for task in tasks:
|
||||
find_chains(task, [])
|
||||
|
||||
return msgs
|
||||
|
||||
@@ -608,18 +581,11 @@ class RunQueueData:
|
||||
if t in taskData[mc].taskentries:
|
||||
depends.add(t)
|
||||
|
||||
def add_mc_dependencies(mc, tid):
|
||||
mcdeps = taskData[mc].get_mcdepends()
|
||||
for dep in mcdeps:
|
||||
mcdependency = dep.split(':')
|
||||
pn = mcdependency[3]
|
||||
frommc = mcdependency[1]
|
||||
mcdep = mcdependency[2]
|
||||
deptask = mcdependency[4]
|
||||
if mc == frommc:
|
||||
fn = taskData[mcdep].build_targets[pn][0]
|
||||
newdep = '%s:%s' % (fn,deptask)
|
||||
taskData[mc].taskentries[tid].tdepends.append(newdep)
|
||||
def add_resolved_dependencies(mc, fn, tasknames, depends):
|
||||
for taskname in tasknames:
|
||||
tid = build_tid(mc, fn, taskname)
|
||||
if tid in self.runtaskentries:
|
||||
depends.add(tid)
|
||||
|
||||
for mc in taskData:
|
||||
for tid in taskData[mc].taskentries:
|
||||
@@ -637,16 +603,12 @@ class RunQueueData:
|
||||
if fn in taskData[mc].failed_fns:
|
||||
continue
|
||||
|
||||
# We add multiconfig dependencies before processing internal task deps (tdepends)
|
||||
if 'mcdepends' in task_deps and taskname in task_deps['mcdepends']:
|
||||
add_mc_dependencies(mc, tid)
|
||||
|
||||
# Resolve task internal dependencies
|
||||
#
|
||||
# e.g. addtask before X after Y
|
||||
for t in taskData[mc].taskentries[tid].tdepends:
|
||||
(depmc, depfn, deptaskname, _) = split_tid_mcfn(t)
|
||||
depends.add(build_tid(depmc, depfn, deptaskname))
|
||||
(_, depfn, deptaskname, _) = split_tid_mcfn(t)
|
||||
depends.add(build_tid(mc, depfn, deptaskname))
|
||||
|
||||
# Resolve 'deptask' dependencies
|
||||
#
|
||||
@@ -711,106 +673,57 @@ class RunQueueData:
|
||||
recursiveitasks[tid].append(newdep)
|
||||
|
||||
self.runtaskentries[tid].depends = depends
|
||||
# Remove all self references
|
||||
self.runtaskentries[tid].depends.discard(tid)
|
||||
|
||||
#self.dump_data()
|
||||
|
||||
self.init_progress_reporter.next_stage()
|
||||
|
||||
# Resolve recursive 'recrdeptask' dependencies (Part B)
|
||||
#
|
||||
# e.g. do_sometask[recrdeptask] = "do_someothertask"
|
||||
# (makes sure sometask runs after someothertask of all DEPENDS, RDEPENDS and intertask dependencies, recursively)
|
||||
# We need to do this separately since we need all of runtaskentries[*].depends to be complete before this is processed
|
||||
self.init_progress_reporter.next_stage(len(recursivetasks))
|
||||
extradeps = {}
|
||||
for taskcounter, tid in enumerate(recursivetasks):
|
||||
extradeps[tid] = set(self.runtaskentries[tid].depends)
|
||||
|
||||
# Generating/interating recursive lists of dependencies is painful and potentially slow
|
||||
# Precompute recursive task dependencies here by:
|
||||
# a) create a temp list of reverse dependencies (revdeps)
|
||||
# b) walk up the ends of the chains (when a given task no longer has dependencies i.e. len(deps) == 0)
|
||||
# c) combine the total list of dependencies in cumulativedeps
|
||||
# d) optimise by pre-truncating 'task' off the items in cumulativedeps (keeps items in sets lower)
|
||||
tasknames = recursivetasks[tid]
|
||||
seendeps = set()
|
||||
|
||||
def generate_recdeps(t):
|
||||
newdeps = set()
|
||||
(mc, fn, taskname, _) = split_tid_mcfn(t)
|
||||
add_resolved_dependencies(mc, fn, tasknames, newdeps)
|
||||
extradeps[tid].update(newdeps)
|
||||
seendeps.add(t)
|
||||
newdeps.add(t)
|
||||
for i in newdeps:
|
||||
if i not in self.runtaskentries:
|
||||
# Not all recipes might have the recrdeptask task as a task
|
||||
continue
|
||||
task = self.runtaskentries[i].task
|
||||
for n in self.runtaskentries[i].depends:
|
||||
if n not in seendeps:
|
||||
generate_recdeps(n)
|
||||
generate_recdeps(tid)
|
||||
|
||||
if tid in recursiveitasks:
|
||||
for dep in recursiveitasks[tid]:
|
||||
generate_recdeps(dep)
|
||||
self.init_progress_reporter.update(taskcounter)
|
||||
|
||||
# Remove circular references so that do_a[recrdeptask] = "do_a do_b" can work
|
||||
for tid in recursivetasks:
|
||||
extradeps[tid].difference_update(recursivetasksselfref)
|
||||
|
||||
revdeps = {}
|
||||
deps = {}
|
||||
cumulativedeps = {}
|
||||
for tid in self.runtaskentries:
|
||||
deps[tid] = set(self.runtaskentries[tid].depends)
|
||||
revdeps[tid] = set()
|
||||
cumulativedeps[tid] = set()
|
||||
# Generate a temp list of reverse dependencies
|
||||
for tid in self.runtaskentries:
|
||||
for dep in self.runtaskentries[tid].depends:
|
||||
revdeps[dep].add(tid)
|
||||
# Find the dependency chain endpoints
|
||||
endpoints = set()
|
||||
for tid in self.runtaskentries:
|
||||
if len(deps[tid]) == 0:
|
||||
endpoints.add(tid)
|
||||
# Iterate the chains collating dependencies
|
||||
while endpoints:
|
||||
next = set()
|
||||
for tid in endpoints:
|
||||
for dep in revdeps[tid]:
|
||||
cumulativedeps[dep].add(fn_from_tid(tid))
|
||||
cumulativedeps[dep].update(cumulativedeps[tid])
|
||||
if tid in deps[dep]:
|
||||
deps[dep].remove(tid)
|
||||
if len(deps[dep]) == 0:
|
||||
next.add(dep)
|
||||
endpoints = next
|
||||
#for tid in deps:
|
||||
# if len(deps[tid]) != 0:
|
||||
# bb.warn("Sanity test failure, dependencies left for %s (%s)" % (tid, deps[tid]))
|
||||
|
||||
# Loop here since recrdeptasks can depend upon other recrdeptasks and we have to
|
||||
# resolve these recursively until we aren't adding any further extra dependencies
|
||||
extradeps = True
|
||||
while extradeps:
|
||||
extradeps = 0
|
||||
for tid in recursivetasks:
|
||||
tasknames = recursivetasks[tid]
|
||||
|
||||
totaldeps = set(self.runtaskentries[tid].depends)
|
||||
if tid in recursiveitasks:
|
||||
totaldeps.update(recursiveitasks[tid])
|
||||
for dep in recursiveitasks[tid]:
|
||||
if dep not in self.runtaskentries:
|
||||
continue
|
||||
totaldeps.update(self.runtaskentries[dep].depends)
|
||||
|
||||
deps = set()
|
||||
for dep in totaldeps:
|
||||
if dep in cumulativedeps:
|
||||
deps.update(cumulativedeps[dep])
|
||||
|
||||
for t in deps:
|
||||
for taskname in tasknames:
|
||||
newtid = t + ":" + taskname
|
||||
if newtid == tid:
|
||||
continue
|
||||
if newtid in self.runtaskentries and newtid not in self.runtaskentries[tid].depends:
|
||||
extradeps += 1
|
||||
self.runtaskentries[tid].depends.add(newtid)
|
||||
|
||||
# Handle recursive tasks which depend upon other recursive tasks
|
||||
deps = set()
|
||||
for dep in self.runtaskentries[tid].depends.intersection(recursivetasks):
|
||||
deps.update(self.runtaskentries[dep].depends.difference(self.runtaskentries[tid].depends))
|
||||
for newtid in deps:
|
||||
for taskname in tasknames:
|
||||
if not newtid.endswith(":" + taskname):
|
||||
continue
|
||||
if newtid in self.runtaskentries:
|
||||
extradeps += 1
|
||||
self.runtaskentries[tid].depends.add(newtid)
|
||||
|
||||
bb.debug(1, "Added %s recursive dependencies in this loop" % extradeps)
|
||||
|
||||
# Remove recrdeptask circular references so that do_a[recrdeptask] = "do_a do_b" can work
|
||||
for tid in recursivetasksselfref:
|
||||
self.runtaskentries[tid].depends.difference_update(recursivetasksselfref)
|
||||
task = self.runtaskentries[tid].task
|
||||
# Add in extra dependencies
|
||||
if tid in extradeps:
|
||||
self.runtaskentries[tid].depends = extradeps[tid]
|
||||
# Remove all self references
|
||||
if tid in self.runtaskentries[tid].depends:
|
||||
logger.debug(2, "Task %s contains self reference!", tid)
|
||||
self.runtaskentries[tid].depends.remove(tid)
|
||||
|
||||
self.init_progress_reporter.next_stage()
|
||||
|
||||
@@ -885,57 +798,30 @@ class RunQueueData:
|
||||
#
|
||||
# Once all active tasks are marked, prune the ones we don't need.
|
||||
|
||||
delcount = {}
|
||||
delcount = 0
|
||||
for tid in list(self.runtaskentries.keys()):
|
||||
if tid not in runq_build:
|
||||
delcount[tid] = self.runtaskentries[tid]
|
||||
del self.runtaskentries[tid]
|
||||
|
||||
# Handle --runall
|
||||
if self.cooker.configuration.runall:
|
||||
# re-run the mark_active and then drop unused tasks from new list
|
||||
runq_build = {}
|
||||
|
||||
for task in self.cooker.configuration.runall:
|
||||
runall_tids = set()
|
||||
for tid in list(self.runtaskentries):
|
||||
wanttid = fn_from_tid(tid) + ":do_%s" % task
|
||||
if wanttid in delcount:
|
||||
self.runtaskentries[wanttid] = delcount[wanttid]
|
||||
if wanttid in self.runtaskentries:
|
||||
runall_tids.add(wanttid)
|
||||
|
||||
for tid in list(runall_tids):
|
||||
mark_active(tid,1)
|
||||
|
||||
for tid in list(self.runtaskentries.keys()):
|
||||
if tid not in runq_build:
|
||||
delcount[tid] = self.runtaskentries[tid]
|
||||
del self.runtaskentries[tid]
|
||||
|
||||
if len(self.runtaskentries) == 0:
|
||||
bb.msg.fatal("RunQueue", "Could not find any tasks with the tasknames %s to run within the recipes of the taskgraphs of the targets %s" % (str(self.cooker.configuration.runall), str(self.targets)))
|
||||
delcount += 1
|
||||
|
||||
self.init_progress_reporter.next_stage()
|
||||
|
||||
# Handle runonly
|
||||
if self.cooker.configuration.runonly:
|
||||
if self.cooker.configuration.runall is not None:
|
||||
runall = "do_%s" % self.cooker.configuration.runall
|
||||
runall_tids = { k: v for k, v in self.runtaskentries.items() if taskname_from_tid(k) == runall }
|
||||
|
||||
# re-run the mark_active and then drop unused tasks from new list
|
||||
runq_build = {}
|
||||
|
||||
for task in self.cooker.configuration.runonly:
|
||||
runonly_tids = { k: v for k, v in self.runtaskentries.items() if taskname_from_tid(k) == "do_%s" % task }
|
||||
|
||||
for tid in list(runonly_tids):
|
||||
mark_active(tid,1)
|
||||
for tid in list(runall_tids):
|
||||
mark_active(tid,1)
|
||||
|
||||
for tid in list(self.runtaskentries.keys()):
|
||||
if tid not in runq_build:
|
||||
delcount[tid] = self.runtaskentries[tid]
|
||||
del self.runtaskentries[tid]
|
||||
delcount += 1
|
||||
|
||||
if len(self.runtaskentries) == 0:
|
||||
bb.msg.fatal("RunQueue", "Could not find any tasks with the tasknames %s to run within the taskgraphs of the targets %s" % (str(self.cooker.configuration.runonly), str(self.targets)))
|
||||
bb.msg.fatal("RunQueue", "No remaining tasks to run for build target %s with runall %s" % (target, runall))
|
||||
|
||||
#
|
||||
# Step D - Sanity checks and computation
|
||||
@@ -948,7 +834,7 @@ class RunQueueData:
|
||||
else:
|
||||
bb.msg.fatal("RunQueue", "No active tasks and not in --continue mode?! Please report this bug.")
|
||||
|
||||
logger.verbose("Pruned %s inactive tasks, %s left", len(delcount), len(self.runtaskentries))
|
||||
logger.verbose("Pruned %s inactive tasks, %s left", delcount, len(self.runtaskentries))
|
||||
|
||||
logger.verbose("Assign Weightings")
|
||||
|
||||
@@ -1076,7 +962,7 @@ class RunQueueData:
|
||||
msg += "\n%s has unique rprovides:\n %s" % (provfn, "\n ".join(rprovide_results[provfn] - commonrprovs))
|
||||
|
||||
if self.warn_multi_bb:
|
||||
logger.verbnote(msg)
|
||||
logger.warning(msg)
|
||||
else:
|
||||
logger.error(msg)
|
||||
|
||||
@@ -1084,7 +970,7 @@ class RunQueueData:
|
||||
|
||||
# Create a whitelist usable by the stamp checks
|
||||
self.stampfnwhitelist = {}
|
||||
for mc in self.taskData:
|
||||
for mc in self.taskData:
|
||||
self.stampfnwhitelist[mc] = []
|
||||
for entry in self.stampwhitelist.split():
|
||||
if entry not in self.taskData[mc].build_targets:
|
||||
@@ -1116,7 +1002,7 @@ class RunQueueData:
|
||||
bb.debug(1, "Task %s is marked nostamp, cannot invalidate this task" % taskname)
|
||||
else:
|
||||
logger.verbose("Invalidate task %s, %s", taskname, fn)
|
||||
bb.parse.siggen.invalidate_task(taskname, self.dataCaches[mc], taskfn)
|
||||
bb.parse.siggen.invalidate_task(taskname, self.dataCaches[mc], fn)
|
||||
|
||||
self.init_progress_reporter.next_stage()
|
||||
|
||||
@@ -1156,21 +1042,18 @@ class RunQueueData:
|
||||
if len(self.runtaskentries[tid].depends - dealtwith) == 0:
|
||||
dealtwith.add(tid)
|
||||
todeal.remove(tid)
|
||||
self.prepare_task_hash(tid)
|
||||
procdep = []
|
||||
for dep in self.runtaskentries[tid].depends:
|
||||
procdep.append(fn_from_tid(dep) + "." + taskname_from_tid(dep))
|
||||
(mc, fn, taskname, taskfn) = split_tid_mcfn(tid)
|
||||
self.runtaskentries[tid].hash = bb.parse.siggen.get_taskhash(taskfn, taskname, procdep, self.dataCaches[mc])
|
||||
task = self.runtaskentries[tid].task
|
||||
|
||||
bb.parse.siggen.writeout_file_checksum_cache()
|
||||
|
||||
#self.dump_data()
|
||||
return len(self.runtaskentries)
|
||||
|
||||
def prepare_task_hash(self, tid):
|
||||
procdep = []
|
||||
for dep in self.runtaskentries[tid].depends:
|
||||
procdep.append(fn_from_tid(dep) + "." + taskname_from_tid(dep))
|
||||
(mc, fn, taskname, taskfn) = split_tid_mcfn(tid)
|
||||
self.runtaskentries[tid].hash = bb.parse.siggen.get_taskhash(taskfn, taskname, procdep, self.dataCaches[mc])
|
||||
self.runtaskentries[tid].unihash = bb.parse.siggen.get_unihash(taskfn + "." + taskname)
|
||||
|
||||
def dump_data(self):
|
||||
"""
|
||||
Dump some debug information on the internal data structures
|
||||
@@ -1222,23 +1105,28 @@ class RunQueue:
|
||||
if fakeroot:
|
||||
magic = magic + "beef"
|
||||
mcdata = self.cooker.databuilder.mcdata[mc]
|
||||
fakerootcmd = shlex.split(mcdata.getVar("FAKEROOTCMD"))
|
||||
fakerootcmd = mcdata.getVar("FAKEROOTCMD")
|
||||
fakerootenv = (mcdata.getVar("FAKEROOTBASEENV") or "").split()
|
||||
env = os.environ.copy()
|
||||
for key, value in (var.split('=') for var in fakerootenv):
|
||||
env[key] = value
|
||||
worker = subprocess.Popen(fakerootcmd + ["bitbake-worker", magic], stdout=subprocess.PIPE, stdin=subprocess.PIPE, env=env)
|
||||
worker = subprocess.Popen([fakerootcmd, "bitbake-worker", magic], stdout=subprocess.PIPE, stdin=subprocess.PIPE, env=env)
|
||||
else:
|
||||
worker = subprocess.Popen(["bitbake-worker", magic], stdout=subprocess.PIPE, stdin=subprocess.PIPE)
|
||||
bb.utils.nonblockingfd(worker.stdout)
|
||||
workerpipe = runQueuePipe(worker.stdout, None, self.cfgData, self, rqexec)
|
||||
|
||||
runqhash = {}
|
||||
for tid in self.rqdata.runtaskentries:
|
||||
runqhash[tid] = self.rqdata.runtaskentries[tid].hash
|
||||
|
||||
workerdata = {
|
||||
"taskdeps" : self.rqdata.dataCaches[mc].task_deps,
|
||||
"fakerootenv" : self.rqdata.dataCaches[mc].fakerootenv,
|
||||
"fakerootdirs" : self.rqdata.dataCaches[mc].fakerootdirs,
|
||||
"fakerootnoenv" : self.rqdata.dataCaches[mc].fakerootnoenv,
|
||||
"sigdata" : bb.parse.siggen.get_taskdata(),
|
||||
"runq_hash" : runqhash,
|
||||
"logdefaultdebug" : bb.msg.loggerDefaultDebugLevel,
|
||||
"logdefaultverbose" : bb.msg.loggerDefaultVerbose,
|
||||
"logdefaultverboselogs" : bb.msg.loggerVerboseLogs,
|
||||
@@ -1380,26 +1268,6 @@ class RunQueue:
|
||||
cache[tid] = iscurrent
|
||||
return iscurrent
|
||||
|
||||
def validate_hash(self, *, sq_fn, sq_task, sq_hash, sq_hashfn, siginfo, sq_unihash, d):
|
||||
locs = {"sq_fn" : sq_fn, "sq_task" : sq_task, "sq_hash" : sq_hash, "sq_hashfn" : sq_hashfn,
|
||||
"sq_unihash" : sq_unihash, "siginfo" : siginfo, "d" : d}
|
||||
|
||||
hashvalidate_args = ("(sq_fn, sq_task, sq_hash, sq_hashfn, d, siginfo=siginfo, sq_unihash=sq_unihash)",
|
||||
"(sq_fn, sq_task, sq_hash, sq_hashfn, d, siginfo=siginfo)",
|
||||
"(sq_fn, sq_task, sq_hash, sq_hashfn, d)")
|
||||
|
||||
for args in hashvalidate_args[:-1]:
|
||||
try:
|
||||
call = self.hashvalidate + args
|
||||
return bb.utils.better_eval(call, locs)
|
||||
except TypeError:
|
||||
continue
|
||||
|
||||
# Call the last entry without a try...catch to propagate any thrown
|
||||
# TypeError
|
||||
call = self.hashvalidate + hashvalidate_args[-1]
|
||||
return bb.utils.better_eval(call, locs)
|
||||
|
||||
def _execute_runqueue(self):
|
||||
"""
|
||||
Run the tasks in a queue prepared by rqdata.prepare()
|
||||
@@ -1433,12 +1301,6 @@ class RunQueue:
|
||||
bb.event.fire(bb.event.DepTreeGenerated(depgraph), self.cooker.data)
|
||||
|
||||
if self.state is runQueueSceneInit:
|
||||
if not self.dm_event_handler_registered:
|
||||
res = bb.event.register(self.dm_event_handler_name,
|
||||
lambda x: self.dm.check(self) if self.state in [runQueueSceneRun, runQueueRunning, runQueueCleanUp] else False,
|
||||
('bb.event.HeartbeatEvent',))
|
||||
self.dm_event_handler_registered = True
|
||||
|
||||
dump = self.cooker.configuration.dump_signatures
|
||||
if dump:
|
||||
self.rqdata.init_progress_reporter.finish()
|
||||
@@ -1455,6 +1317,11 @@ class RunQueue:
|
||||
self.rqexe = RunQueueExecuteScenequeue(self)
|
||||
|
||||
if self.state is runQueueSceneRun:
|
||||
if not self.dm_event_handler_registered:
|
||||
res = bb.event.register(self.dm_event_handler_name,
|
||||
lambda x: self.dm.check(self) if self.state in [runQueueSceneRun, runQueueRunning, runQueueCleanUp] else False,
|
||||
('bb.event.HeartbeatEvent',))
|
||||
self.dm_event_handler_registered = True
|
||||
retval = self.rqexe.execute()
|
||||
|
||||
if self.state is runQueueRunInit:
|
||||
@@ -1571,7 +1438,6 @@ class RunQueue:
|
||||
valid = []
|
||||
sq_hash = []
|
||||
sq_hashfn = []
|
||||
sq_unihash = []
|
||||
sq_fn = []
|
||||
sq_taskname = []
|
||||
sq_task = []
|
||||
@@ -1590,13 +1456,16 @@ class RunQueue:
|
||||
sq_fn.append(fn)
|
||||
sq_hashfn.append(self.rqdata.dataCaches[mc].hashfn[taskfn])
|
||||
sq_hash.append(self.rqdata.runtaskentries[tid].hash)
|
||||
sq_unihash.append(self.rqdata.runtaskentries[tid].unihash)
|
||||
sq_taskname.append(taskname)
|
||||
sq_task.append(tid)
|
||||
|
||||
valid = self.validate_hash(sq_fn=sq_fn, sq_task=sq_taskname, sq_hash=sq_hash, sq_hashfn=sq_hashfn,
|
||||
siginfo=True, sq_unihash=sq_unihash, d=self.cooker.data)
|
||||
|
||||
locs = { "sq_fn" : sq_fn, "sq_task" : sq_taskname, "sq_hash" : sq_hash, "sq_hashfn" : sq_hashfn, "d" : self.cooker.data }
|
||||
try:
|
||||
call = self.hashvalidate + "(sq_fn, sq_task, sq_hash, sq_hashfn, d, siginfo=True)"
|
||||
valid = bb.utils.better_eval(call, locs)
|
||||
# Handle version with no siginfo parameter
|
||||
except TypeError:
|
||||
call = self.hashvalidate + "(sq_fn, sq_task, sq_hash, sq_hashfn, d)"
|
||||
valid = bb.utils.better_eval(call, locs)
|
||||
for v in valid:
|
||||
valid_new.add(sq_task[v])
|
||||
|
||||
@@ -1678,7 +1547,7 @@ class RunQueue:
|
||||
matches = {k : v for k, v in iter(matches.items()) if h not in k}
|
||||
if matches:
|
||||
latestmatch = sorted(matches.keys(), key=lambda f: matches[f])[-1]
|
||||
prevh = __find_sha256__.search(latestmatch).group(0)
|
||||
prevh = __find_md5__.search(latestmatch).group(0)
|
||||
output = bb.siggen.compare_sigfiles(latestmatch, match, recursecb)
|
||||
bb.plain("\nTask %s:%s couldn't be used from the cache because:\n We need hash %s, closest matching task was %s\n " % (pn, taskname, h, prevh) + '\n '.join(output))
|
||||
|
||||
@@ -1777,10 +1646,6 @@ class RunQueueExecute:
|
||||
valid = bb.utils.better_eval(call, locs)
|
||||
return valid
|
||||
|
||||
def can_start_task(self):
|
||||
can_start = self.stats.active < self.number_tasks
|
||||
return can_start
|
||||
|
||||
class RunQueueExecuteDummy(RunQueueExecute):
|
||||
def __init__(self, rq):
|
||||
self.rq = rq
|
||||
@@ -1854,14 +1719,13 @@ class RunQueueExecuteTasks(RunQueueExecute):
|
||||
bb.build.del_stamp(taskname, self.rqdata.dataCaches[mc], taskfn)
|
||||
self.rq.scenequeue_covered.remove(tid)
|
||||
|
||||
toremove = covered_remove | self.rq.scenequeue_notcovered
|
||||
toremove = covered_remove
|
||||
for task in toremove:
|
||||
logger.debug(1, 'Not skipping task %s due to setsceneverify', task)
|
||||
while toremove:
|
||||
covered_remove = []
|
||||
for task in toremove:
|
||||
if task in self.rq.scenequeue_covered:
|
||||
removecoveredtask(task)
|
||||
removecoveredtask(task)
|
||||
for deptask in self.rqdata.runtaskentries[task].depends:
|
||||
if deptask not in self.rq.scenequeue_covered:
|
||||
continue
|
||||
@@ -1917,7 +1781,7 @@ class RunQueueExecuteTasks(RunQueueExecute):
|
||||
|
||||
def setbuildable(self, task):
|
||||
self.runq_buildable.add(task)
|
||||
self.sched.newbuildable(task)
|
||||
self.sched.newbuilable(task)
|
||||
|
||||
def task_completeoutright(self, task):
|
||||
"""
|
||||
@@ -1931,13 +1795,14 @@ class RunQueueExecuteTasks(RunQueueExecute):
|
||||
continue
|
||||
if revdep in self.runq_buildable:
|
||||
continue
|
||||
alldeps = True
|
||||
alldeps = 1
|
||||
for dep in self.rqdata.runtaskentries[revdep].depends:
|
||||
if dep not in self.runq_complete:
|
||||
alldeps = False
|
||||
break
|
||||
if alldeps:
|
||||
alldeps = 0
|
||||
if alldeps == 1:
|
||||
self.setbuildable(revdep)
|
||||
fn = fn_from_tid(revdep)
|
||||
taskname = taskname_from_tid(revdep)
|
||||
logger.debug(1, "Marking task %s as buildable", revdep)
|
||||
|
||||
def task_complete(self, task):
|
||||
@@ -1961,8 +1826,8 @@ class RunQueueExecuteTasks(RunQueueExecute):
|
||||
self.setbuildable(task)
|
||||
bb.event.fire(runQueueTaskSkipped(task, self.stats, self.rq, reason), self.cfgData)
|
||||
self.task_completeoutright(task)
|
||||
self.stats.taskSkipped()
|
||||
self.stats.taskCompleted()
|
||||
self.stats.taskSkipped()
|
||||
|
||||
def execute(self):
|
||||
"""
|
||||
@@ -2053,8 +1918,6 @@ class RunQueueExecuteTasks(RunQueueExecute):
|
||||
taskdepdata = self.build_taskdepdata(task)
|
||||
|
||||
taskdep = self.rqdata.dataCaches[mc].task_deps[taskfn]
|
||||
taskhash = self.rqdata.get_task_hash(task)
|
||||
unihash = self.rqdata.get_task_unihash(task)
|
||||
if 'fakeroot' in taskdep and taskname in taskdep['fakeroot'] and not (self.cooker.configuration.dry_run or self.rqdata.setscene_enforce):
|
||||
if not mc in self.rq.fakeworker:
|
||||
try:
|
||||
@@ -2064,17 +1927,17 @@ class RunQueueExecuteTasks(RunQueueExecute):
|
||||
self.rq.state = runQueueFailed
|
||||
self.stats.taskFailed()
|
||||
return True
|
||||
self.rq.fakeworker[mc].process.stdin.write(b"<runtask>" + pickle.dumps((taskfn, task, taskname, taskhash, unihash, False, self.cooker.collection.get_file_appends(taskfn), taskdepdata, self.rqdata.setscene_enforce)) + b"</runtask>")
|
||||
self.rq.fakeworker[mc].process.stdin.write(b"<runtask>" + pickle.dumps((taskfn, task, taskname, False, self.cooker.collection.get_file_appends(taskfn), taskdepdata, self.rqdata.setscene_enforce)) + b"</runtask>")
|
||||
self.rq.fakeworker[mc].process.stdin.flush()
|
||||
else:
|
||||
self.rq.worker[mc].process.stdin.write(b"<runtask>" + pickle.dumps((taskfn, task, taskname, taskhash, unihash, False, self.cooker.collection.get_file_appends(taskfn), taskdepdata, self.rqdata.setscene_enforce)) + b"</runtask>")
|
||||
self.rq.worker[mc].process.stdin.write(b"<runtask>" + pickle.dumps((taskfn, task, taskname, False, self.cooker.collection.get_file_appends(taskfn), taskdepdata, self.rqdata.setscene_enforce)) + b"</runtask>")
|
||||
self.rq.worker[mc].process.stdin.flush()
|
||||
|
||||
self.build_stamps[task] = bb.build.stampfile(taskname, self.rqdata.dataCaches[mc], taskfn, noextra=True)
|
||||
self.build_stamps2.append(self.build_stamps[task])
|
||||
self.runq_running.add(task)
|
||||
self.stats.taskActive()
|
||||
if self.can_start_task():
|
||||
if self.stats.active < self.number_tasks:
|
||||
return True
|
||||
|
||||
if self.stats.active > 0:
|
||||
@@ -2097,23 +1960,10 @@ class RunQueueExecuteTasks(RunQueueExecute):
|
||||
|
||||
return True
|
||||
|
||||
def filtermcdeps(self, task, deps):
|
||||
ret = set()
|
||||
mainmc = mc_from_tid(task)
|
||||
for dep in deps:
|
||||
mc = mc_from_tid(dep)
|
||||
if mc != mainmc:
|
||||
continue
|
||||
ret.add(dep)
|
||||
return ret
|
||||
|
||||
# We filter out multiconfig dependencies from taskdepdata we pass to the tasks
|
||||
# as most code can't handle them
|
||||
def build_taskdepdata(self, task):
|
||||
taskdepdata = {}
|
||||
next = self.rqdata.runtaskentries[task].depends
|
||||
next.add(task)
|
||||
next = self.filtermcdeps(task, next)
|
||||
while next:
|
||||
additional = []
|
||||
for revdep in next:
|
||||
@@ -2122,9 +1972,7 @@ class RunQueueExecuteTasks(RunQueueExecute):
|
||||
deps = self.rqdata.runtaskentries[revdep].depends
|
||||
provides = self.rqdata.dataCaches[mc].fn_provides[taskfn]
|
||||
taskhash = self.rqdata.runtaskentries[revdep].hash
|
||||
unihash = self.rqdata.runtaskentries[revdep].unihash
|
||||
deps = self.filtermcdeps(task, deps)
|
||||
taskdepdata[revdep] = [pn, taskname, fn, deps, provides, taskhash, unihash]
|
||||
taskdepdata[revdep] = [pn, taskname, fn, deps, provides, taskhash]
|
||||
for revdep2 in deps:
|
||||
if revdep2 not in taskdepdata:
|
||||
additional.append(revdep2)
|
||||
@@ -2144,7 +1992,6 @@ class RunQueueExecuteScenequeue(RunQueueExecute):
|
||||
# If we don't have any setscene functions, skip this step
|
||||
if len(self.rqdata.runq_setscene_tids) == 0:
|
||||
rq.scenequeue_covered = set()
|
||||
rq.scenequeue_notcovered = set()
|
||||
rq.state = runQueueRunInit
|
||||
return
|
||||
|
||||
@@ -2327,7 +2174,6 @@ class RunQueueExecuteScenequeue(RunQueueExecute):
|
||||
if self.rq.hashvalidate:
|
||||
sq_hash = []
|
||||
sq_hashfn = []
|
||||
sq_unihash = []
|
||||
sq_fn = []
|
||||
sq_taskname = []
|
||||
sq_task = []
|
||||
@@ -2359,16 +2205,11 @@ class RunQueueExecuteScenequeue(RunQueueExecute):
|
||||
sq_fn.append(fn)
|
||||
sq_hashfn.append(self.rqdata.dataCaches[mc].hashfn[taskfn])
|
||||
sq_hash.append(self.rqdata.runtaskentries[tid].hash)
|
||||
sq_unihash.append(self.rqdata.runtaskentries[tid].unihash)
|
||||
sq_taskname.append(taskname)
|
||||
sq_task.append(tid)
|
||||
|
||||
self.cooker.data.setVar("BB_SETSCENE_STAMPCURRENT_COUNT", len(stamppresent))
|
||||
|
||||
valid = self.rq.validate_hash(sq_fn=sq_fn, sq_task=sq_taskname, sq_hash=sq_hash, sq_hashfn=sq_hashfn,
|
||||
siginfo=False, sq_unihash=sq_unihash, d=self.cooker.data)
|
||||
|
||||
self.cooker.data.delVar("BB_SETSCENE_STAMPCURRENT_COUNT")
|
||||
call = self.rq.hashvalidate + "(sq_fn, sq_task, sq_hash, sq_hashfn, d)"
|
||||
locs = { "sq_fn" : sq_fn, "sq_task" : sq_taskname, "sq_hash" : sq_hash, "sq_hashfn" : sq_hashfn, "d" : self.cooker.data }
|
||||
valid = bb.utils.better_eval(call, locs)
|
||||
|
||||
valid_new = stamppresent
|
||||
for v in valid:
|
||||
@@ -2431,8 +2272,8 @@ class RunQueueExecuteScenequeue(RunQueueExecute):
|
||||
def task_failoutright(self, task):
|
||||
self.runq_running.add(task)
|
||||
self.runq_buildable.add(task)
|
||||
self.stats.taskSkipped()
|
||||
self.stats.taskCompleted()
|
||||
self.stats.taskSkipped()
|
||||
self.scenequeue_notcovered.add(task)
|
||||
self.scenequeue_updatecounters(task, True)
|
||||
|
||||
@@ -2440,8 +2281,8 @@ class RunQueueExecuteScenequeue(RunQueueExecute):
|
||||
self.runq_running.add(task)
|
||||
self.runq_buildable.add(task)
|
||||
self.task_completeoutright(task)
|
||||
self.stats.taskSkipped()
|
||||
self.stats.taskCompleted()
|
||||
self.stats.taskSkipped()
|
||||
|
||||
def execute(self):
|
||||
"""
|
||||
@@ -2451,7 +2292,7 @@ class RunQueueExecuteScenequeue(RunQueueExecute):
|
||||
self.rq.read_workers()
|
||||
|
||||
task = None
|
||||
if self.can_start_task():
|
||||
if self.stats.active < self.number_tasks:
|
||||
# Find the next setscene to run
|
||||
for nexttask in self.rqdata.runq_setscene_tids:
|
||||
if nexttask in self.runq_buildable and nexttask not in self.runq_running and self.stamps[nexttask] not in self.build_stamps.values():
|
||||
@@ -2497,22 +2338,20 @@ class RunQueueExecuteScenequeue(RunQueueExecute):
|
||||
taskdepdata = self.build_taskdepdata(task)
|
||||
|
||||
taskdep = self.rqdata.dataCaches[mc].task_deps[taskfn]
|
||||
taskhash = self.rqdata.get_task_hash(task)
|
||||
unihash = self.rqdata.get_task_unihash(task)
|
||||
if 'fakeroot' in taskdep and taskname in taskdep['fakeroot'] and not self.cooker.configuration.dry_run:
|
||||
if not mc in self.rq.fakeworker:
|
||||
self.rq.start_fakeworker(self, mc)
|
||||
self.rq.fakeworker[mc].process.stdin.write(b"<runtask>" + pickle.dumps((taskfn, task, taskname, taskhash, unihash, True, self.cooker.collection.get_file_appends(taskfn), taskdepdata, False)) + b"</runtask>")
|
||||
self.rq.fakeworker[mc].process.stdin.write(b"<runtask>" + pickle.dumps((taskfn, task, taskname, True, self.cooker.collection.get_file_appends(taskfn), taskdepdata, False)) + b"</runtask>")
|
||||
self.rq.fakeworker[mc].process.stdin.flush()
|
||||
else:
|
||||
self.rq.worker[mc].process.stdin.write(b"<runtask>" + pickle.dumps((taskfn, task, taskname, taskhash, unihash, True, self.cooker.collection.get_file_appends(taskfn), taskdepdata, False)) + b"</runtask>")
|
||||
self.rq.worker[mc].process.stdin.write(b"<runtask>" + pickle.dumps((taskfn, task, taskname, True, self.cooker.collection.get_file_appends(taskfn), taskdepdata, False)) + b"</runtask>")
|
||||
self.rq.worker[mc].process.stdin.flush()
|
||||
|
||||
self.build_stamps[task] = bb.build.stampfile(taskname, self.rqdata.dataCaches[mc], taskfn, noextra=True)
|
||||
self.build_stamps2.append(self.build_stamps[task])
|
||||
self.runq_running.add(task)
|
||||
self.stats.taskActive()
|
||||
if self.can_start_task():
|
||||
if self.stats.active < self.number_tasks:
|
||||
return True
|
||||
|
||||
if self.stats.active > 0:
|
||||
@@ -2569,8 +2408,7 @@ class RunQueueExecuteScenequeue(RunQueueExecute):
|
||||
deps = getsetscenedeps(revdep)
|
||||
provides = self.rqdata.dataCaches[mc].fn_provides[taskfn]
|
||||
taskhash = self.rqdata.runtaskentries[revdep].hash
|
||||
unihash = self.rqdata.runtaskentries[revdep].unihash
|
||||
taskdepdata[revdep] = [pn, taskname, fn, deps, provides, taskhash, unihash]
|
||||
taskdepdata[revdep] = [pn, taskname, fn, deps, provides, taskhash]
|
||||
for revdep2 in deps:
|
||||
if revdep2 not in taskdepdata:
|
||||
additional.append(revdep2)
|
||||
|
||||
@@ -5,5 +5,17 @@
|
||||
# Copyright (C) 2006 - 2008 Richard Purdie
|
||||
# Copyright (C) 2013 Alexandru Damian
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# 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.
|
||||
|
||||
|
||||
|
||||
@@ -3,8 +3,18 @@
|
||||
#
|
||||
# Copyright (C) 2010 Bob Foerster <robert@erafx.com>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# 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 multiprocessing.Process based server for bitbake.
|
||||
@@ -120,7 +130,6 @@ class ProcessServer(multiprocessing.Process):
|
||||
bb.utils.set_process_name("Cooker")
|
||||
|
||||
ready = []
|
||||
newconnections = []
|
||||
|
||||
self.controllersock = False
|
||||
fds = [self.sock]
|
||||
@@ -129,48 +138,37 @@ class ProcessServer(multiprocessing.Process):
|
||||
print("Entering server connection loop")
|
||||
|
||||
def disconnect_client(self, fds):
|
||||
if not self.haveui:
|
||||
return
|
||||
print("Disconnecting Client")
|
||||
if self.controllersock:
|
||||
fds.remove(self.controllersock)
|
||||
self.controllersock.close()
|
||||
self.controllersock = False
|
||||
if self.haveui:
|
||||
fds.remove(self.command_channel)
|
||||
bb.event.unregister_UIHhandler(self.event_handle, True)
|
||||
self.command_channel_reply.writer.close()
|
||||
self.event_writer.writer.close()
|
||||
self.command_channel.close()
|
||||
self.command_channel = False
|
||||
del self.event_writer
|
||||
self.lastui = time.time()
|
||||
self.cooker.clientComplete()
|
||||
self.haveui = False
|
||||
ready = select.select(fds,[],[],0)[0]
|
||||
if newconnections:
|
||||
print("Starting new client")
|
||||
conn = newconnections.pop(-1)
|
||||
fds.append(conn)
|
||||
self.controllersock = conn
|
||||
elif self.timeout is None and not ready:
|
||||
fds.remove(self.controllersock)
|
||||
fds.remove(self.command_channel)
|
||||
bb.event.unregister_UIHhandler(self.event_handle, True)
|
||||
self.command_channel_reply.writer.close()
|
||||
self.event_writer.writer.close()
|
||||
del self.event_writer
|
||||
self.controllersock.close()
|
||||
self.controllersock = False
|
||||
self.haveui = False
|
||||
self.lastui = time.time()
|
||||
self.cooker.clientComplete()
|
||||
if self.timeout is None:
|
||||
print("No timeout, exiting.")
|
||||
self.quit = True
|
||||
|
||||
while not self.quit:
|
||||
if self.sock in ready:
|
||||
while select.select([self.sock],[],[],0)[0]:
|
||||
controllersock, address = self.sock.accept()
|
||||
if self.controllersock:
|
||||
print("Queuing %s (%s)" % (str(ready), str(newconnections)))
|
||||
newconnections.append(controllersock)
|
||||
else:
|
||||
print("Accepting %s (%s)" % (str(ready), str(newconnections)))
|
||||
self.controllersock = controllersock
|
||||
fds.append(controllersock)
|
||||
self.controllersock, address = self.sock.accept()
|
||||
if self.haveui:
|
||||
print("Dropping connection attempt as we have a UI %s" % (str(ready)))
|
||||
self.controllersock.close()
|
||||
else:
|
||||
print("Accepting %s" % (str(ready)))
|
||||
fds.append(self.controllersock)
|
||||
if self.controllersock in ready:
|
||||
try:
|
||||
print("Processing Client")
|
||||
ui_fds = recvfds(self.controllersock, 3)
|
||||
print("Connecting Client")
|
||||
ui_fds = recvfds(self.controllersock, 3)
|
||||
|
||||
# Where to write events to
|
||||
writer = ConnectionWriter(ui_fds[0])
|
||||
@@ -225,8 +223,6 @@ class ProcessServer(multiprocessing.Process):
|
||||
|
||||
try:
|
||||
self.cooker.shutdown(True)
|
||||
self.cooker.notifier.stop()
|
||||
self.cooker.confignotifier.stop()
|
||||
except:
|
||||
pass
|
||||
|
||||
@@ -241,12 +237,6 @@ class ProcessServer(multiprocessing.Process):
|
||||
while not lock:
|
||||
with bb.utils.timeout(3):
|
||||
lock = bb.utils.lockfile(lockfile, shared=False, retry=False, block=True)
|
||||
if lock:
|
||||
# We hold the lock so we can remove the file (hide stale pid data)
|
||||
bb.utils.remove(lockfile)
|
||||
bb.utils.unlockfile(lock)
|
||||
return
|
||||
|
||||
if not lock:
|
||||
# Some systems may not have lsof available
|
||||
procs = None
|
||||
@@ -267,6 +257,10 @@ class ProcessServer(multiprocessing.Process):
|
||||
if procs:
|
||||
msg += ":\n%s" % str(procs)
|
||||
print(msg)
|
||||
return
|
||||
# We hold the lock so we can remove the file (hide stale pid data)
|
||||
bb.utils.remove(lockfile)
|
||||
bb.utils.unlockfile(lock)
|
||||
|
||||
def idle_commands(self, delay, fds=None):
|
||||
nextsleep = delay
|
||||
@@ -381,12 +375,11 @@ class BitBakeServer(object):
|
||||
if os.path.exists(sockname):
|
||||
os.unlink(sockname)
|
||||
|
||||
# Place the log in the builddirectory alongside the lock file
|
||||
logfile = os.path.join(os.path.dirname(self.bitbake_lock.name), "bitbake-cookerdaemon.log")
|
||||
|
||||
self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
||||
# AF_UNIX has path length issues so chdir here to workaround
|
||||
cwd = os.getcwd()
|
||||
logfile = os.path.join(cwd, "bitbake-cookerdaemon.log")
|
||||
|
||||
try:
|
||||
os.chdir(os.path.dirname(sockname))
|
||||
self.sock.bind(os.path.basename(sockname))
|
||||
@@ -399,72 +392,55 @@ class BitBakeServer(object):
|
||||
bb.daemonize.createDaemon(self._startServer, logfile)
|
||||
self.sock.close()
|
||||
self.bitbake_lock.close()
|
||||
os.close(self.readypipein)
|
||||
|
||||
ready = ConnectionReader(self.readypipe)
|
||||
r = ready.poll(5)
|
||||
if not r:
|
||||
bb.note("Bitbake server didn't start within 5 seconds, waiting for 90")
|
||||
r = ready.poll(90)
|
||||
r = ready.poll(30)
|
||||
if r:
|
||||
try:
|
||||
r = ready.get()
|
||||
except EOFError:
|
||||
# Trap the child exitting/closing the pipe and error out
|
||||
r = None
|
||||
if not r or r[0] != "r":
|
||||
r = ready.get()
|
||||
if not r or r != "ready":
|
||||
ready.close()
|
||||
bb.error("Unable to start bitbake server (%s)" % str(r))
|
||||
bb.error("Unable to start bitbake server")
|
||||
if os.path.exists(logfile):
|
||||
logstart_re = re.compile(self.start_log_format % ('([0-9]+)', '([0-9-]+ [0-9:.]+)'))
|
||||
started = False
|
||||
lines = []
|
||||
lastlines = []
|
||||
with open(logfile, "r") as f:
|
||||
for line in f:
|
||||
if started:
|
||||
lines.append(line)
|
||||
else:
|
||||
lastlines.append(line)
|
||||
res = logstart_re.match(line.rstrip())
|
||||
if res:
|
||||
ldatetime = datetime.datetime.strptime(res.group(2), self.start_log_datetime_format)
|
||||
if ldatetime >= startdatetime:
|
||||
started = True
|
||||
lines.append(line)
|
||||
if len(lastlines) > 60:
|
||||
lastlines = lastlines[-60:]
|
||||
if lines:
|
||||
if len(lines) > 60:
|
||||
bb.error("Last 60 lines of server log for this session (%s):\n%s" % (logfile, "".join(lines[-60:])))
|
||||
if len(lines) > 10:
|
||||
bb.error("Last 10 lines of server log for this session (%s):\n%s" % (logfile, "".join(lines[-10:])))
|
||||
else:
|
||||
bb.error("Server log for this session (%s):\n%s" % (logfile, "".join(lines)))
|
||||
elif lastlines:
|
||||
bb.error("Server didn't start, last 60 loglines (%s):\n%s" % (logfile, "".join(lastlines)))
|
||||
else:
|
||||
bb.error("%s doesn't exist" % logfile)
|
||||
|
||||
raise SystemExit(1)
|
||||
|
||||
ready.close()
|
||||
os.close(self.readypipein)
|
||||
|
||||
def _startServer(self):
|
||||
print(self.start_log_format % (os.getpid(), datetime.datetime.now().strftime(self.start_log_datetime_format)))
|
||||
sys.stdout.flush()
|
||||
|
||||
server = ProcessServer(self.bitbake_lock, self.sock, self.sockname)
|
||||
self.configuration.setServerRegIdleCallback(server.register_idle_function)
|
||||
os.close(self.readypipe)
|
||||
writer = ConnectionWriter(self.readypipein)
|
||||
self.cooker = bb.cooker.BBCooker(self.configuration, self.featureset)
|
||||
writer.send("r")
|
||||
writer.close()
|
||||
try:
|
||||
self.cooker = bb.cooker.BBCooker(self.configuration, self.featureset)
|
||||
writer.send("ready")
|
||||
except:
|
||||
writer.send("fail")
|
||||
raise
|
||||
finally:
|
||||
os.close(self.readypipein)
|
||||
server.cooker = self.cooker
|
||||
server.server_timeout = self.configuration.server_timeout
|
||||
server.xmlrpcinterface = self.configuration.xmlrpcinterface
|
||||
print("Started bitbake server pid %d" % os.getpid())
|
||||
sys.stdout.flush()
|
||||
|
||||
server.start()
|
||||
|
||||
def connectProcessServer(sockname, featureset):
|
||||
@@ -473,25 +449,16 @@ def connectProcessServer(sockname, featureset):
|
||||
# AF_UNIX has path length issues so chdir here to workaround
|
||||
cwd = os.getcwd()
|
||||
|
||||
try:
|
||||
os.chdir(os.path.dirname(sockname))
|
||||
sock.connect(os.path.basename(sockname))
|
||||
finally:
|
||||
os.chdir(cwd)
|
||||
|
||||
readfd = writefd = readfd1 = writefd1 = readfd2 = writefd2 = None
|
||||
eq = command_chan_recv = command_chan = None
|
||||
|
||||
sock.settimeout(10)
|
||||
|
||||
try:
|
||||
try:
|
||||
os.chdir(os.path.dirname(sockname))
|
||||
finished = False
|
||||
while not finished:
|
||||
try:
|
||||
sock.connect(os.path.basename(sockname))
|
||||
finished = True
|
||||
except IOError as e:
|
||||
if e.errno == errno.EWOULDBLOCK:
|
||||
pass
|
||||
raise
|
||||
finally:
|
||||
os.chdir(cwd)
|
||||
|
||||
# Send an fd for the remote to write events to
|
||||
readfd, writefd = os.pipe()
|
||||
@@ -520,8 +487,7 @@ def connectProcessServer(sockname, featureset):
|
||||
command_chan.close()
|
||||
for i in [writefd, readfd1, writefd2]:
|
||||
try:
|
||||
if i:
|
||||
os.close(i)
|
||||
os.close(i)
|
||||
except OSError:
|
||||
pass
|
||||
sock.close()
|
||||
|
||||
@@ -4,8 +4,18 @@
|
||||
# Copyright (C) 2006 - 2007 Michael 'Mickey' Lauer
|
||||
# Copyright (C) 2006 - 2008 Richard Purdie
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License version 2 as
|
||||
# published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
@@ -4,8 +4,18 @@
|
||||
# Copyright (C) 2006 - 2007 Michael 'Mickey' Lauer
|
||||
# Copyright (C) 2006 - 2008 Richard Purdie
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License version 2 as
|
||||
# published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
820
bitbake/lib/bb/shell.py
Normal file
820
bitbake/lib/bb/shell.py
Normal file
@@ -0,0 +1,820 @@
|
||||
# ex:ts=4:sw=4:sts=4:et
|
||||
# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
|
||||
##########################################################################
|
||||
#
|
||||
# Copyright (C) 2005-2006 Michael 'Mickey' Lauer <mickey@Vanille.de>
|
||||
# Copyright (C) 2005-2006 Vanille Media
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
##########################################################################
|
||||
#
|
||||
# Thanks to:
|
||||
# * Holger Freyther <zecke@handhelds.org>
|
||||
# * Justin Patrin <papercrane@reversefold.com>
|
||||
#
|
||||
##########################################################################
|
||||
|
||||
"""
|
||||
BitBake Shell
|
||||
|
||||
IDEAS:
|
||||
* list defined tasks per package
|
||||
* list classes
|
||||
* toggle force
|
||||
* command to reparse just one (or more) bbfile(s)
|
||||
* automatic check if reparsing is necessary (inotify?)
|
||||
* frontend for bb file manipulation
|
||||
* more shell-like features:
|
||||
- output control, i.e. pipe output into grep, sort, etc.
|
||||
- job control, i.e. bring running commands into background and foreground
|
||||
* start parsing in background right after startup
|
||||
* ncurses interface
|
||||
|
||||
PROBLEMS:
|
||||
* force doesn't always work
|
||||
* readline completion for commands with more than one parameters
|
||||
|
||||
"""
|
||||
|
||||
##########################################################################
|
||||
# Import and setup global variables
|
||||
##########################################################################
|
||||
|
||||
from __future__ import print_function
|
||||
from functools import reduce
|
||||
try:
|
||||
set
|
||||
except NameError:
|
||||
from sets import Set as set
|
||||
import sys, os, readline, socket, httplib, urllib, commands, popen2, shlex, Queue, fnmatch
|
||||
from bb import data, parse, build, cache, taskdata, runqueue, providers as Providers
|
||||
|
||||
__version__ = "0.5.3.1"
|
||||
__credits__ = """BitBake Shell Version %s (C) 2005 Michael 'Mickey' Lauer <mickey@Vanille.de>
|
||||
Type 'help' for more information, press CTRL-D to exit.""" % __version__
|
||||
|
||||
cmds = {}
|
||||
leave_mainloop = False
|
||||
last_exception = None
|
||||
cooker = None
|
||||
parsed = False
|
||||
debug = os.environ.get( "BBSHELL_DEBUG", "" )
|
||||
|
||||
##########################################################################
|
||||
# Class BitBakeShellCommands
|
||||
##########################################################################
|
||||
|
||||
class BitBakeShellCommands:
|
||||
"""This class contains the valid commands for the shell"""
|
||||
|
||||
def __init__( self, shell ):
|
||||
"""Register all the commands"""
|
||||
self._shell = shell
|
||||
for attr in BitBakeShellCommands.__dict__:
|
||||
if not attr.startswith( "_" ):
|
||||
if attr.endswith( "_" ):
|
||||
command = attr[:-1].lower()
|
||||
else:
|
||||
command = attr[:].lower()
|
||||
method = getattr( BitBakeShellCommands, attr )
|
||||
debugOut( "registering command '%s'" % command )
|
||||
# scan number of arguments
|
||||
usage = getattr( method, "usage", "" )
|
||||
if usage != "<...>":
|
||||
numArgs = len( usage.split() )
|
||||
else:
|
||||
numArgs = -1
|
||||
shell.registerCommand( command, method, numArgs, "%s %s" % ( command, usage ), method.__doc__ )
|
||||
|
||||
def _checkParsed( self ):
|
||||
if not parsed:
|
||||
print("SHELL: This command needs to parse bbfiles...")
|
||||
self.parse( None )
|
||||
|
||||
def _findProvider( self, item ):
|
||||
self._checkParsed()
|
||||
# Need to use taskData for this information
|
||||
preferred = data.getVar( "PREFERRED_PROVIDER_%s" % item, cooker.configuration.data, 1 )
|
||||
if not preferred: preferred = item
|
||||
try:
|
||||
lv, lf, pv, pf = Providers.findBestProvider(preferred, cooker.configuration.data, cooker.status)
|
||||
except KeyError:
|
||||
if item in cooker.status.providers:
|
||||
pf = cooker.status.providers[item][0]
|
||||
else:
|
||||
pf = None
|
||||
return pf
|
||||
|
||||
def alias( self, params ):
|
||||
"""Register a new name for a command"""
|
||||
new, old = params
|
||||
if not old in cmds:
|
||||
print("ERROR: Command '%s' not known" % old)
|
||||
else:
|
||||
cmds[new] = cmds[old]
|
||||
print("OK")
|
||||
alias.usage = "<alias> <command>"
|
||||
|
||||
def buffer( self, params ):
|
||||
"""Dump specified output buffer"""
|
||||
index = params[0]
|
||||
print(self._shell.myout.buffer( int( index ) ))
|
||||
buffer.usage = "<index>"
|
||||
|
||||
def buffers( self, params ):
|
||||
"""Show the available output buffers"""
|
||||
commands = self._shell.myout.bufferedCommands()
|
||||
if not commands:
|
||||
print("SHELL: No buffered commands available yet. Start doing something.")
|
||||
else:
|
||||
print("="*35, "Available Output Buffers", "="*27)
|
||||
for index, cmd in enumerate( commands ):
|
||||
print("| %s %s" % ( str( index ).ljust( 3 ), cmd ))
|
||||
print("="*88)
|
||||
|
||||
def build( self, params, cmd = "build" ):
|
||||
"""Build a providee"""
|
||||
global last_exception
|
||||
globexpr = params[0]
|
||||
self._checkParsed()
|
||||
names = globfilter( cooker.status.pkg_pn, globexpr )
|
||||
if len( names ) == 0: names = [ globexpr ]
|
||||
print("SHELL: Building %s" % ' '.join( names ))
|
||||
|
||||
td = taskdata.TaskData(cooker.configuration.abort)
|
||||
localdata = data.createCopy(cooker.configuration.data)
|
||||
data.update_data(localdata)
|
||||
data.expandKeys(localdata)
|
||||
|
||||
try:
|
||||
tasks = []
|
||||
for name in names:
|
||||
td.add_provider(localdata, cooker.status, name)
|
||||
providers = td.get_provider(name)
|
||||
|
||||
if len(providers) == 0:
|
||||
raise Providers.NoProvider
|
||||
|
||||
tasks.append([name, "do_%s" % cmd])
|
||||
|
||||
td.add_unresolved(localdata, cooker.status)
|
||||
|
||||
rq = runqueue.RunQueue(cooker, localdata, cooker.status, td, tasks)
|
||||
rq.prepare_runqueue()
|
||||
rq.execute_runqueue()
|
||||
|
||||
except Providers.NoProvider:
|
||||
print("ERROR: No Provider")
|
||||
last_exception = Providers.NoProvider
|
||||
|
||||
except runqueue.TaskFailure as fnids:
|
||||
last_exception = runqueue.TaskFailure
|
||||
|
||||
except build.FuncFailed as e:
|
||||
print("ERROR: Couldn't build '%s'" % names)
|
||||
last_exception = e
|
||||
|
||||
|
||||
build.usage = "<providee>"
|
||||
|
||||
def clean( self, params ):
|
||||
"""Clean a providee"""
|
||||
self.build( params, "clean" )
|
||||
clean.usage = "<providee>"
|
||||
|
||||
def compile( self, params ):
|
||||
"""Execute 'compile' on a providee"""
|
||||
self.build( params, "compile" )
|
||||
compile.usage = "<providee>"
|
||||
|
||||
def configure( self, params ):
|
||||
"""Execute 'configure' on a providee"""
|
||||
self.build( params, "configure" )
|
||||
configure.usage = "<providee>"
|
||||
|
||||
def install( self, params ):
|
||||
"""Execute 'install' on a providee"""
|
||||
self.build( params, "install" )
|
||||
install.usage = "<providee>"
|
||||
|
||||
def edit( self, params ):
|
||||
"""Call $EDITOR on a providee"""
|
||||
name = params[0]
|
||||
bbfile = self._findProvider( name )
|
||||
if bbfile is not None:
|
||||
os.system( "%s %s" % ( os.environ.get( "EDITOR", "vi" ), bbfile ) )
|
||||
else:
|
||||
print("ERROR: Nothing provides '%s'" % name)
|
||||
edit.usage = "<providee>"
|
||||
|
||||
def environment( self, params ):
|
||||
"""Dump out the outer BitBake environment"""
|
||||
cooker.showEnvironment()
|
||||
|
||||
def exit_( self, params ):
|
||||
"""Leave the BitBake Shell"""
|
||||
debugOut( "setting leave_mainloop to true" )
|
||||
global leave_mainloop
|
||||
leave_mainloop = True
|
||||
|
||||
def fetch( self, params ):
|
||||
"""Fetch a providee"""
|
||||
self.build( params, "fetch" )
|
||||
fetch.usage = "<providee>"
|
||||
|
||||
def fileBuild( self, params, cmd = "build" ):
|
||||
"""Parse and build a .bb file"""
|
||||
global last_exception
|
||||
name = params[0]
|
||||
bf = completeFilePath( name )
|
||||
print("SHELL: Calling '%s' on '%s'" % ( cmd, bf ))
|
||||
|
||||
try:
|
||||
cooker.buildFile(bf, cmd)
|
||||
except parse.ParseError:
|
||||
print("ERROR: Unable to open or parse '%s'" % bf)
|
||||
except build.FuncFailed as e:
|
||||
print("ERROR: Couldn't build '%s'" % name)
|
||||
last_exception = e
|
||||
|
||||
fileBuild.usage = "<bbfile>"
|
||||
|
||||
def fileClean( self, params ):
|
||||
"""Clean a .bb file"""
|
||||
self.fileBuild( params, "clean" )
|
||||
fileClean.usage = "<bbfile>"
|
||||
|
||||
def fileEdit( self, params ):
|
||||
"""Call $EDITOR on a .bb file"""
|
||||
name = params[0]
|
||||
os.system( "%s %s" % ( os.environ.get( "EDITOR", "vi" ), completeFilePath( name ) ) )
|
||||
fileEdit.usage = "<bbfile>"
|
||||
|
||||
def fileRebuild( self, params ):
|
||||
"""Rebuild (clean & build) a .bb file"""
|
||||
self.fileBuild( params, "rebuild" )
|
||||
fileRebuild.usage = "<bbfile>"
|
||||
|
||||
def fileReparse( self, params ):
|
||||
"""(re)Parse a bb file"""
|
||||
bbfile = params[0]
|
||||
print("SHELL: Parsing '%s'" % bbfile)
|
||||
parse.update_mtime( bbfile )
|
||||
cooker.parser.reparse(bbfile)
|
||||
if False: #fromCache:
|
||||
print("SHELL: File has not been updated, not reparsing")
|
||||
else:
|
||||
print("SHELL: Parsed")
|
||||
fileReparse.usage = "<bbfile>"
|
||||
|
||||
def abort( self, params ):
|
||||
"""Toggle abort task execution flag (see bitbake -k)"""
|
||||
cooker.configuration.abort = not cooker.configuration.abort
|
||||
print("SHELL: Abort Flag is now '%s'" % repr( cooker.configuration.abort ))
|
||||
|
||||
def force( self, params ):
|
||||
"""Toggle force task execution flag (see bitbake -f)"""
|
||||
cooker.configuration.force = not cooker.configuration.force
|
||||
print("SHELL: Force Flag is now '%s'" % repr( cooker.configuration.force ))
|
||||
|
||||
def help( self, params ):
|
||||
"""Show a comprehensive list of commands and their purpose"""
|
||||
print("="*30, "Available Commands", "="*30)
|
||||
for cmd in sorted(cmds):
|
||||
function, numparams, usage, helptext = cmds[cmd]
|
||||
print("| %s | %s" % (usage.ljust(30), helptext))
|
||||
print("="*78)
|
||||
|
||||
def lastError( self, params ):
|
||||
"""Show the reason or log that was produced by the last BitBake event exception"""
|
||||
if last_exception is None:
|
||||
print("SHELL: No Errors yet (Phew)...")
|
||||
else:
|
||||
reason, event = last_exception.args
|
||||
print("SHELL: Reason for the last error: '%s'" % reason)
|
||||
if ':' in reason:
|
||||
msg, filename = reason.split( ':' )
|
||||
filename = filename.strip()
|
||||
print("SHELL: Dumping log file for last error:")
|
||||
try:
|
||||
print(open( filename ).read())
|
||||
except IOError:
|
||||
print("ERROR: Couldn't open '%s'" % filename)
|
||||
|
||||
def match( self, params ):
|
||||
"""Dump all files or providers matching a glob expression"""
|
||||
what, globexpr = params
|
||||
if what == "files":
|
||||
self._checkParsed()
|
||||
for key in globfilter( cooker.status.pkg_fn, globexpr ): print(key)
|
||||
elif what == "providers":
|
||||
self._checkParsed()
|
||||
for key in globfilter( cooker.status.pkg_pn, globexpr ): print(key)
|
||||
else:
|
||||
print("Usage: match %s" % self.print_.usage)
|
||||
match.usage = "<files|providers> <glob>"
|
||||
|
||||
def new( self, params ):
|
||||
"""Create a new .bb file and open the editor"""
|
||||
dirname, filename = params
|
||||
packages = '/'.join( data.getVar( "BBFILES", cooker.configuration.data, 1 ).split('/')[:-2] )
|
||||
fulldirname = "%s/%s" % ( packages, dirname )
|
||||
|
||||
if not os.path.exists( fulldirname ):
|
||||
print("SHELL: Creating '%s'" % fulldirname)
|
||||
os.mkdir( fulldirname )
|
||||
if os.path.exists( fulldirname ) and os.path.isdir( fulldirname ):
|
||||
if os.path.exists( "%s/%s" % ( fulldirname, filename ) ):
|
||||
print("SHELL: ERROR: %s/%s already exists" % ( fulldirname, filename ))
|
||||
return False
|
||||
print("SHELL: Creating '%s/%s'" % ( fulldirname, filename ))
|
||||
newpackage = open( "%s/%s" % ( fulldirname, filename ), "w" )
|
||||
print("""DESCRIPTION = ""
|
||||
SECTION = ""
|
||||
AUTHOR = ""
|
||||
HOMEPAGE = ""
|
||||
MAINTAINER = ""
|
||||
LICENSE = "GPL"
|
||||
PR = "r0"
|
||||
|
||||
SRC_URI = ""
|
||||
|
||||
#inherit base
|
||||
|
||||
#do_configure() {
|
||||
#
|
||||
#}
|
||||
|
||||
#do_compile() {
|
||||
#
|
||||
#}
|
||||
|
||||
#do_stage() {
|
||||
#
|
||||
#}
|
||||
|
||||
#do_install() {
|
||||
#
|
||||
#}
|
||||
""", file=newpackage)
|
||||
newpackage.close()
|
||||
os.system( "%s %s/%s" % ( os.environ.get( "EDITOR" ), fulldirname, filename ) )
|
||||
new.usage = "<directory> <filename>"
|
||||
|
||||
def package( self, params ):
|
||||
"""Execute 'package' on a providee"""
|
||||
self.build( params, "package" )
|
||||
package.usage = "<providee>"
|
||||
|
||||
def pasteBin( self, params ):
|
||||
"""Send a command + output buffer to the pastebin at http://rafb.net/paste"""
|
||||
index = params[0]
|
||||
contents = self._shell.myout.buffer( int( index ) )
|
||||
sendToPastebin( "output of " + params[0], contents )
|
||||
pasteBin.usage = "<index>"
|
||||
|
||||
def pasteLog( self, params ):
|
||||
"""Send the last event exception error log (if there is one) to http://rafb.net/paste"""
|
||||
if last_exception is None:
|
||||
print("SHELL: No Errors yet (Phew)...")
|
||||
else:
|
||||
reason, event = last_exception.args
|
||||
print("SHELL: Reason for the last error: '%s'" % reason)
|
||||
if ':' in reason:
|
||||
msg, filename = reason.split( ':' )
|
||||
filename = filename.strip()
|
||||
print("SHELL: Pasting log file to pastebin...")
|
||||
|
||||
file = open( filename ).read()
|
||||
sendToPastebin( "contents of " + filename, file )
|
||||
|
||||
def patch( self, params ):
|
||||
"""Execute 'patch' command on a providee"""
|
||||
self.build( params, "patch" )
|
||||
patch.usage = "<providee>"
|
||||
|
||||
def parse( self, params ):
|
||||
"""(Re-)parse .bb files and calculate the dependency graph"""
|
||||
cooker.status = cache.CacheData(cooker.caches_array)
|
||||
ignore = data.getVar("ASSUME_PROVIDED", cooker.configuration.data, 1) or ""
|
||||
cooker.status.ignored_dependencies = set( ignore.split() )
|
||||
cooker.handleCollections( data.getVar("BBFILE_COLLECTIONS", cooker.configuration.data, 1) )
|
||||
|
||||
(filelist, masked) = cooker.collect_bbfiles()
|
||||
cooker.parse_bbfiles(filelist, masked, cooker.myProgressCallback)
|
||||
cooker.buildDepgraph()
|
||||
global parsed
|
||||
parsed = True
|
||||
print()
|
||||
|
||||
def reparse( self, params ):
|
||||
"""(re)Parse a providee's bb file"""
|
||||
bbfile = self._findProvider( params[0] )
|
||||
if bbfile is not None:
|
||||
print("SHELL: Found bbfile '%s' for '%s'" % ( bbfile, params[0] ))
|
||||
self.fileReparse( [ bbfile ] )
|
||||
else:
|
||||
print("ERROR: Nothing provides '%s'" % params[0])
|
||||
reparse.usage = "<providee>"
|
||||
|
||||
def getvar( self, params ):
|
||||
"""Dump the contents of an outer BitBake environment variable"""
|
||||
var = params[0]
|
||||
value = data.getVar( var, cooker.configuration.data, 1 )
|
||||
print(value)
|
||||
getvar.usage = "<variable>"
|
||||
|
||||
def peek( self, params ):
|
||||
"""Dump contents of variable defined in providee's metadata"""
|
||||
name, var = params
|
||||
bbfile = self._findProvider( name )
|
||||
if bbfile is not None:
|
||||
the_data = cache.Cache.loadDataFull(bbfile, cooker.configuration.data)
|
||||
value = the_data.getVar( var, 1 )
|
||||
print(value)
|
||||
else:
|
||||
print("ERROR: Nothing provides '%s'" % name)
|
||||
peek.usage = "<providee> <variable>"
|
||||
|
||||
def poke( self, params ):
|
||||
"""Set contents of variable defined in providee's metadata"""
|
||||
name, var, value = params
|
||||
bbfile = self._findProvider( name )
|
||||
if bbfile is not None:
|
||||
print("ERROR: Sorry, this functionality is currently broken")
|
||||
#d = cooker.pkgdata[bbfile]
|
||||
#data.setVar( var, value, d )
|
||||
|
||||
# mark the change semi persistant
|
||||
#cooker.pkgdata.setDirty(bbfile, d)
|
||||
#print "OK"
|
||||
else:
|
||||
print("ERROR: Nothing provides '%s'" % name)
|
||||
poke.usage = "<providee> <variable> <value>"
|
||||
|
||||
def print_( self, params ):
|
||||
"""Dump all files or providers"""
|
||||
what = params[0]
|
||||
if what == "files":
|
||||
self._checkParsed()
|
||||
for key in cooker.status.pkg_fn: print(key)
|
||||
elif what == "providers":
|
||||
self._checkParsed()
|
||||
for key in cooker.status.providers: print(key)
|
||||
else:
|
||||
print("Usage: print %s" % self.print_.usage)
|
||||
print_.usage = "<files|providers>"
|
||||
|
||||
def python( self, params ):
|
||||
"""Enter the expert mode - an interactive BitBake Python Interpreter"""
|
||||
sys.ps1 = "EXPERT BB>>> "
|
||||
sys.ps2 = "EXPERT BB... "
|
||||
import code
|
||||
interpreter = code.InteractiveConsole( dict( globals() ) )
|
||||
interpreter.interact( "SHELL: Expert Mode - BitBake Python %s\nType 'help' for more information, press CTRL-D to switch back to BBSHELL." % sys.version )
|
||||
|
||||
def showdata( self, params ):
|
||||
"""Execute 'showdata' on a providee"""
|
||||
cooker.showEnvironment(None, params)
|
||||
showdata.usage = "<providee>"
|
||||
|
||||
def setVar( self, params ):
|
||||
"""Set an outer BitBake environment variable"""
|
||||
var, value = params
|
||||
data.setVar( var, value, cooker.configuration.data )
|
||||
print("OK")
|
||||
setVar.usage = "<variable> <value>"
|
||||
|
||||
def rebuild( self, params ):
|
||||
"""Clean and rebuild a .bb file or a providee"""
|
||||
self.build( params, "clean" )
|
||||
self.build( params, "build" )
|
||||
rebuild.usage = "<providee>"
|
||||
|
||||
def shell( self, params ):
|
||||
"""Execute a shell command and dump the output"""
|
||||
if params != "":
|
||||
print(commands.getoutput( " ".join( params ) ))
|
||||
shell.usage = "<...>"
|
||||
|
||||
def stage( self, params ):
|
||||
"""Execute 'stage' on a providee"""
|
||||
self.build( params, "populate_staging" )
|
||||
stage.usage = "<providee>"
|
||||
|
||||
def status( self, params ):
|
||||
"""<just for testing>"""
|
||||
print("-" * 78)
|
||||
print("building list = '%s'" % cooker.building_list)
|
||||
print("build path = '%s'" % cooker.build_path)
|
||||
print("consider_msgs_cache = '%s'" % cooker.consider_msgs_cache)
|
||||
print("build stats = '%s'" % cooker.stats)
|
||||
if last_exception is not None: print("last_exception = '%s'" % repr( last_exception.args ))
|
||||
print("memory output contents = '%s'" % self._shell.myout._buffer)
|
||||
|
||||
def test( self, params ):
|
||||
"""<just for testing>"""
|
||||
print("testCommand called with '%s'" % params)
|
||||
|
||||
def unpack( self, params ):
|
||||
"""Execute 'unpack' on a providee"""
|
||||
self.build( params, "unpack" )
|
||||
unpack.usage = "<providee>"
|
||||
|
||||
def which( self, params ):
|
||||
"""Computes the providers for a given providee"""
|
||||
# Need to use taskData for this information
|
||||
item = params[0]
|
||||
|
||||
self._checkParsed()
|
||||
|
||||
preferred = data.getVar( "PREFERRED_PROVIDER_%s" % item, cooker.configuration.data, 1 )
|
||||
if not preferred: preferred = item
|
||||
|
||||
try:
|
||||
lv, lf, pv, pf = Providers.findBestProvider(preferred, cooker.configuration.data, cooker.status)
|
||||
except KeyError:
|
||||
lv, lf, pv, pf = (None,)*4
|
||||
|
||||
try:
|
||||
providers = cooker.status.providers[item]
|
||||
except KeyError:
|
||||
print("SHELL: ERROR: Nothing provides", preferred)
|
||||
else:
|
||||
for provider in providers:
|
||||
if provider == pf: provider = " (***) %s" % provider
|
||||
else: provider = " %s" % provider
|
||||
print(provider)
|
||||
which.usage = "<providee>"
|
||||
|
||||
##########################################################################
|
||||
# Common helper functions
|
||||
##########################################################################
|
||||
|
||||
def completeFilePath( bbfile ):
|
||||
"""Get the complete bbfile path"""
|
||||
if not cooker.status: return bbfile
|
||||
if not cooker.status.pkg_fn: return bbfile
|
||||
for key in cooker.status.pkg_fn:
|
||||
if key.endswith( bbfile ):
|
||||
return key
|
||||
return bbfile
|
||||
|
||||
def sendToPastebin( desc, content ):
|
||||
"""Send content to http://oe.pastebin.com"""
|
||||
mydata = {}
|
||||
mydata["lang"] = "Plain Text"
|
||||
mydata["desc"] = desc
|
||||
mydata["cvt_tabs"] = "No"
|
||||
mydata["nick"] = "%s@%s" % ( os.environ.get( "USER", "unknown" ), socket.gethostname() or "unknown" )
|
||||
mydata["text"] = content
|
||||
params = urllib.urlencode( mydata )
|
||||
headers = {"Content-type": "application/x-www-form-urlencoded", "Accept": "text/plain"}
|
||||
|
||||
host = "rafb.net"
|
||||
conn = httplib.HTTPConnection( "%s:80" % host )
|
||||
conn.request("POST", "/paste/paste.php", params, headers )
|
||||
|
||||
response = conn.getresponse()
|
||||
conn.close()
|
||||
|
||||
if response.status == 302:
|
||||
location = response.getheader( "location" ) or "unknown"
|
||||
print("SHELL: Pasted to http://%s%s" % ( host, location ))
|
||||
else:
|
||||
print("ERROR: %s %s" % ( response.status, response.reason ))
|
||||
|
||||
def completer( text, state ):
|
||||
"""Return a possible readline completion"""
|
||||
debugOut( "completer called with text='%s', state='%d'" % ( text, state ) )
|
||||
|
||||
if state == 0:
|
||||
line = readline.get_line_buffer()
|
||||
if " " in line:
|
||||
line = line.split()
|
||||
# we are in second (or more) argument
|
||||
if line[0] in cmds and hasattr( cmds[line[0]][0], "usage" ): # known command and usage
|
||||
u = getattr( cmds[line[0]][0], "usage" ).split()[0]
|
||||
if u == "<variable>":
|
||||
allmatches = cooker.configuration.data.keys()
|
||||
elif u == "<bbfile>":
|
||||
if cooker.status.pkg_fn is None: allmatches = [ "(No Matches Available. Parsed yet?)" ]
|
||||
else: allmatches = [ x.split("/")[-1] for x in cooker.status.pkg_fn ]
|
||||
elif u == "<providee>":
|
||||
if cooker.status.pkg_fn is None: allmatches = [ "(No Matches Available. Parsed yet?)" ]
|
||||
else: allmatches = cooker.status.providers.iterkeys()
|
||||
else: allmatches = [ "(No tab completion available for this command)" ]
|
||||
else: allmatches = [ "(No tab completion available for this command)" ]
|
||||
else:
|
||||
# we are in first argument
|
||||
allmatches = cmds.iterkeys()
|
||||
|
||||
completer.matches = [ x for x in allmatches if x[:len(text)] == text ]
|
||||
#print "completer.matches = '%s'" % completer.matches
|
||||
if len( completer.matches ) > state:
|
||||
return completer.matches[state]
|
||||
else:
|
||||
return None
|
||||
|
||||
def debugOut( text ):
|
||||
if debug:
|
||||
sys.stderr.write( "( %s )\n" % text )
|
||||
|
||||
def columnize( alist, width = 80 ):
|
||||
"""
|
||||
A word-wrap function that preserves existing line breaks
|
||||
and most spaces in the text. Expects that existing line
|
||||
breaks are posix newlines (\n).
|
||||
"""
|
||||
return reduce(lambda line, word, width=width: '%s%s%s' %
|
||||
(line,
|
||||
' \n'[(len(line[line.rfind('\n')+1:])
|
||||
+ len(word.split('\n', 1)[0]
|
||||
) >= width)],
|
||||
word),
|
||||
alist
|
||||
)
|
||||
|
||||
def globfilter( names, pattern ):
|
||||
return fnmatch.filter( names, pattern )
|
||||
|
||||
##########################################################################
|
||||
# Class MemoryOutput
|
||||
##########################################################################
|
||||
|
||||
class MemoryOutput:
|
||||
"""File-like output class buffering the output of the last 10 commands"""
|
||||
def __init__( self, delegate ):
|
||||
self.delegate = delegate
|
||||
self._buffer = []
|
||||
self.text = []
|
||||
self._command = None
|
||||
|
||||
def startCommand( self, command ):
|
||||
self._command = command
|
||||
self.text = []
|
||||
def endCommand( self ):
|
||||
if self._command is not None:
|
||||
if len( self._buffer ) == 10: del self._buffer[0]
|
||||
self._buffer.append( ( self._command, self.text ) )
|
||||
def removeLast( self ):
|
||||
if self._buffer:
|
||||
del self._buffer[ len( self._buffer ) - 1 ]
|
||||
self.text = []
|
||||
self._command = None
|
||||
def lastBuffer( self ):
|
||||
if self._buffer:
|
||||
return self._buffer[ len( self._buffer ) -1 ][1]
|
||||
def bufferedCommands( self ):
|
||||
return [ cmd for cmd, output in self._buffer ]
|
||||
def buffer( self, i ):
|
||||
if i < len( self._buffer ):
|
||||
return "BB>> %s\n%s" % ( self._buffer[i][0], "".join( self._buffer[i][1] ) )
|
||||
else: return "ERROR: Invalid buffer number. Buffer needs to be in (0, %d)" % ( len( self._buffer ) - 1 )
|
||||
def write( self, text ):
|
||||
if self._command is not None and text != "BB>> ": self.text.append( text )
|
||||
if self.delegate is not None: self.delegate.write( text )
|
||||
def flush( self ):
|
||||
return self.delegate.flush()
|
||||
def fileno( self ):
|
||||
return self.delegate.fileno()
|
||||
def isatty( self ):
|
||||
return self.delegate.isatty()
|
||||
|
||||
##########################################################################
|
||||
# Class BitBakeShell
|
||||
##########################################################################
|
||||
|
||||
class BitBakeShell:
|
||||
|
||||
def __init__( self ):
|
||||
"""Register commands and set up readline"""
|
||||
self.commandQ = Queue.Queue()
|
||||
self.commands = BitBakeShellCommands( self )
|
||||
self.myout = MemoryOutput( sys.stdout )
|
||||
self.historyfilename = os.path.expanduser( "~/.bbsh_history" )
|
||||
self.startupfilename = os.path.expanduser( "~/.bbsh_startup" )
|
||||
|
||||
readline.set_completer( completer )
|
||||
readline.set_completer_delims( " " )
|
||||
readline.parse_and_bind("tab: complete")
|
||||
|
||||
try:
|
||||
readline.read_history_file( self.historyfilename )
|
||||
except IOError:
|
||||
pass # It doesn't exist yet.
|
||||
|
||||
print(__credits__)
|
||||
|
||||
def cleanup( self ):
|
||||
"""Write readline history and clean up resources"""
|
||||
debugOut( "writing command history" )
|
||||
try:
|
||||
readline.write_history_file( self.historyfilename )
|
||||
except:
|
||||
print("SHELL: Unable to save command history")
|
||||
|
||||
def registerCommand( self, command, function, numparams = 0, usage = "", helptext = "" ):
|
||||
"""Register a command"""
|
||||
if usage == "": usage = command
|
||||
if helptext == "": helptext = function.__doc__ or "<not yet documented>"
|
||||
cmds[command] = ( function, numparams, usage, helptext )
|
||||
|
||||
def processCommand( self, command, params ):
|
||||
"""Process a command. Check number of params and print a usage string, if appropriate"""
|
||||
debugOut( "processing command '%s'..." % command )
|
||||
try:
|
||||
function, numparams, usage, helptext = cmds[command]
|
||||
except KeyError:
|
||||
print("SHELL: ERROR: '%s' command is not a valid command." % command)
|
||||
self.myout.removeLast()
|
||||
else:
|
||||
if (numparams != -1) and (not len( params ) == numparams):
|
||||
print("Usage: '%s'" % usage)
|
||||
return
|
||||
|
||||
result = function( self.commands, params )
|
||||
debugOut( "result was '%s'" % result )
|
||||
|
||||
def processStartupFile( self ):
|
||||
"""Read and execute all commands found in $HOME/.bbsh_startup"""
|
||||
if os.path.exists( self.startupfilename ):
|
||||
startupfile = open( self.startupfilename, "r" )
|
||||
for cmdline in startupfile:
|
||||
debugOut( "processing startup line '%s'" % cmdline )
|
||||
if not cmdline:
|
||||
continue
|
||||
if "|" in cmdline:
|
||||
print("ERROR: '|' in startup file is not allowed. Ignoring line")
|
||||
continue
|
||||
self.commandQ.put( cmdline.strip() )
|
||||
|
||||
def main( self ):
|
||||
"""The main command loop"""
|
||||
while not leave_mainloop:
|
||||
try:
|
||||
if self.commandQ.empty():
|
||||
sys.stdout = self.myout.delegate
|
||||
cmdline = raw_input( "BB>> " )
|
||||
sys.stdout = self.myout
|
||||
else:
|
||||
cmdline = self.commandQ.get()
|
||||
if cmdline:
|
||||
allCommands = cmdline.split( ';' )
|
||||
for command in allCommands:
|
||||
pipecmd = None
|
||||
#
|
||||
# special case for expert mode
|
||||
if command == 'python':
|
||||
sys.stdout = self.myout.delegate
|
||||
self.processCommand( command, "" )
|
||||
sys.stdout = self.myout
|
||||
else:
|
||||
self.myout.startCommand( command )
|
||||
if '|' in command: # disable output
|
||||
command, pipecmd = command.split( '|' )
|
||||
delegate = self.myout.delegate
|
||||
self.myout.delegate = None
|
||||
tokens = shlex.split( command, True )
|
||||
self.processCommand( tokens[0], tokens[1:] or "" )
|
||||
self.myout.endCommand()
|
||||
if pipecmd is not None: # restore output
|
||||
self.myout.delegate = delegate
|
||||
|
||||
pipe = popen2.Popen4( pipecmd )
|
||||
pipe.tochild.write( "\n".join( self.myout.lastBuffer() ) )
|
||||
pipe.tochild.close()
|
||||
sys.stdout.write( pipe.fromchild.read() )
|
||||
#
|
||||
except EOFError:
|
||||
print()
|
||||
return
|
||||
except KeyboardInterrupt:
|
||||
print()
|
||||
|
||||
##########################################################################
|
||||
# Start function - called from the BitBake command line utility
|
||||
##########################################################################
|
||||
|
||||
def start( aCooker ):
|
||||
global cooker
|
||||
cooker = aCooker
|
||||
bbshell = BitBakeShell()
|
||||
bbshell.processStartupFile()
|
||||
bbshell.main()
|
||||
bbshell.cleanup()
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("SHELL: Sorry, this program should only be called by BitBake.")
|
||||
@@ -1,7 +1,3 @@
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
#
|
||||
|
||||
import hashlib
|
||||
import logging
|
||||
import os
|
||||
@@ -45,9 +41,6 @@ class SignatureGenerator(object):
|
||||
def finalise(self, fn, d, varient):
|
||||
return
|
||||
|
||||
def get_unihash(self, task):
|
||||
return self.taskhash[task]
|
||||
|
||||
def get_taskhash(self, fn, task, deps, dataCache):
|
||||
return "0"
|
||||
|
||||
@@ -94,7 +87,7 @@ class SignatureGeneratorBasic(SignatureGenerator):
|
||||
self.taints = {}
|
||||
self.gendeps = {}
|
||||
self.lookupcache = {}
|
||||
self.pkgnameextract = re.compile(r"(?P<fn>.*)\..*")
|
||||
self.pkgnameextract = re.compile("(?P<fn>.*)\..*")
|
||||
self.basewhitelist = set((data.getVar("BB_HASHBASE_WHITELIST") or "").split())
|
||||
self.taskwhitelist = None
|
||||
self.init_rundepcheck(data)
|
||||
@@ -117,13 +110,42 @@ class SignatureGeneratorBasic(SignatureGenerator):
|
||||
ignore_mismatch = ((d.getVar("BB_HASH_IGNORE_MISMATCH") or '') == '1')
|
||||
tasklist, gendeps, lookupcache = bb.data.generate_dependencies(d)
|
||||
|
||||
taskdeps, basehash = bb.data.generate_dependency_hash(tasklist, gendeps, lookupcache, self.basewhitelist, fn)
|
||||
taskdeps = {}
|
||||
basehash = {}
|
||||
|
||||
for task in tasklist:
|
||||
data = lookupcache[task]
|
||||
|
||||
if data is None:
|
||||
bb.error("Task %s from %s seems to be empty?!" % (task, fn))
|
||||
data = ''
|
||||
|
||||
gendeps[task] -= self.basewhitelist
|
||||
newdeps = gendeps[task]
|
||||
seen = set()
|
||||
while newdeps:
|
||||
nextdeps = newdeps
|
||||
seen |= nextdeps
|
||||
newdeps = set()
|
||||
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:
|
||||
data = data + dep
|
||||
var = lookupcache[dep]
|
||||
if var is not None:
|
||||
data = data + str(var)
|
||||
datahash = hashlib.md5(data.encode("utf-8")).hexdigest()
|
||||
k = fn + "." + task
|
||||
if not ignore_mismatch and k in self.basehash and self.basehash[k] != basehash[k]:
|
||||
bb.error("When reparsing %s, the basehash value changed from %s to %s. The metadata is not deterministic and this needs to be fixed." % (k, self.basehash[k], basehash[k]))
|
||||
self.basehash[k] = basehash[k]
|
||||
if not ignore_mismatch and k in self.basehash and self.basehash[k] != datahash:
|
||||
bb.error("When reparsing %s, the basehash value changed from %s to %s. The metadata is not deterministic and this needs to be fixed." % (k, self.basehash[k], datahash))
|
||||
self.basehash[k] = datahash
|
||||
taskdeps[task] = alldeps
|
||||
|
||||
self.taskdeps[fn] = taskdeps
|
||||
self.gendeps[fn] = gendeps
|
||||
@@ -171,31 +193,20 @@ class SignatureGeneratorBasic(SignatureGenerator):
|
||||
return taint
|
||||
|
||||
def get_taskhash(self, fn, task, deps, dataCache):
|
||||
|
||||
mc = ''
|
||||
if fn.startswith('multiconfig:'):
|
||||
mc = fn.split(':')[1]
|
||||
k = fn + "." + task
|
||||
|
||||
data = dataCache.basetaskhash[k]
|
||||
self.basehash[k] = data
|
||||
self.runtaskdeps[k] = []
|
||||
self.file_checksum_values[k] = []
|
||||
recipename = dataCache.pkg_fn[fn]
|
||||
|
||||
for dep in sorted(deps, key=clean_basepath):
|
||||
pkgname = self.pkgnameextract.search(dep).group('fn')
|
||||
if mc:
|
||||
depmc = pkgname.split(':')[1]
|
||||
if mc != depmc:
|
||||
continue
|
||||
if dep.startswith("multiconfig:") and not mc:
|
||||
continue
|
||||
depname = dataCache.pkg_fn[pkgname]
|
||||
depname = dataCache.pkg_fn[self.pkgnameextract.search(dep).group('fn')]
|
||||
if not self.rundep_check(fn, recipename, task, dep, depname, dataCache):
|
||||
continue
|
||||
if dep not in self.taskhash:
|
||||
bb.fatal("%s is not in taskhash, caller isn't calling in dependency order?" % dep)
|
||||
data = data + self.get_unihash(dep)
|
||||
bb.fatal("%s is not in taskhash, caller isn't calling in dependency order?", dep)
|
||||
data = data + self.taskhash[dep]
|
||||
self.runtaskdeps[k].append(dep)
|
||||
|
||||
if task in dataCache.file_checksums[fn]:
|
||||
@@ -222,7 +233,7 @@ class SignatureGeneratorBasic(SignatureGenerator):
|
||||
self.taints[k] = taint
|
||||
logger.warning("%s is tainted from a forced run" % k)
|
||||
|
||||
h = hashlib.sha256(data.encode("utf-8")).hexdigest()
|
||||
h = hashlib.md5(data.encode("utf-8")).hexdigest()
|
||||
self.taskhash[k] = h
|
||||
#d.setVar("BB_TASKHASH_task-%s" % task, taskhash[task])
|
||||
return h
|
||||
@@ -270,7 +281,7 @@ class SignatureGeneratorBasic(SignatureGenerator):
|
||||
data['file_checksum_values'] = [(os.path.basename(f), cs) for f,cs in self.file_checksum_values[k]]
|
||||
data['runtaskhashes'] = {}
|
||||
for dep in data['runtaskdeps']:
|
||||
data['runtaskhashes'][dep] = self.get_unihash(dep)
|
||||
data['runtaskhashes'][dep] = self.taskhash[dep]
|
||||
data['taskhash'] = self.taskhash[k]
|
||||
|
||||
taint = self.read_taint(fn, task, referencestamp)
|
||||
@@ -320,13 +331,6 @@ class SignatureGeneratorBasic(SignatureGenerator):
|
||||
class SignatureGeneratorBasicHash(SignatureGeneratorBasic):
|
||||
name = "basichash"
|
||||
|
||||
def get_stampfile_hash(self, task):
|
||||
if task in self.taskhash:
|
||||
return self.taskhash[task]
|
||||
|
||||
# If task is not in basehash, then error
|
||||
return self.basehash[task]
|
||||
|
||||
def stampfile(self, stampbase, fn, taskname, extrainfo, clean=False):
|
||||
if taskname != "do_setscene" and taskname.endswith("_setscene"):
|
||||
k = fn + "." + taskname[:-9]
|
||||
@@ -334,14 +338,16 @@ class SignatureGeneratorBasicHash(SignatureGeneratorBasic):
|
||||
k = fn + "." + taskname
|
||||
if clean:
|
||||
h = "*"
|
||||
elif k in self.taskhash:
|
||||
h = self.taskhash[k]
|
||||
else:
|
||||
h = self.get_stampfile_hash(k)
|
||||
|
||||
# If k is not in basehash, then error
|
||||
h = self.basehash[k]
|
||||
return ("%s.%s.%s.%s" % (stampbase, taskname, h, extrainfo)).rstrip('.')
|
||||
|
||||
def stampcleanmask(self, stampbase, fn, taskname, extrainfo):
|
||||
return self.stampfile(stampbase, fn, taskname, extrainfo, clean=True)
|
||||
|
||||
|
||||
def invalidate_task(self, task, d, fn):
|
||||
bb.note("Tainting hash to force rebuild of task %s, %s" % (fn, task))
|
||||
bb.build.write_taint(task, d, fn)
|
||||
@@ -356,10 +362,10 @@ def dump_this_task(outfile, d):
|
||||
def init_colors(enable_color):
|
||||
"""Initialise colour dict for passing to compare_sigfiles()"""
|
||||
# First set up the colours
|
||||
colors = {'color_title': '\033[1m',
|
||||
'color_default': '\033[0m',
|
||||
'color_add': '\033[0;32m',
|
||||
'color_remove': '\033[0;31m',
|
||||
colors = {'color_title': '\033[1;37;40m',
|
||||
'color_default': '\033[0;37;40m',
|
||||
'color_add': '\033[1;32;40m',
|
||||
'color_remove': '\033[1;31;40m',
|
||||
}
|
||||
# Leave all keys present but clear the values
|
||||
if not enable_color:
|
||||
@@ -630,7 +636,7 @@ def compare_sigfiles(a, b, recursecb=None, color=False, collapsed=False):
|
||||
if collapsed:
|
||||
output.extend(recout)
|
||||
else:
|
||||
# If a dependent hash changed, might as well print the line above and then defer to the changes in
|
||||
# If a dependent hash changed, might as well print the line above and then defer to the changes in
|
||||
# that hash since in all likelyhood, they're the same changes this task also saw.
|
||||
output = [output[-1]] + recout
|
||||
|
||||
@@ -656,7 +662,7 @@ def calc_basehash(sigdata):
|
||||
if val is not None:
|
||||
basedata = basedata + str(val)
|
||||
|
||||
return hashlib.sha256(basedata.encode("utf-8")).hexdigest()
|
||||
return hashlib.md5(basedata.encode("utf-8")).hexdigest()
|
||||
|
||||
def calc_taskhash(sigdata):
|
||||
data = sigdata['basehash']
|
||||
@@ -674,7 +680,7 @@ def calc_taskhash(sigdata):
|
||||
else:
|
||||
data = data + sigdata['taint']
|
||||
|
||||
return hashlib.sha256(data.encode("utf-8")).hexdigest()
|
||||
return hashlib.md5(data.encode("utf-8")).hexdigest()
|
||||
|
||||
|
||||
def dump_sigfile(a):
|
||||
|
||||
@@ -10,8 +10,18 @@ Task data collection and handling
|
||||
|
||||
# Copyright (C) 2006 Richard Purdie
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# 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 logging
|
||||
import re
|
||||
@@ -60,8 +70,6 @@ class TaskData:
|
||||
|
||||
self.skiplist = skiplist
|
||||
|
||||
self.mcdepends = []
|
||||
|
||||
def add_tasks(self, fn, dataCache):
|
||||
"""
|
||||
Add tasks for a given fn to the database
|
||||
@@ -80,13 +88,6 @@ class TaskData:
|
||||
|
||||
self.add_extra_deps(fn, dataCache)
|
||||
|
||||
def add_mcdepends(task):
|
||||
for dep in task_deps['mcdepends'][task].split():
|
||||
if len(dep.split(':')) != 5:
|
||||
bb.msg.fatal("TaskData", "Error for %s:%s[%s], multiconfig dependency %s does not contain exactly four ':' characters.\n Task '%s' should be specified in the form 'multiconfig:fromMC:toMC:packagename:task'" % (fn, task, 'mcdepends', dep, 'mcdepends'))
|
||||
if dep not in self.mcdepends:
|
||||
self.mcdepends.append(dep)
|
||||
|
||||
# Common code for dep_name/depends = 'depends'/idepends and 'rdepends'/irdepends
|
||||
def handle_deps(task, dep_name, depends, seen):
|
||||
if dep_name in task_deps and task in task_deps[dep_name]:
|
||||
@@ -109,20 +110,16 @@ class TaskData:
|
||||
parentids = []
|
||||
for dep in task_deps['parents'][task]:
|
||||
if dep not in task_deps['tasks']:
|
||||
bb.debug(2, "Not adding dependency of %s on %s since %s does not exist" % (task, dep, dep))
|
||||
bb.debug(2, "Not adding dependeny of %s on %s since %s does not exist" % (task, dep, dep))
|
||||
continue
|
||||
parentid = "%s:%s" % (fn, dep)
|
||||
parentids.append(parentid)
|
||||
self.taskentries[tid].tdepends.extend(parentids)
|
||||
|
||||
|
||||
# Touch all intertask dependencies
|
||||
handle_deps(task, 'depends', self.taskentries[tid].idepends, self.seen_build_target)
|
||||
handle_deps(task, 'rdepends', self.taskentries[tid].irdepends, self.seen_run_target)
|
||||
|
||||
if 'mcdepends' in task_deps and task in task_deps['mcdepends']:
|
||||
add_mcdepends(task)
|
||||
|
||||
# Work out build dependencies
|
||||
if not fn in self.depids:
|
||||
dependids = set()
|
||||
@@ -540,9 +537,6 @@ class TaskData:
|
||||
provmap[name] = provider[0]
|
||||
return provmap
|
||||
|
||||
def get_mcdepends(self):
|
||||
return self.mcdepends
|
||||
|
||||
def dump_data(self):
|
||||
"""
|
||||
Dump some debug information on the internal data structures
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user