Full Code of WindRiver-Labs/wrlinux-x for AI

WRLINUX_10_21_BASE 1bccf8827e6b cached
89 files
460.4 KB
118.1k tokens
197 symbols
1 requests
Download .txt
Showing preview only (487K chars total). Download the full file or copy to clipboard to get everything.
Repository: WindRiver-Labs/wrlinux-x
Branch: WRLINUX_10_21_BASE
Commit: 1bccf8827e6b
Files: 89
Total size: 460.4 KB

Directory structure:
gitextract_d8ghdmvu/

├── .gitignore
├── EULA
├── LICENSE
├── README.md
├── bin/
│   ├── .pylintrc
│   ├── LICENSE.texttable
│   ├── Makefile
│   ├── argparse_setup.py
│   ├── argparse_wrl.py
│   ├── branch_mirror.py
│   ├── dump_layer_dependencies.py
│   ├── dump_layer_rev.py
│   ├── flatten_mirror.py
│   ├── layer_index.py
│   ├── logger_setup.py
│   ├── sanity.py
│   ├── settings.py
│   ├── setup.py
│   ├── test-network.py
│   ├── texttable.py
│   ├── toaster_fixture.py
│   ├── transform_index.py
│   ├── utils_setup.py
│   └── windshare.py
├── data/
│   ├── environment.d/
│   │   ├── 00_check_repo.sh
│   │   ├── 00_wrl_eula.sh
│   │   ├── 01_wrl_buildtools.sh
│   │   ├── 02_wrl_anspass.sh
│   │   ├── 03_wrl_askpass.sh
│   │   ├── 04_wrl_buildtools.sh
│   │   ├── 05_wrl_anspass.sh
│   │   ├── 06_wrl_repo.sh
│   │   ├── 07_toaster_update.sh
│   │   ├── check_update.sh
│   │   ├── kernel_type.sh
│   │   ├── setup_anspass
│   │   ├── setup_askpass
│   │   ├── setup_ssh
│   │   └── setup_utils
│   ├── local_layer/
│   │   ├── README
│   │   ├── classes/
│   │   │   └── .keepme
│   │   ├── conf/
│   │   │   └── layer.conf
│   │   ├── downloads/
│   │   │   └── .keepme
│   │   ├── git/
│   │   │   └── .keepme
│   │   ├── recipes-sample/
│   │   │   └── hello/
│   │   │       ├── hello/
│   │   │       │   └── hello.c
│   │   │       └── hello_1.0.bb
│   │   └── scripts/
│   │       └── .keepme
│   ├── samples/
│   │   ├── README-MIRROR.sample
│   │   ├── README.sample
│   │   ├── bblayers.conf.sample
│   │   ├── conf-notes.sample
│   │   ├── local.conf.sample
│   │   └── site.conf.sample
│   └── xml/
│       ├── axxiaarm-dl.xml
│       ├── bitbake.inc
│       ├── intel-socfpga-dl.xml
│       ├── meta-anaconda-dl.xml
│       ├── meta-cgl-common-dl.xml
│       ├── meta-clang-dl.xml
│       ├── meta-cloud-services-dl-3-3.xml
│       ├── meta-dpdk-dl.xml
│       ├── meta-efi-secure-boot-dl.xml
│       ├── meta-encrypted-storage-dl.xml
│       ├── meta-freescale-dl.xml
│       ├── meta-ids-dl.xml
│       ├── meta-integrity-dl.xml
│       ├── meta-intel-dl.xml
│       ├── meta-iot-cloud-dl.xml
│       ├── meta-openembedded-dl-3-3.xml
│       ├── meta-qt5-dl.xml
│       ├── meta-raspberrypi-dl.xml
│       ├── meta-realtime-dl-3-3.xml
│       ├── meta-security-compliance-dl.xml
│       ├── meta-selinux-dl.xml
│       ├── meta-signing-key-dl.xml
│       ├── meta-tensorflow-dl-3-3.xml
│       ├── meta-tpm-dl.xml
│       ├── meta-tpm2-dl.xml
│       ├── meta-virtualization-dl-3-3.xml
│       ├── nxp-imx7.xml
│       ├── nxp-s32g2xx-dl.xml
│       ├── oe-core-dl-3-3.xml
│       ├── openembedded-core.inc
│       ├── ti-j72xx-dl.xml
│       ├── wr-ostree-dl.xml
│       ├── wrlinux-dl.xml
│       ├── wrlinux.xml
│       └── xilinx-zynqmp-dl.xml
└── setup.sh

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
buildtools.git
*.pyc
bin/.venv
*.pyo
/*.patch
*.swp
*.orig
*.rej
*~


================================================
FILE: EULA
================================================
                         WIND RIVER LINUX PLATFORM
                         SOFTWARE LICENSE AGREEMENT

This Wind River Linux Platform Software License Agreement (the 
"Agreement"), is made between Wind River Systems, Inc. ("Wind River"), 
on the one hand, and the individual accessing or using the Software or 
any single legal entity on behalf of which such individual is acting 
("Customer"), on the other hand.  The effective date of this Agreement 
is the earlier of the date that you accept this Agreement or the date 
that Wind River makes the Products available to you ("Effective Date").

PLEASE READ THIS AGREEMENT CAREFULLY BEFORE DOWNLOADING, ACCESSING, 
INSTALLING OR USING THE PRODUCTS.  BY CLICKING ON THE "I ACCEPT" BUTTON 
YOU: ACKNOWLEDGE THAT YOU HAVE READ AND UNDERSTAND THIS AGREEMENT, 
AGREE TO BE BOUND BY ITS TERMS AND CONDITIONS, AND WARRANT YOU HAVE 
AUTHORITY TO ENTER INTO THIS AGREEMENT.  IF YOU ARE ACTING ON BEHALF OF 
AN ENTITY, YOU REPRESENT THAT YOU HAVE THE AUTHORITY TO ENTER INTO THIS 
AGREEMENT ON BEHALF OF THAT ENTITY.  IF YOU DO NOT ACCEPT THE TERMS OF 
THIS AGREEMENT, THEN YOU MUST NOT USE THE PRODUCTS AND SERVICES AND YOU 
MUST UNINSTALL AND RETURN THE PRODUCT TO WIND RIVER WITHIN TEN (10) 
DAYS.

IF YOU ARE EVALUATING THE PRODUCT, THE TERMS SPECIFIED IN APPENDIX B 
SHALL APPLY IN ADDITION OF THE TERMS OF THE AGREEMENT AND APPENDIX A.
  
________________________________________________________________________

The parties agree as follows:

1. SCOPE. This framework Agreement governs Wind River's provision to 
Customer of the Products and Services as detailed in the Quote or 
Exhibit. Terms in initial capitalized letters, not defined elsewhere in 
this Agreement, have the meanings set forth in Section 12 (Definitions).

2. LICENSE. Each program, component or application included in the 
Software may be governed by one or more Open Source License(s), as 
specified or referenced in the respective Source Code files.  Without 
limiting the foregoing, for the convenience of Customer, Wind River will 
make available, upon request, applicable licensing information in the 
Linux Foundation's SPDX(R) format. Tools provided to Customer shall be 
licensed under the terms of the attached Appendix A, which is hereby 
incorporated by reference into this Agreement.  

3. SERVICES.
3.1. Support. Customer's payment of the applicable fees entitles 
Customer to Support during the License Term. Support is provided in 
accordance with the terms of Wind River's then current Software Support 
and Maintenance Agreement, which terms are hereby incorporated by 
reference into this Agreement. A copy of the curr ent Software Support 
and Maintenance Agreement can be accessed through Wind River's website: 
http://www.windriver.com/support/SupportTerms.pdf


3.2. Professional Services. Professional services, if included in a 
signed statement of work, will be provided at additional cost and 
subject to Wind River's then current Professional Services Terms and 
Conditions, which terms are hereby incorporated by reference into this 
Agreement. A copy of the current Professional Services Terms and 
Conditions can be accessed through Wind River's website: 
http://windriver.com/services/ProductAgreementServicesAttachment.pdf
 
3.3. Education and Training. Education and training services (e.g., 
mentoring, live or remote classes, etc.), if included in the Quote or 
Exhibit will be provided pursuant to Wind River's then current Education 
Services terms and conditions, which terms are hereby incorporated by 
reference into this Agreement. A copy of the current Education Services 
terms and conditions can be accessed through Wind River's website: 
http://education.windriver.com/content/public/resources/Supplemental_Education_Services_Terms_and_Conditions.pdf

4. CONFIDENTIAL INFORMATION. Customer will not use or disclose any 
Confidential Information, except as expressly authorized by this 
Agreement, and will protect all such Confidential Information using the 
same degree of care that Customer uses with respect to its own 
proprietary information, but in no event less than reasonable care. If 
Confidential Information must be disclosed to a third party by reason of 
legal, accounting or regulatory requirements beyond the reasonable 
control of Customer, Customer will: (i) assert the confidential nature 
of the information in the action or proceeding; (ii) promptly notify 
Wind River of the order or request; and (iii) permit Wind River (at its 
own expense) to seek an appropriate protective order.

5. TERM AND TERMINATION.  
5.1. Term.  The term of this Agreement will commence upon the Effective 
Date and continue until expiration of the License Term unless earlier 
terminated as set forth herein. The renewal date for all Products and 
Services hereunder will be the last day of the applicable License Term, 
regardless of whether Customer chooses to license additional Products 
during such License Term. Customer must notify Wind River at least 
thirty (30) days prior to the end of the License Term of its request to 
renew its subscription. Unless the parties mutually agree to renew the 
subscription, and Customer pays the then-applicable fees, Customer's 
license to the Tools and entitlement to Support will terminate on the 
last day of the then-current License Term.

5.2. Termination. Either party may terminate this Agreement immediately 
upon notice for the material breach of the other party, which breach is 
curable and has remained uncured for a period of thirty (30) days from 
the date of notice. In addition, Wind River may immediately terminate 
this Agreement if Customer is delinquent on its payment obligations for 
thirty (30) days or more.

5.3. Consequences of Expiration or Termination. Upon expiration of the 
License Term or termination of this Agreement, Customer will: (a) not 
use the Tools for any purpose whatsoever; (b) no longer be entitled to 
receive or have access to Support or other Services; (c) immediately 
destroy or return to Wind River all material belonging to Wind River or 
its licensors, including, without limitation, all Confidential 
Information of Wind River then in Customer's possession; and (d) 
promptly certify to Wind River in writing that Customer has completed 
the actions described in the foregoing subsections. These remedies will 
be cumulative and in addition to any other remedies available to Wind 
River. Sections 4, 5, 6, 7, 8, 9, 10, 11 and 12 will survive expiration 
or termination of this Agreement.

6. DELIVERY, PAYMENT AND TAXES.
6.1. Delivery and Payment Terms.
6.1.1. The Product will be deemed irrevocably accepted upon shipment. 
When Product is made available to Customer for electronic download 
through access to a website and/or server, shipment will be deemed to 
have occurred at the time of such availability.
6.1.2. Customer will pay Wind River the fees set forth in the applicable 
Exhibit or Quote.  Wind River will invoice Customer the applicable fees 
upon receipt of a correctly issued purchase order from Customer, which 
may coincide with shipment of the Software or Tools. Payment terms 
herein are subject to prior credit approval by Wind River. Customer will 
pay all invoices within thirty (30) days of the date of such invoice in 
U.S. dollars unless otherwise set forth in the applicable Exhibit or 
Quote. Interest on late payments will accrue at the rate of one and 
one-half percent (1.5%) per month or partial month, or, if lower, the 
highest rate permitted by law.  Customer is responsible for reasonable 
costs associated with collection of overdue amounts, including without 
limitation, reasonable attorneys' fees and court costs.  Failure to pay 
any invoice in the manner described in this Section 6 may, at Wind 
River's discretion, be deemed a material breach of this Agreement.
6.1.3. If Products or Services are purchased through an authorized Wind 
River distributor, Customer will be invoiced directly by such 
distributor (and not Wind River), and Customer will pay the distributor 
the applicable fees in accordance with the payment terms agreed to 
between Customer and the distributor.

6.2. Purchase Orders. Unless Products or Services are purchased through 
an authorized Wind River distributor, Customer will submit to Wind River 
a purchase order in the amount specified in the corresponding Exhibit or 
Quote. Any additional or different terms and conditions on the purchase 
order will be of no force or effect. Wind River may reject any purchase 
order that Wind River determines to be outside the scope of this 
Agreement.

6.3. Taxes. All amounts due hereunder will be paid without deduction, 
set-off or counter claim, free and clear of any restrictions or 
conditions, and without deduction for any taxes, levies, imposts, 
duties, fees, deductions, withholdings or other governmental charges.  
If any deduction is required to be made by law, Customer will pay the 
full amount owed to Wind River plus the amount to be deducted, so that 
Wind River will receive the same amount as it would have received had 
the deduction not been required.  If Customer is claiming sales or use 
tax exemption, a valid and fully executed Tax Exempt Certificate must be 
attached to this Agreement or the applicable Quote or Exhibit, or the 
applicable purchase order.  Customer will promptly pay or reimburse all 
taxes (exclusive of taxes on Wind River's net income), duties and 
assessments arising from amounts payable to Wind River under this 
Agreement, or furnish Wind River with evidence acceptable to the taxing 
authority to sustain exemption therefrom.

7. CUSTOMER COMPLIANCE.  Wind River or its designated representative 
will have the right to: (a) require that Customer send a written 
certification of compliance with the terms of this Agreement within 
fifteen (15) days of Wind River's request; and (b) conduct an inspection 
and audit ("Audit") upon reasonable notice of the relevant operational, 
accounting and sales books and records of Customer and any other 
information within Customer's possession or control that is reasonably 
necessary to determine whether Customer has complied with this 
Agreement, and obtain true and correct photocopies of the foregoing 
materials.  Such Audit will be conducted during regular business hours 
at Customer's offices and so as not to interfere unreasonably with 
Customer's normal business activities.  Customer will permit or provide 
for completion of any Audit within forty-five (45) days of notice.  If 
an Audit discloses any underpayment of fees, then Wind River will 
invoice Customer for, and Customer will promptly pay Wind River, the 
underpaid fee amount based on the higher of the price specified in this 
Agreement or Wind River's price list in effect at the time the audit is 
completed, together with late payment interest in accordance with 
Section 6.1 (Delivery and Payment Terms). If an Audit discloses 
underpayment of five percent (5%) or more, then Wind River will also 
invoice Customer for, and Customer will promptly pay, Wind River's 
reasonable costs of conducting the Audit.

8. LIMITED WARRANTY.

8.1. Limited Warranty. The Software is provided "AS IS". In no event 
does Wind River warrant that the Software is error free or that the 
Software will satisfy Customer's own specific requirements. Customer 
assumes full responsibility for: (a) the selection of the Product; (b) 
the proper installation and use of the Products; (c) verifying the 
results obtained from the use of the Products; and (d) taking 
appropriate measures to prevent loss of data.
    
8.2. Warranty Disclaimer.  EXCEPT AS EXPRESSLY SET FORTH IN SECTION 8.1 
ABOVE, WIND RIVER AND ITS LICENSORS DISCLAIM ALL WARRANTIES, EXPRESS, 
IMPLIED AND STATUTORY INCLUDING, WITHOUT LIMITATION, THE IMPLIED 
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE 
AND NON-INFRINGEMENT OF THIRD PARTY RIGHTS WITH RESPECT TO THE PRODUCTS 
AND SERVICES PROVIDED UNDER THIS AGREEMENT.  NO ORAL OR WRITTEN 
INFORMATION OR ADVICE GIVEN BY WIND RIVER, ITS DEALERS, DISTRIBUTORS, 
AGENTS OR EMPLOYEES WILL IN ANY WAY INCREASE THE SCOPE OF THE WARRANTIES 
PROVIDED BY WIND RIVER IN THIS AGREEMENT OR THE APPLICABLE OPEN SOURCE 
LICENSES.  WIND RIVER DOES NOT WARRANT THAT THE QUALITY OR PERFORMANCE 
OF ANY PRODUCT AND SERVICES WILL MEET CUSTOMER'S REQUIREMENTS OR THAT 
CUSTOMER WILL BE ABLE TO ACHIEVE ANY PARTICULAR RESULTS FROM USE OR 
MODIFICATION OF THE PRODUCT, OR THAT THE PRODUCT WILL OPERATE FREE FROM 
ERROR.  WIND RIVER MAKES NO WARRANTY WITH RESPECT TO ANY MALFUNCTIONS OR 
OTHER ERRORS IN ITS PRODUCTS CAUSED BY VIRUS, INFECTION, WORM OR SIMILAR 
MALICIOUS CODE NOT DEVELOPED BY WIND RIVER.  WIND RIVER MAKES NO 
WARRANTY THAT ANY PRODUCTS OF WIND RIVER WILL PROTECT AGAINST ALL 
POSSIBLE SECURITY THREATS, INCLUDING INTENTIONAL MISCONDUCT BY THIRD 
PARTIES.  WIND RIVER IS NOT LIABLE FOR ANY DOWNTIME OR SERVICE 
INTERRUPTION, FOR ANY LOST OR STOLEN DATA OR SYSTEMS, OR FOR ANY OTHER 
DAMAGES ARISING OUT OF OR RELATING TO ANY SUCH ACTIONS OR INTRUSIONS.  
Some jurisdictions do not allow the limitation or exclusion of implied 
warranties or how long an implied warranty may last, so the above 
limitations may not apply to Customer.  This warranty gives Customer 
specific legal rights and Customer may have other rights that vary from 
jurisdiction to jurisdiction.

9. CUSTOMER INDEMNITY. Customer will defend at its expense Wind River 
against any claims, suits, or proceedings brought against Wind River by 
third parties resulting from, in connection with, attributable to any 
Customer product or service incorporating or using the Software, or by 
Customer's direct or indirect end users, and will indemnify Wind River 
for any costs, losses, damages, and expenses (including reasonable legal 
fees) resulting from or in connection with such claim, suit, or 
proceeding. Customer's obligations under this Section are conditioned on 
Wind River: (a) providing Customer prompt notice of such claim, suit, or 
proceeding; (b) tendering to Customer the defense or settlement of any 
such claim, suit, or proceeding at Customer's expense; and (c) 
cooperating with Customer, at Customer's expense, in defending or 
settling such claim, suit, or proceeding.

10. LIMITATION OF LIABILITY. WIND RIVER AND ITS LICENSORS WILL NOT BE 
LIABLE TO CUSTOMER OR ANY THIRD PARTY FOR ANY LOSS OF PROFITS, REVENUE 
OR GOODWILL, COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, LOSS 
OR INTERRUPTION OF BUSINESS, LOSS OF ANTICIPATED SAVINGS, OR LOSS OF 
DATA, OR ANY INDIRECT, EXEMPLARY, PUNITIVE, SPECIAL, INCIDENTAL OR 
CONSEQUENTIAL DAMAGES OF ANY KIND, HOWEVER CAUSED AND REGARDLESS OF THE 
FORM OF ACTION, WHETHER IN CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT 
PRODUCT LIABILITY OR ANY OTHER LEGAL OR EQUITABLE THEORY, EVEN IF WIND 
RIVER HAS BEEN ADVISED OR SHOULD HAVE KNOWN OF THE POSSIBILITY OF SUCH 
DAMAGES. IN NO EVENT WILL WIND RIVER'S AGGREGATE CUMULATIVE LIABILITY 
FOR ANY CLAIMS ARISING OUT OF OR RELATED TO THIS AGREEMENT EXCEED THE 
AMOUNTS PAID TO WIND RIVER BY CUSTOMER FOR THE AFFECTED PRODUCT OR 
SERVICES PURSUANT TO THIS AGREEMENT IN THE TWELVE (12) MONTHS PRECEDING 
THE CLAIM.  Some jurisdictions do not allow the exclusion or limitation 
of incidental or consequential damages so this limitation and exclusion 
may not apply to Customer.

THE LIMITED WARRANTY, LIMITED REMEDIES, WARRANTY DISCLAIMER AND LIMITED 
LIABILITY ARE FUNDAMENTAL ELEMENTS OF THE BASIS OF THE BARGAIN BETWEEN 
WIND RIVER AND CUSTOMER. WIND RIVER WOULD NOT BE ABLE TO PROVIDE THE 
PRODUCTS OR SERVICES WITHOUT SUCH LIMITATIONS.

11. GENERAL.
11.1. Governing Law and Venue. This Agreement will be governed in all 
respects by the laws of the United States of America and the State of 
Delaware, without reference to conflict of laws principles. The United 
Nations Convention on Contracts for the International Sale of Goods is 
specifically excluded from application to to this Agreement. All 
disputes arising under this Agreement will be brought exclusively in the 
State of Delaware or of the Federal courts sitting therein, provided, 
however, that the parties will be entitled to seek injunctive relief in 
the appropriate forum. Customer consents to the personal jurisdiction of 
the above courts.
	
11.2. Export Control. All software and technical information delivered 
under this Agreement are subject to U.S. export controls under the 
Export Administration Regulations (the "EAR") or the International 
Traffic in Arms Regulations (the "ITAR") and may be subject to export, 
re-export or import regulations in other countries.  Customer agrees to 
strictly comply with all such laws and regulations. Customer will not 
export or re-export the software and technical information, directly or 
indirectly, to: (a) any countries that are subject to US export 
restrictions (currently including, but not necessarily limited to, Cuba, 
Iran, North Korea, Sudan, and Syria); (b) any end user who Customer 
knows or has reason to know will utilize them in the design, development 
or production of nuclear, chemical or biological weapons, or rocket 
systems, space launch vehicles, and sounding rockets, or unmanned air 
vehicle systems; or (c) any end user who has been prohibited from 
participating in US export transactions by any federal agency of the US 
government. Some of Wind River's products are classified as "restricted" 
encryption products under Section 740.17(b)(2) of the EAR and may not be 
exported or re-exported to government end-users (as defined in Section 
772 of the EAR) outside the countries listed in Supplement No. 3 to Part 
740 of the EAR without authorization from the U.S. government.

11.3. U.S. Government End-Users. All software and any data relating 
thereto or derived therefrom are "commercial items" as defined in 48 
C.F.R. 2.101, consisting of "commercial computer software" and 
"commercial computer software documentation" as such terms are used in 
48 C.F.R. 12.212.  If the end User is a U.S. Government agency, 
department, or instrumentality, then the use, duplication, reproduction, 
release, modification, disclosure or transfer of the Software and any 
data relating thereto or derived therefrom, is restricted in accordance 
with 48 C.F.R. 12.211, 48 C.F.R. 12.212, 48 C.F.R. 227.7102-2, and 48 
C.F.R. 227.7202, as applicable.  Customer will provide the Software to 
the U.S. Government or to U.S. Government end Users only pursuant to an 
end user license agreement in accordance with the terms of this 
Agreement. This U.S. Government end users clause is in lieu of, and 
supersedes, any Federal Acquisition Regulations ("FAR"), the Defense FAR 
Supplement ("DFARS"), or other clause or provision that addresses 
Government rights in computer software or technical data.

11.4. Notices. All notices under this Agreement will be: (a) in writing; 
(b) delivered by personal delivery or certified or registered mail, 
return receipt requested, and deemed given upon personal delivery or 
five (5) days after deposit in the mail.  Notices to Wind River will be 
sent to Wind River Systems, Inc., General Counsel, Legal Affairs, 500 
Wind River Way, Alameda, CA 94501, USA (or such other address designated 
in writing by Wind River), and notices to Customer will be sent to the 
address identified in Customer's purchase order.

11.5. Force Majeure. Neither party will be liable for any failure or 
delay (except for the payment of money) on account of strikes, 
shortages, riots, insurrection, fires, explosions, acts of God, war, 
governmental action, labor conditions, material shortages or any other 
cause which is beyond the reasonable control of such party.

11.6. Use of Customer's Name. Subject to Customer's approval, Wind River 
may identify Customer as a customer of Wind River products or services.

11.7. Assignment. Customer will not assign, transfer or delegate any 
right, license or obligation under this Agreement to a third party, 
directly or indirectly, including by operation of law or through 
bankruptcy, merger, acquisition, sale or transfer of all, substantially 
all or any part of the business or assets of Customer, or undergo a 
change of Control, without first obtaining Wind River's prior written 
consent, which Wind River may withhold in Wind River's sole discretion.  
Any purported assignment, transfer, delegation or change of Control in 
violation of this Section 11.7 (Assignment) is null and void.  Wind 
River may assign, transfer or delegate this Agreement or any right, 
license or obligation hereunder in its sole discretion.

11.8. Counterparts. In the event th is Agreement is executed with 
signatures, this Agreement may be executed in one or more counterparts, 
each of which will be deemed an original, but all of which together will 
constitute one and the same instrument. Counterparts to this Agreement 
transmitted by facsimile transmission, by electronic mail in "portable 
document format" (".pdf") form, or by any other electronic means 
intended to preserve the original graphic and pictorial appearance of a 
document, will have the same effect as a signed original of this 
Agreement.

11.9. Waiver. The failure of either party to require performance by the 
other party of any provision hereof will not affect the full right to 
require such performance at any time thereafter; nor will the waiver by 
either party of a breach of any provision hereof be taken or held to be 
a waiver of the provision itself.

11.10. Miscellaneous. This Agreement will not create any agency, 
employment relationship, partnership or other form of joint enterprise 
between the parties. This Agreement and its attachments and exhibits 
constitute the entire agreement between Customer and Wind River and 
supersedes all prior oral or written agreements between the parties with 
respect to the subject matter hereof.  The terms and conditions of any 
purchase order or other instrument issued by Customer in connection with 
this Agreement will be of no force or effect.  This Agreement may only 
be amended by a writing signed by the parties that refers explicitly to 
this Agreement.  If a provision of this Agreement is unenforceable or 
invalid, the provision will be revised so as to best accomplish the 
objectives of the parties.

12. DEFINITIONS. In addition to the terms in initial capitalized letters 
defined elsewhere in this Agreement, the following terms in initial 
capitalized letters have the respective meanings set forth below:

12.1. "Confidential Information" means information disclosed by Wind 
River to Customer, including without limitation, intellectual property, 
software programs, documentation, pricing, current, future, and proposed 
products and services, which is (a) in tangible form and bears a 
"confidential", "proprietary" or similar legend; and (b) discussions 
relating to that information whether those discussion occur prior to, 
concurrent with, or following disclosure of the information. Wind River 
shall make reasonable efforts to mark its confidential information in 
tangible form with any of the aforementioned legends prior to 
disclosure. However, Wind River's information in tangible form that does 
not bear any of these legends, and discussions relating to that 
information, shall nevertheless be protected hereunder as Confidential 
Information, if Customer knew, or should have reasonably known under the 
circumstances, that the information was confidential and had been 
communicated to it in confidence. Confidential Information does not 
include any information that Customer reasonably demonstrates is: (i) 
published or otherwise available to the public other than by breach of 
this Agreement by Customer; (ii) rightfully received by Customer from a 
third party without confidentiality limitations; (iii) independently 
developed by Customer as evidenced by appropriate records; (iv) known to 
Customer prior to its first receipt from Wind River as evidenced by 
appropriate records; (v) hereinafter disclosed by Wind River to a third 
party without restriction on disclosure; or (vi) approved for public 
release by written authorization of Wind River.

12.2. "Control" means: (a) ownership of more than fifty percent (50%) of 
the outstanding stock or securities entitled to vote for the election of 
directors or similar managing authority of the subject entity; (b) 
ownership of more than fifty percent (50%) of the ownership interest 
that represents the right to make decisions for the subject entity; (c) 
any other ability to elect more than half of the board of directors or 
similar managing authority of the subject entity, whether by contract or 
otherwise; or (d) the possession, directly or indirectly, of the power 
to direct or cause the direction of the management or policies of the 
subject entity whether through the ownership of voting securities, 
through other voting rights, by contract or otherwise.

12.3. "Exhibit" means an attachment to this Agreement that the parties 
may elect to simultaneously or separately execute from time to time, in 
addition to the Quote, detailing Products and Services to be provided to 
Customer, as well as other business restrictions associated with such 
Products and Services (e.g., Project and Development Locations).

12.4. "License Term" means the term set forth in the Quote or Exhibit or 
one (1) year commencing on the Effective Date if no term is specified.

12.5. "Object Code" means computer programming code in a form not 
readily perceivable by humans and suitable for machine execution without 
the intervening steps of interpretation or compilation. 1 2.6. "Open 
Source License" means a software license under which the Soft ware 
Object Code and/or Source Code is made available under terms that allow 
any licensee to copy, create derivative works and distribute the 
software without any fee or cost, including but not limited to any open 
source license listed by the Open Source Initiative 
(http://www.opensource.org).

12.7. "Product" means Software and Tools. 

12.8. "Quote" means the Wind River final sales quote detailing the 
Products and Services to be provided to Customer, as well as other 
business restrictions associated with such Products and Services (e.g., 
Project and Development Locations).

12.9. "Services" means those services provided by Wind River as detailed 
in the Quote, statement of work or Exhibit, and includes, but is not 
limited to Support, professional services and education services.

12.10. "Software" means the Linux operating system components (such as 
the kernel, BSPs and drivers) and any add-on profiles and other related 
software components, as specified in the Quote or Exhibit and made 
available by Wind River to Customer in Source Code or Object Code form, 
including any updates thereto and all accompanying documentation 
governed by an Open Source License. Software does not include Tools.

12.11. "Source Code" means computer programming code in human readable 
form that is not suitable for machine execution without the intervening 
steps of interpretation or compilation.

12.12. "SPDX" means the Software Package Data Exchange specification for 
communicating the components, licenses and copyrights associated with a 
software package, as developed by the Linux Foundation.

12.13. "Support" means the annual support and maintenance services 
specified in the Quote or Exhibit to be provided by Wind River in 
accordance with Section 3.1 (Support & Maintenance).

12.14. "Tools" means the proprietary Source Code and Object Code and any 
accompanying documentation provided by Wind River under this Agreement 
which is intended for Customer's internal use in accordance with the 
terms of the Tools Agreement in Addendum 1 (e.g., Wind River Workbench). 
Tools shall be deemed "Confidential Information".


                   APPENDIX A - WIND RIVER LINUX PLATFORM
                          TOOLS ADDITIONAL TERMS

1. SCOPE. These terms ("Tools Agreement") govern Customer's rights and 
obligations with respect to the Tools, as specified in the Quote or 
Exhibit. Terms in initial capitalized letters, not defined in the 
Agreement or in this Tools Agreement, have the meanings set forth in 
Section 5 (Definitions). The terms of the Agreement hereby incorporated 
by reference into this Tools Agreement. The terms of this Tools 
Agreement shall supersede any conflicting provisions of the Agreement 
for purposes of such Tools.
 
2. LICENSE GRANTS. Subject to Customer's compliance with the terms and 
conditions of this Tools Agreement and any Quote or Exhibit, and payment 
of the applicable fees, Wind River grants to Customer, during the 
License Term, a restricted, personal, non-transferable, non-exclusive, 
internal-use license:

2.1. for Floating User Development Licenses, to reproduce and use one 
(1) copy of the Tools per Development License on the Supported 
Architecture Family, solely for the number of licensed concurrent 
Floating Users located at each Development Location and specified as 
licensed for such Tools in such Exhibit or Quote;

OR

2.2. for Named User Development Licenses, to reproduce and use one (1) 
copy of the Tools per Development License on the Supported Architecture 
Family, solely for the licensed Named Users located at each Development 
Location and specified as licensed for such Tools in such Exhibit or 
Quote. Customer will use license management technology in the Tools to 
assign each Development License to a Named User and no other User may 
use the copy of the Tools designated for that Development License 
without the prior written consent of Wind River; except, however, that 
Customer may (a) transfer a Named User Development License from one 
Named User to another individual if the Named User has left Customer's 
business, and is replaced by another Named User, or (b) make legal name 
changes or network UserID changes to the Named User profile information, 
subject to notification to Wind River submitted to Wind River's email 
alias (CustomerReports@windriver.com);

OR

2.3. for Node-Lock User Development Licenses, to reproduce, access and 
use one (1) copy of the Tools per Development License, solely on the 
number of "Node-locked hosts" licensed and located at each Development 
Location and specified as licensed for such Tools in such Exhibit A or 
Quote.  For purposes of this Agreement, the "Node" means the host 
computer where both the Tools and license management file are physically 
installed.

3. GENERAL RESTRICTIONS. 3.1. General.  Tools are provided to Customer 
in Object Code and are intended for Customer's internal use in 
developing applications in accordance with the Development License and 
not for distribution. Except as expressly permitted by this Tools 
Agreement, Customer will not, nor permit any third party to: (a) for 
Floating User Development Licenses: (i) permit access to or use of the 
Tools in excess of the quantity of concurrent Floating Users set forth 
in the applicable Exhibit or Quote; (ii) transfer any Floating User 
Development License from a Development Location in one country to a 
Development Location in another country; or (iii) allow one Floating 
User in one country to access the Tools from a licensed server in 
another country; (b) for Named User Development License, permit 
concurrent access to or use of a single copy of the Tools for any Named 
User Development License, or access or use by anyone other than the 
Named User assigned to the Development License, as set forth in the 
applicable Exhibit or Quote; (c) for Node-Lock User Development 
Licenses, install the Tools on more than the quantity of licensed Nodes 
set forth in the applicable Exhibit or Quote; (d) translate, reverse 
engineer, decompile, disassemble (except to the extent applicable laws 
specifically prohibit such restriction) or attempt to derive the Source 
Code of any Tools Object Code provided to Customer; (e) reproduce the 
Tools other than as specified in the applicable license grant set forth 
in Section 2 (License Grants); (f) sublicense, rent, lease, loan, 
timeshare, sell, distribute, disclose, publish, assign or transfer any 
rights, grant a security interest in, transfer possession of the Tools, 
or electronically transfer the Tools from one computer to another except 
over Customer's internal network pursuant to Section 3.2 (Network 
Access); (g) modify, distribute or otherwise use the Tools in any manner 
that causes any portion of the Tools that is not already subject to Open 
Source License to become subject to the terms of any Open Source 
License; or (h) alter or remove any of Wind River's or its licensors' 
copyright or proprietary rights notices or legends appearing on or in 
the Tools.  Customer will reproduce such notices on any copies of the 
Tools Customer is permitted to make. Customer will inform all Users of 
the restrictions set forth in this Tools Agreement with respect to use 
of the Tools.

3.2. Network Access.  Floating and Named Users who have a unique network 
log-in (e.g., NT or Unix log-in) may access the Tools from a secure 
network server located at the Development Location over a secure VPN or 
equivalent secure network.  Within thirty (30) days following Wind 
River's written request, Customer will disclose to Wind River the 
Development Location of each network from which Tools will be accessed.  
Node-Lock Users will not remotely access the licensed node, where 
"remote access" means any access to the node other than being physically 
present at the host computer.

3.3. Third Party Software. The Tools licensed under this Tools Agreement 
may contain or be derived from materials of third party licensors such 
as materials subject to an Open Source Licenses ("Third Party 
Software"). Such third party materials may be subject to restrictions in 
addition to those listed in this Section 3 (General Restrictions), which 
restrictions, if any, are set forth in the third party notice file that 
accompanies the Tools. Customer acknowledges and agrees that its use of 
Third Party Software is subject to its compliance with any such 
additional terms.

3.4 Copies.  Customer may make a reasonable number of copies of the 
Tools for archival purposes or for use as a back-up.  Customer must copy 
all copyright legends, trademarks, trade names, and other legends on any 
copies of the Tools.

4. KEYS AND ACCESS. Wind River will provide Customer those keys that are 
reasonably necessary to permit Customer to gain access to the licensed 
Tools. Any technology, ideas, know how, documentation, processes, 
algorithms, and trade secrets disclosed to Customer by Wind River in 
connection with or as embodied in the Tools and keys shall be considered 
"Confidential Information" as defined in the Agreement. Customer will 
disclose such keys solely to authorized Users of the Tools.  The Tools 
also contains license management technology intended to cause the Tools 
to cease operating upon expiration or termination of the license.  
Customer will not circumvent the license management technology, or any 
other security devices, access logs, or other protective measures 
provided with the Tools or permit or assist any User or any third party 
to do the same.  The license management technology and any other 
protective measures in the Tools are included solely as a matter of 
administrative convenience, and Customer has no right or license in or 
to such protective measures.  Customer will be invoiced for any 
additional Users who access the Tools and will pay any such invoice in 
accordance with Section 6 (Delivery, Payment and Taxes) of the 
Agreement.  Customer will follow the recommended installation procedures 
for each Tools product licensed under this Tools Agreement.
  
5. DEFINITIONS. In addition to the terms in initial capitalized letters 
defined elsewhere in this Agreement, the following terms in initial 
capitalized letters have the respective meanings set forth below:


5.1. "Development License" means the right of a User to use certain 
Tools pursuant to Section 2 (License Grants) of this Tools Agreement. 
The Development License type and quantity will be specified in an 
Exhibit or Quote.
   
5.2. "Development Location" means the geographic address of each 
Customer site or facility where the Tools are authorized to be installed 
and used in accordance with the terms of this Agreement.  Customer's 
Development Location(s) will be specified in an Exhibit A or Quote.

5.3. "Floating User" means any User who may access and use the Tools 
pursuant to Section 2.1 (Floating User Development License).

5.4. "Named User" means any User who uses the Tools pursuant to Section 
2.2 (Named User Development License).

5.5. "Node-Lock User" means any User who uses the Tools pursuant to 
Section 2.3 (Node-Lock User Development License).

5.6. "Supported Architecture Family" means the target architecture 
family or families then-supported by Wind River on which Customer may 
use the Tools pursuant to this Agreement, as specified in an Exhibit or 
Quote.

5.7. "User" means a Customer employee or independent contractor who (a) 
is based at a Development Location, (b) will utilize the Tools on behalf 
of Customer, and (c) has signed a confidentiality agreement with 
Customer in which such employee or independent contractor agrees to 
protect third party confidential information with terms no less 
stringent than those set forth herein.  A User may be either: a Floating 
User, Named User or Node-Lock User, as such terms are further defined in 
Section 2 (License Grants). For the avoidance of doubt, a User will be 
deemed to have utilized the Tools if such User has accessed or used any 
portion of the Tools, including without limitation, to accomplish the 
goal of, or which results in, any of the following: (a) developing 
Customer products, including without limitation, software systems, 
devices, applications or API code, as further specified in Section 
2.1(License Grants); (b) using Tools to compile any code; or other 
similar engineering activity or result.

5.8. "Externally downloadable 3rd party components" means third party software
that we don't include with our code when we ship, however we do include
recipes/hooks etc that enable downloading from the third party website. By
selecting this component, you understand that it will be downloaded and
installed from a third party website.  Such software may involve additional
licensing terms. Please contact your legal department should you have any
questions regarding licensing terms and obligations.


                 APPENDIX B - WIND RIVER LINUX PLATFORM
                      PRODUCT EVALUATION TERMS

1. SCOPE. These terms govern Customer's rights and obligations with 
respect to Products which are for Customer's limited evaluation purposes 
("Evaluation Software"). These terms shall supersede any conflicting 
provisions of the Agreement with respect to the Evaluation Software.

2. LICENSE GRANTS. The following license terms and conditions set forth 
in this Section 2 (and no other terms) will solely apply to Customer's 
use of Evaluation Software:

2.1. Evaluation License. Subject to Customer's compliance with the terms 
and conditions of the Agreement, Appendix A and this Appendix B, Wind 
River hereby grants to Customer a restricted, personal, 
non-transferable, non-exclusive, internal-use license, for a thirty (30) 
day period from the Effective Date ("Evaluation Term") to: (i) use the 
Tools solely at the Development Location agreed to in writing by the 
parties and solely for the purpose of internally evaluating the Products 
and not for any other purpose (including without limitation, commercial 
or production purposes); and (ii) reproduce the Tools for archive 
purposes, consistent with Customer's standard archive procedures.
 
2.2. Feedback. Customer may disclose any results of any evaluation of 
the Products including, without limitation, Customer's opinions, 
observations, comments, criticisms and suggested improvements, whether 
in written or oral form (herein, "Feedback") from its evaluations only 
to Wind River.  Should Customer provide Wind River with Feedback, Wind 
River will have the right to use such Feedback and related information 
in any manner it deems appropriate.
 
2.3. LIMITED OBLIGATIONS. CUSTOMER ACKNOWLEDGES THAT WIND RIVER HAS NO 
OBLIGATION TO PROVIDE SUPPORT OR MAINTENANCE FOR THE EVALUATION 
SOFTWARE. IN NO EVENT WILL WIND RIVER'S AGGREGATE CUMULATIVE LIABILITY 
FOR ANY CLAIMS ARISING OUT OF OR RELATED TO EVALUATION OF THE PRODUCTS 
EXCEED $50.00.

---
Linux Click Wrap Rev Feb 2020


================================================
FILE: LICENSE
================================================
		    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.


================================================
FILE: README.md
================================================
wrlinux setup
=============

With this tool you can either create a new distribution builder platform
project, or create a mirror that other projects can be based on.

In addition, you can use the tool to obtain information about available
project configuration options.

The tool uses a layer index (such as layers.openembedded.org), as specified in
the bin/settings.py file, to determine what layers are required to construct
a distribution builder project.

The tool relies on 'repo' from the Android 'git-repo' project.  It produces
a repo style 'default.xml' file, and then calls repo to download all of
the layer components necessary.

The tool also configures various sample files that are used by 
oe-init-build-env to construct your build directory.


Documentation
-------------

For documentation, see the Wind River Knowledge Library:
https://knowledge.windriver.com

Select "Products > Operating Systems > Linux > Linux LTS" to view all
documentation categories.

It is suggested that you start with:
_The Wind River Linux Platform Development Quick Start_.

When following the quick start and other examples, use:

    branchName: WRLINUX_10_21_BASE
    repoURL: git://<git mirror>/git/wrlinux-x


Workflows
---------

Basic setup/usage workflow:

The setup program is expected to have been cloned inside of a project
directory, such as:

    $ mkdir my-project
    $ cd my-project
    $ git clone --branch <branchName> <repoURL> wrlinux-x

Once cloned, simply run the setup.sh (./wrlinux-x/setup.sh) to get a list
of options.  The setup program will construct a new git repository in the
current working directory.  This repository is used to manage the output of
the setup program.

You may re-run the setup program at any time to update/change the project
settings.  However, your build directory will not be touched.  You will have
to resync it with the updated project.  (Specifically bblayers.conf and
local.conf to the config/*.sample versions.)

To update your project, re-run the setup program with the same arguments.
Note the original arguments are available in the generated README file.


Mirror workflow:

    $ mkdir my-mirror
    $ cd my-mirror
    $ git clone --branch <branchName> <repoURL> wrlinux-x
    $ ./wrlinux-x/setup.sh --all-layers --mirror

The above command will mirror all layers, including download layers into the
current location, for the branch specified.

To update the mirror, re-run the setup.sh command with the same arguments.
To add additional branches to your mirror, change the branch in the wrlinux-x,
and re-run the setup.sh with the same arguments.

A user can reference this mirror by doing:

    $ mkdir my-project
    $ cd my-project
    $ git clone --branch <branchName> <path_to_mirror>/wrlinux-x

and then run the wrlinux-x/setup.sh program as described above.


License
-------

Copyright (C) 2016-2017 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
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA


================================================
FILE: bin/.pylintrc
================================================
[MASTER]

# Specify a configuration file.
#rcfile=

# Python code to execute, usually for sys.path manipulation such as
# pygtk.require().
#init-hook=

# Add files or directories to the blacklist. They should be base names, not
# paths.
ignore=CVS

# Add files or directories matching the regex patterns to the blacklist. The
# regex matches against base names, not paths.
ignore-patterns=

# Pickle collected data for later comparisons.
persistent=yes

# List of plugins (as comma separated values of python modules names) to load,
# usually to register additional checkers.
load-plugins=

# Use multiple processes to speed up Pylint.
jobs=2

# Allow loading of arbitrary C extensions. Extensions are imported into the
# active Python interpreter and may run arbitrary code.
unsafe-load-any-extension=no

# A comma-separated list of package or module names from where C extensions may
# be loaded. Extensions are loading into the active Python interpreter and may
# run arbitrary code
extension-pkg-whitelist=

# Allow optimization of some AST trees. This will activate a peephole AST
# optimizer, which will apply various small optimizations. For instance, it can
# be used to obtain the result of joining multiple strings with the addition
# operator. Joining a lot of strings can lead to a maximum recursion error in
# Pylint and this flag can prevent that. It has one side effect, the resulting
# AST will be different than the one from reality. This option is deprecated
# and it will be removed in Pylint 2.0.
optimize-ast=no


[MESSAGES CONTROL]

# Only show warnings with the listed confidence levels. Leave empty to show
# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED
confidence=

# Enable the message, report, category or checker with the given id(s). You can
# either give multiple identifier separated by comma (,) or put this option
# multiple time (only on the command line, not in the configuration file where
# it should appear only once). See also the "--disable" option for examples.
#enable=

# Disable the message, report, category or checker with the given id(s). You
# can either give multiple identifiers separated by comma (,) or put this
# option multiple times (only on the command line, not in the configuration
# file where it should appear only once).You can also use "--disable=all" to
# disable everything first and then reenable specific checks. For example, if
# you want to run only the similarities checker, you can use "--disable=all
# --enable=similarities". If you want to run only the classes checker, but have
# no Warning level messages displayed, use"--disable=all --enable=classes
# --disable=W"
disable=long-builtin,coerce-builtin,apply-builtin,raising-string,parameter-unpacking,reduce-builtin,old-raise-syntax,unpacking-in-except,nonzero-method,dict-iter-method,getslice-method,cmp-builtin,round-builtin,range-builtin-not-iterating,basestring-builtin,standarderror-builtin,import-star-module-level,coerce-method,old-octal-literal,file-builtin,dict-view-method,old-ne-operator,indexing-exception,no-absolute-import,execfile-builtin,oct-method,zip-builtin-not-iterating,buffer-builtin,delslice-method,raw_input-builtin,metaclass-assignment,xrange-builtin,cmp-method,intern-builtin,print-statement,useless-suppression,filter-builtin-not-iterating,unicode-builtin,using-cmp-argument,map-builtin-not-iterating,backtick,input-builtin,old-division,setslice-method,next-method-called,long-suffix,suppressed-message,hex-method,unichr-builtin,reload-builtin,bad-whitespace,missing-docstring,logging-not-lazy,line-too-long,invalid-name,too-few-public-methods,trailing-newlines,bad-continuation


[REPORTS]

# Set the output format. Available formats are text, parseable, colorized, msvs
# (visual studio) and html. You can also give a reporter class, eg
# mypackage.mymodule.MyReporterClass.
output-format=text

# Put messages in a separate file for each module / package specified on the
# command line instead of printing them on stdout. Reports (if any) will be
# written in a file name "pylint_global.[txt|html]". This option is deprecated
# and it will be removed in Pylint 2.0.
files-output=no

# Tells whether to display a full report or only the messages
reports=no

# Python expression which should return a note less than 10 (10 is the highest
# note). You have access to the variables errors warning, statement which
# respectively contain the number of errors / warnings messages and the total
# number of statements analyzed. This is used by the global evaluation report
# (RP0004).
evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)

# Template used to display messages. This is a python new-style format string
# used to format the message information. See doc for all details
#msg-template=


[MISCELLANEOUS]

# List of note tags to take in consideration, separated by a comma.
notes=FIXME,XXX,TODO


[SPELLING]

# Spelling dictionary name. Available dictionaries: none. To make it working
# install python-enchant package.
spelling-dict=

# List of comma separated words that should not be checked.
spelling-ignore-words=

# A path to a file that contains private dictionary; one word per line.
spelling-private-dict-file=

# Tells whether to store unknown words to indicated private dictionary in
# --spelling-private-dict-file option instead of raising a message.
spelling-store-unknown-words=no


[LOGGING]

# Logging modules to check that the string format arguments are in logging
# function parameter format
#logging-modules=logging


[SIMILARITIES]

# Minimum lines number of a similarity.
min-similarity-lines=4

# Ignore comments when computing similarities.
ignore-comments=yes

# Ignore docstrings when computing similarities.
ignore-docstrings=yes

# Ignore imports when computing similarities.
ignore-imports=no


[TYPECHECK]

# Tells whether missing members accessed in mixin class should be ignored. A
# mixin class is detected if its name ends with "mixin" (case insensitive).
ignore-mixin-members=yes

# List of module names for which member attributes should not be checked
# (useful for modules/projects where namespaces are manipulated during runtime
# and thus existing member attributes cannot be deduced by static analysis. It
# supports qualified module names, as well as Unix pattern matching.
ignored-modules=

# List of class names for which member attributes should not be checked (useful
# for classes with dynamically set attributes). This supports the use of
# qualified names.
ignored-classes=optparse.Values,thread._local,_thread._local

# List of members which are set dynamically and missed by pylint inference
# system, and so shouldn't trigger E1101 when accessed. Python regular
# expressions are accepted.
generated-members=

# List of decorators that produce context managers, such as
# contextlib.contextmanager. Add to this list to register other decorators that
# produce valid context managers.
contextmanager-decorators=contextlib.contextmanager


[VARIABLES]

# Tells whether we should check for unused import in __init__ files.
init-import=no

# A regular expression matching the name of dummy variables (i.e. expectedly
# not used).
dummy-variables-rgx=(_+[a-zA-Z0-9]*?$)|dummy

# List of additional names supposed to be defined in builtins. Remember that
# you should avoid to define new builtins when possible.
additional-builtins=

# List of strings which can identify a callback function by name. A callback
# name must start or end with one of those strings.
callbacks=cb_,_cb

# List of qualified module names which can have objects that can redefine
# builtins.
redefining-builtins-modules=six.moves,future.builtins


[FORMAT]

# Maximum number of characters on a single line.
max-line-length=100

# Regexp for a line that is allowed to be longer than the limit.
ignore-long-lines=^\s*(# )?<?https?://\S+>?$

# Allow the body of an if to be on the same line as the test if there is no
# else.
single-line-if-stmt=no

# List of optional constructs for which whitespace checking is disabled. `dict-
# separator` is used to allow tabulation in dicts, etc.: {1  : 1,\n222: 2}.
# `trailing-comma` allows a space between comma and closing bracket: (a, ).
# `empty-line` allows space-only lines.
no-space-check=trailing-comma,dict-separator

# Maximum number of lines in a module
max-module-lines=1000

# String used as indentation unit. This is usually "    " (4 spaces) or "\t" (1
# tab).
indent-string='    '

# Number of spaces of indent required inside a hanging  or continued line.
indent-after-paren=4

# Expected format of line ending, e.g. empty (any line ending), LF or CRLF.
expected-line-ending-format=


[BASIC]

# Good variable names which should always be accepted, separated by a comma
good-names=i,j,k,ex,Run,_

# Bad variable names which should always be refused, separated by a comma
bad-names=foo,bar,baz,toto,tutu,tata

# Colon-delimited sets of names that determine each other's naming style when
# the name regexes allow several styles.
name-group=

# Include a hint for the correct naming format with invalid-name
include-naming-hint=no

# List of decorators that produce properties, such as abc.abstractproperty. Add
# to this list to register other decorators that produce valid properties.
property-classes=abc.abstractproperty

# Regular expression matching correct constant names
const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$

# Naming hint for constant names
const-name-hint=(([A-Z_][A-Z0-9_]*)|(__.*__))$

# Regular expression matching correct class attribute names
class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$

# Naming hint for class attribute names
class-attribute-name-hint=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$

# Regular expression matching correct inline iteration names
inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$

# Naming hint for inline iteration names
inlinevar-name-hint=[A-Za-z_][A-Za-z0-9_]*$

# Regular expression matching correct argument names
argument-rgx=[a-z_][a-z0-9_]{2,30}$

# Naming hint for argument names
argument-name-hint=[a-z_][a-z0-9_]{2,30}$

# Regular expression matching correct variable names
variable-rgx=[a-z_][a-z0-9_]{2,30}$

# Naming hint for variable names
variable-name-hint=[a-z_][a-z0-9_]{2,30}$

# Regular expression matching correct method names
method-rgx=[a-z_][a-z0-9_]{2,30}$

# Naming hint for method names
method-name-hint=[a-z_][a-z0-9_]{2,30}$

# Regular expression matching correct module names
module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$

# Naming hint for module names
module-name-hint=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$

# Regular expression matching correct function names
function-rgx=[a-z_][a-z0-9_]{2,30}$

# Naming hint for function names
function-name-hint=[a-z_][a-z0-9_]{2,30}$

# Regular expression matching correct class names
class-rgx=[A-Z_][a-zA-Z0-9]+$

# Naming hint for class names
class-name-hint=[A-Z_][a-zA-Z0-9]+$

# Regular expression matching correct attribute names
attr-rgx=[a-z_][a-z0-9_]{2,30}$

# Naming hint for attribute names
attr-name-hint=[a-z_][a-z0-9_]{2,30}$

# Regular expression which should only match function or class names that do
# not require a docstring.
no-docstring-rgx=^_

# Minimum line length for functions/classes that require docstrings, shorter
# ones are exempt.
docstring-min-length=-1


[ELIF]

# Maximum number of nested blocks for function / method body
max-nested-blocks=5


[DESIGN]

# Maximum number of arguments for function / method
max-args=10

# Argument names that match this expression will be ignored. Default to name
# with leading underscore
ignored-argument-names=_.*

# Maximum number of locals for function / method body
max-locals=50

# Maximum number of return / yield for function / method body
max-returns=6

# Maximum number of branch for function / method body
max-branches=30

# Maximum number of statements in function / method body
max-statements=50

# Maximum number of parents for a class (see R0901).
max-parents=7

# Maximum number of attributes for a class (see R0902).
max-attributes=7

# Minimum number of public methods for a class (see R0903).
min-public-methods=2

# Maximum number of public methods for a class (see R0904).
max-public-methods=20

# Maximum number of boolean expressions in a if statement
max-bool-expr=5


[CLASSES]

# List of method names used to declare (i.e. assign) instance attributes.
defining-attr-methods=__init__,__new__,setUp

# List of valid names for the first argument in a class method.
valid-classmethod-first-arg=cls

# List of valid names for the first argument in a metaclass class method.
valid-metaclass-classmethod-first-arg=mcs

# List of member names, which should be excluded from the protected access
# warning.
exclude-protected=_asdict,_fields,_replace,_source,_make


[IMPORTS]

# Deprecated modules which should not be used, separated by a comma
deprecated-modules=optparse

# Create a graph of every (i.e. internal and external) dependencies in the
# given file (report RP0402 must not be disabled)
import-graph=

# Create a graph of external dependencies in the given file (report RP0402 must
# not be disabled)
ext-import-graph=

# Create a graph of internal dependencies in the given file (report RP0402 must
# not be disabled)
int-import-graph=

# Force import order to recognize a module as part of the standard
# compatibility libraries.
known-standard-library=

# Force import order to recognize a module as part of a third party library.
known-third-party=enchant

# Analyse import fallback blocks. This can be used to support both Python 2 and
# 3 compatible code, which means that the block might have code that exists
# only in one or another interpreter, leading to false positives when analysed.
analyse-fallback-blocks=no


[EXCEPTIONS]

# Exceptions that will emit a warning when being caught. Defaults to
# "Exception"
overgeneral-exceptions=Exception


================================================
FILE: bin/LICENSE.texttable
================================================
The MIT License (MIT)

Copyright (c) 2018 Gerome Fournier

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.



================================================
FILE: bin/Makefile
================================================
SHELL = /bin/bash #requires bash
VENV = $(PWD)/.venv/
DEPS = $(wildcard *.py)
TMP_PIP = $(VENV)/get-pip.py
PYTHON3 := $(shell command -v python3 2> /dev/null)
WGET := $(shell command -v wget 2> /dev/null)

.PHONY: setup lint clean test help

.DEFAULT_GOAL := build

help:
	@echo "Make options for oe-chef development"
	@echo
	@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-10s\033[0m %s\n", $$1, $$2}'

$(VENV):
ifndef PYTHON3
    $(error "python3 is not installed.")
endif
ifndef WGET
    $(error "wget is not installed.")
endif
	test -d $(VENV) || python3 -m venv --without-pip $(VENV); \
	touch $(VENV); \
	. $(VENV)/bin/activate; \
	wget -O $(TMP_PIP) https://bootstrap.pypa.io/get-pip.py; \
	python3 $(TMP_PIP); \
	pip3 install pylint nose flake8;

setup: $(VENV) ## Install all python dependencies in virtualenv

clean: ## Delete virtualenv and all build directories
	rm -rf $(VENV)

test: setup ## Run tests
	. $(VENV)/bin/activate; python3 test/test_oe_chef.py

lint: setup ## Run pylint
	. $(VENV)/bin/activate; pylint $(DEPS)


================================================
FILE: bin/argparse_setup.py
================================================
# Copyright (C) 2016 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
# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

# Note this class MUST run in both python2 and python3

import argparse
import sys
import os

from urllib.parse import urlparse

import logger_setup
logger = logger_setup.setup_logging()

class Argparse_Setup:
    def __init__(self, setup, parser=None):
        if not parser:
            parser = argparse.ArgumentParser(description='setup.py: Application to fetch & setup a distribution project.')
        self.layer_select = False
        self.parser = parser
        self.setup = setup
        # Each group's layername must have a group keyword, for example:
        # - meta-examplekey
        # - meta-examplekey-layer1
        # - meta-examplekey-layer2
        # The examplekey is the keyword for these layers. It will be used to
        # check against the layername from layerindex (not layer's directory
        # name). Any layername contains the keyword is treated as an extra
        # group layer, and they should only be enabled when
        # --use-layer-groups=keyword or --layers=layer is specified.
        # Add the new keyword here when there is a new extra group.
        self.extra_group_keys=['ccm']

    def evaluate_args(self, args):
        self.add_options()
        parsed_args = self.parser.parse_args(args)
        self.handle_setup_args(parsed_args, args)

    def handle_setup_args(self, parsed_args, args):
        # Parse setup options
        if (parsed_args.verbose):
            if self.setup:
                self.setup.set_debug()
            del parsed_args.verbose

        if (parsed_args.base_url):
            if self.setup:
                self.setup.set_base_url(parsed_args.base_url)
            del parsed_args.base_url

        if (parsed_args.base_branch):
            if self.setup:
                self.setup.set_base_branch(parsed_args.base_branch)
            del parsed_args.base_branch

        # Parse repo option
        if (parsed_args.repo_verbose):
            if self.setup:
                self.setup.set_repo_verbose(parsed_args.repo_verbose)
            del parsed_args.repo_verbose

        if (parsed_args.repo_jobs):
            if self.setup:
                self.setup.set_jobs(parsed_args.repo_jobs)
            del parsed_args.repo_jobs

        if (parsed_args.repo_depth):
            if self.setup:
                self.setup.set_depth(parsed_args.repo_depth)
            del parsed_args.repo_depth

        if (parsed_args.repo_force_sync):
            if self.setup:
                self.setup.set_force_sync(parsed_args.repo_force_sync)
            del parsed_args.repo_force_sync

        if (parsed_args.repo_url):
            if self.setup:
                self.setup.set_repo_url(parsed_args.repo_url)
            del parsed_args.repo_url

        if (parsed_args.repo_branch):
            if self.setup:
                self.setup.set_repo_rev(parsed_args.repo_branch)
            del parsed_args.repo_branch

        # Look for list options
        if parsed_args.list_distros:
            if self.setup:
                self.setup.list_distros = parsed_args.list_distros

        if parsed_args.list_machines:
            if self.setup:
                self.setup.list_machines = parsed_args.list_machines

        if parsed_args.list_layers:
            if self.setup:
                self.setup.list_layers = True

        if parsed_args.list_recipes:
            if self.setup:
                self.setup.list_recipes = True

        if parsed_args.repo_no_fetch:
            if self.setup:
                self.setup.repo_no_fetch = True
            del parsed_args.repo_no_fetch


        if (parsed_args.list_distros or parsed_args.list_machines or parsed_args.list_layers or parsed_args.list_recipes):
            return

        # Parse layer selection options
        if parsed_args.distros:
            self.layer_select = True
            if self.setup:
                self.setup.distros = []
                for d in parsed_args.distros:
                    for distro in d.split(','):
                        self.setup.distros.append(distro)

        if parsed_args.machines:
            self.layer_select = True
            if self.setup:
                self.setup.machines = []
                for m in parsed_args.machines:
                    for machine in m.split(','):
                        self.setup.machines.append(machine)

        if parsed_args.layers:
            self.layer_select = True
            if self.setup:
                self.setup.layers = []
                for l in parsed_args.layers:
                    for layer in l.split(','):
                        if '://' in layer:
                            # check if layer has a valid url scheme
                            url = urlparse(layer)
                            if url.scheme and url.scheme != 'file':
                                remote_layer = {}
                                remote_layer['branch'] = 'master'
                                remote = layer.split('+')
                                remote_layer['url'] = remote[0]
                                remote_layer['path'] = 'layers/' + remote[0].split('/')[-1]
                                for arg in remote[1:]:
                                    if arg.startswith('branch='):
                                        remote_layer['branch'] = arg[7:]

                                self.setup.remote_layers.append(remote_layer)
                            else:
                                logger.warning("Skipping invalid remote url: %s" % (layer))
                        elif '/' in layer or os.path.exists(layer):
                            layer = os.path.realpath(layer)
                            if not os.path.isdir(layer):
                                logger.warning("Skipping invalid local layer %s" % (layer))
                            else:
                                self.setup.local_layers.append(layer)
                        else:
                            self.setup.layers.append(layer)

        if parsed_args.recipes:
            self.layer_select = True
            if self.setup:
                self.setup.recipes = []
                for r in parsed_args.recipes:
                    for recipe in r.split(','):
                        self.setup.recipes.append(recipe)

        if parsed_args.all_layers:
            self.layer_select = True
            if self.setup:
                self.setup.all_layers = parsed_args.all_layers

        if parsed_args.no_recommend:
            self.layer_select = True
            if self.setup:
                self.setup.no_recommend = parsed_args.no_recommend

        if (parsed_args.mirror):
            if self.layer_select is not True:
                print('ERROR: The --mirror option requires at least one Layer Section argument, see --help.')
                sys.exit(1)

            if self.setup:
                self.setup.mirror = parsed_args.mirror

        if parsed_args.use_layer_groups:
            if self.setup:
                self.setup.use_layer_groups = parsed_args.use_layer_groups

        if self.layer_select is not True:
            print('ERROR: You must include at least one Layer Selection argument, see --help.')
            sys.exit(1)

    def add_setup_options(self):
        # Setup options
        self.parser.add_argument('-v', '--verbose', help='Set the verbosity to debug', action="store_true")

        self.base_args = self.parser.add_argument_group('Base Settings')

        setup_base_url = ""
        if self.setup and self.setup.base_url:
            setup_base_url = '(default %s)' % (self.setup.base_url)
        self.base_args.add_argument('--base-url', metavar="URL", help='URL to fetch from %s' % (setup_base_url))

        setup_base_branch = ""
        if self.setup and self.setup.base_branch:
            setup_base_branch = '(default %s)' % (self.setup.base_branch)
        self.base_args.add_argument('--base-branch', metavar="BRANCH", help='Base branch identifier %s' % (setup_base_branch))

        self.parser.add_argument('--mirror', help='Do not construct a project, instead construct a mirror of the repositories that would have been used to construct a project (requires a Layer Selection argument)', action='store_true')
    def add_repo_options(self):
        self.repo_args = self.parser.add_argument_group('repo Settings')
        # Repo options
        setup_jobs = ""
        self.repo_args.add_argument('-rv', '--repo-verbose', action='store_true', help='Disables use of --quiet with repo commands')
        if self.setup and self.setup.jobs:
            setup_jobs = '(default %s)' % (self.setup.jobs)
        self.repo_args.add_argument('-rj', '--repo-jobs', metavar='JOBS', help='Sets repo project to fetch simultaneously %s' % (setup_jobs))
        self.repo_args.add_argument('--repo-depth', metavar='DEPTH', help='Sets repo --depth; see repo init --help (note: if set, a value of >= 2 is required)')
        self.repo_args.add_argument('--repo-force-sync', action='store_true', help='Sets repo --force-sync; see repo sync --help')
        self.repo_args.add_argument('--repo-no-fetch', help='Do all the setup but do not call repo sync', action="store_true")

        repo_url = ""
        if 'REPO_URL' in os.environ:
            repo_url = '(default %s)' % os.environ['REPO_URL']

        repo_rev = ""
        if 'REPO_REV' in os.environ:
            repo_rev = '(default %s)' % os.environ['REPO_REV']

        self.repo_args.add_argument('--repo-url', metavar="URL", help='Url for git-repo %s' % (repo_url))
        self.repo_args.add_argument('--repo-branch', metavar="REV", help='Url for git-repo %s' % (repo_rev))


    def add_list_options(self):
        self.list_args = self.parser.add_argument_group('Layer Listings')
        # List options
        self.list_args.add_argument('--list-distros',   metavar='all', nargs='?', const='default', help='List available distro values')
        self.list_args.add_argument('--list-machines',  metavar='all', nargs='?', const='default', help='List available machine values')
        self.list_args.add_argument('--list-layers',    action='store_true', help='List all available layers')
        self.list_args.add_argument('--list-recipes',   action='store_true', help='List all available recipes')

    def add_layer_options(self):
        self.layer_args = self.parser.add_argument_group('Layer Selection')

        # Layer selection and local.conf setup
        setup_distro = ""
        setup_distro_str = ""
        if self.setup and self.setup.distros:
            setup_distro = self.setup.distros[0]
            setup_distro_str = '(default %s)' % setup_distro
        self.layer_args.add_argument('--distros', metavar='DISTRO', help='Select layer(s) based on required distribution and set the default DISTRO= value %s' % setup_distro_str, nargs="+")

        setup_machine = ""
        setup_machine_str = ""
        if self.setup and self.setup.machines:
            setup_machine = self.setup.machines[0]
            setup_machine_str = '(default %s)' % setup_machine
        self.layer_args.add_argument('--machines', metavar='MACHINE', help='Select layer(s) based on required machine(s) and set the default MACHINE= value %s' % setup_machine_str, nargs='+')

        self.layer_args.add_argument('--layers', metavar='LAYER', help='Select layer(s) to include in the project and add to the default bblayers.conf. Can accept the name of a layer in the layerindex, a path to a layer on local storage or a remote url that will be cloned by git-repo. (<name>|<path>|<scheme>://<url>/<repo>(+branch=<branch>)) ', nargs='+')
        self.layer_args.add_argument('--recipes', metavar='RECIPE', help='Select layers(s) based on recipe(s)', nargs='+')
        self.layer_args.add_argument('--all-layers', help='Select all available layers', action='store_true')
        self.layer_args.add_argument('--no-recommend', help='Disable recommended layers during layer resolution', action='store_true')
        self.layer_args.add_argument('--use-layer-groups', metavar='EXTRA_GROUP', help="Specify extra layer groups to use. Make sure you have permissions to access these groups before you use it.", action='store', nargs='+', choices=self.extra_group_keys)

    def add_other_options(self):
        pass

    def add_options(self):
        self.add_setup_options()
        self.add_repo_options()
        self.add_list_options()
        self.add_layer_options()
        self.add_other_options()


================================================
FILE: bin/argparse_wrl.py
================================================
# Copyright (C) 2016 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
# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

# Note this class must run in both python2 and python3

import argparse
import logging
import string
import sys

from argparse_setup import Argparse_Setup

class Argparse_Wrl(Argparse_Setup):
    def __init__(self, setup, parser=None):
        self.parser = argparse.ArgumentParser(description='setup.py: Application to fetch & setup a WindRiver Linux project.')
        Argparse_Setup.__init__(self, setup, parser)

    def handle_setup_args(self, parsed_args, args):
        if (parsed_args.buildtools_branch):
            # ignore (handled by setup.sh)
            del parsed_args.buildtools_branch

        if (parsed_args.buildtools_type):
            # ignore (handled by setup.sh)
            del parsed_args.buildtools_type

        if (parsed_args.user):
            # ignore (handled by setup.sh)
            del parsed_args.user

        if (parsed_args.password):
            # ignore (handled by setup.sh)
            del parsed_args.password

        if parsed_args.no_anspass:
            # ignore (handled by setup.sh)
            del parsed_args.no_anspass

        if (parsed_args.accept_eula):
            # ignore (handled by setup.sh)
            del parsed_args.accept_eula

        if parsed_args.list_templates:
            if self.setup:
                self.setup.list_wrtemplates = parsed_args.list_templates

        if (parsed_args.list_templates):
            return

        if parsed_args.templates:
            self.layer_select = True
            if self.setup:
                self.setup.wrtemplates = []
                for t in parsed_args.templates:
                    for wrtemplate in t.split(','):
                        self.setup.wrtemplates.append(wrtemplate)

        if parsed_args.dl_layers:
            self.layer_select = True
            if self.setup:
                self.setup.dl_layers = parsed_args.dl_layers

        Argparse_Setup.handle_setup_args(self, parsed_args, args)

    def add_setup_options(self):
        Argparse_Setup.add_setup_options(self)

        setup_buildtools_branch = ""
        if self.setup and self.setup.buildtools_branch:
            setup_buildtools_branch = '(default %s)' % (self.setup.buildtools_branch)
        self.base_args.add_argument('--buildtools-branch', metavar="BRANCH", help='Buildtools branch %s' % (setup_buildtools_branch))
        self.base_args.add_argument('--buildtools-type', metavar="TYPE", help="Buildtools type: basic or extended (default basic), install extended buildtools with 'extended'")
        self.base_args.add_argument('--user', help='Specify default user for download')
        self.base_args.add_argument('--password', help='Specify default password for download')
        self.base_args.add_argument('--accept-eula', metavar="ACCEPT", help='Accept End User License Agreement (yes|no)')
        self.base_args.add_argument('--no-anspass', action='store_true', help='Do not use anspass to save the user name and password')

    def add_list_options(self):
        Argparse_Setup.add_list_options(self)
        self.list_args.add_argument('--list-templates', metavar='all', nargs='?', const='default', help='List available templates')

    def add_layer_options(self):
        Argparse_Setup.add_layer_options(self)
        self.layer_args.add_argument('--templates', metavar='TEMPLATE', help='Select layers(s) based on template(s) and add them by default to the builds', nargs='+')
        self.layer_args.add_argument('--dl-layers', help='Enable download layers; these layers include predownloaded items', action='store_true')


================================================
FILE: bin/branch_mirror.py
================================================
#!/usr/bin/env python3

# Copyright (C) 2016 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
# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

# This program will identify the layers, and their current branches,
# that need to be branched as part of the release process.
#
# The program will branch them and provide a list that can be used
# to push the items.
#
# The program will also update the mirror index entries with the
# branch names.

import os
import sys

import subprocess

import xml.etree.ElementTree as ET

import utils_setup

from layer_index import Layer_Index

import logger_setup

import settings

completed = []

def usage():
    print("usage: %s <branch> [--force]" % sys.argv[0])
    sys.exit(1)

if len(sys.argv) < 2:
    usage()

logger = logger_setup.setup_logging()

dest_branch = sys.argv[1]

force = False
if len(sys.argv) > 2:
    if sys.argv[2] != '--force':
        usage()

    force = True

mirror_path = 'mirror-index'
if not os.path.exists(mirror_path):
    logger.critical('No mirror-index found. %s' % mirror_path)
    sys.exit(1)

cmd = ['git', 'rev-parse', '--abbrev-ref', 'HEAD']
ret = subprocess.Popen(cmd, cwd=mirror_path, close_fds=True, stdout=subprocess.PIPE)
branch = ""
output = ""
while True:
    output = ret.stdout.readline()
    if not output and ret.poll() is not None:
        break
    branch += output.decode('utf-8')
ret.wait()
branch = branch.strip()

if branch == dest_branch:
    logger.warning('Branch is already configured!')

work_list = []

def git_branch(_dst, _orig_branch, _branch):
    logger.info('Branching %s: %s -> %s' % (_dst, _orig_branch, _branch))

    # Break this into two commands, so it will work with tags as well...
    _cmd = [ 'git', 'fetch', '.', '%s' % (_orig_branch) ]
    utils_setup.run_cmd(_cmd, cwd=_dst)

    _cmd = [ 'git', 'branch', _branch, 'FETCH_HEAD' ]
    if force:
        _cmd.append('-f')
    utils_setup.run_cmd(_cmd, cwd=_dst)

    work_list.append('%s %s' % (_dst, _branch))

# We assume this program is located in the bin directory
dst = os.path.dirname(os.path.dirname(sys.argv[0]))

# Branch the setup program....
git_branch(_dst=dst, _orig_branch=branch, _branch=dest_branch)
completed.append(dst)

# Transform and export the mirror index
git_branch(mirror_path, branch, dest_branch)
completed.append(mirror_path)

index = Layer_Index(indexcfg=settings.INDEXES, base_branch=branch, replace=settings.REPLACE, mirror=mirror_path)

cmd = ['git', 'checkout', dest_branch]
utils_setup.run_cmd(cmd, cwd=mirror_path)

logger.info('Loading default.xml')
tree = ET.parse('default.xml')
root = tree.getroot()



logger.info('Branching based on default.xml')
default_revision = None
base_url = None
for child in root:
    if child.tag == 'remote':
        if 'fetch' in child.attrib:
            base_url = child.attrib['fetch']

    if child.tag == 'default':
        if 'revision' in child.attrib:
            default_revision = child.attrib['revision']

    if child.tag != 'project':
        continue

    src = child.attrib['name']

    if not os.path.exists(src):
        if os.path.exists(src + '.git'):
            src += '.git'
        else:
            logger.warning('Unable to find %s' % src)
            continue

    revision = None
    if not ('bare' in child.attrib and child.attrib['bare'] == 'True'):
        revision = default_revision
        if 'revision' in child.attrib:
            revision = child.attrib['revision']

    if revision:
        git_branch(src, revision, dest_branch)
    completed.append(src)



logger.info('Transforming default.xml')
for child in root:
    if 'revision' in child.attrib:
        child.attrib['revision'] = dest_branch
open('default.xml', 'wt').write(ET.tostring(root, encoding='unicode'))



logger.info('Transforming index...')

bitbake_branch = branch
branchid = None
for lindex in index.index:
    for branches in lindex['branches']:
        if 'name' in branches and branches['name'] == branch:
            branches['name'] = dest_branch
            if 'bitbake_branch' in branches and branches['bitbake_branch'] != '':
                bitbake_branch = branches['bitbake_branch']
                branches['bitbake_branch'] = dest_branch
            branchid = branches['id']

    for layer in lindex['layerItems']:
        if layer['vcs_url']:
            for lb in lindex['layerBranches']:
                if layer['id'] == lb['layer'] and lb['branch'] == branchid:
                    if 'actual_branch' in lb and lb['actual_branch'] != "":
                        lb['actual_branch'] = ''

    # Remove older entries
    for (dirpath, dirnames, filenames) in os.walk(mirror_path):
        if dirpath.endswith('/.git') or '/.git/' in dirpath or dirpath.endswith('/xml') or '/xml/' in dirpath:
            continue
        for filename in filenames:
            if filename.startswith(lindex['CFG']['DESCRIPTION'].translate(str.maketrans('/ ', '__'))):
                os.remove(os.path.join(dirpath, filename))

    index.serialize_index(lindex, os.path.join(mirror_path, lindex['CFG']['DESCRIPTION']), split=True, IncludeCFG=True, mirror=True, base_url=base_url)

# git add file.
cmd = ['git', 'add', '-A', '.']
utils_setup.run_cmd(cmd, cwd=mirror_path)

cmd = ['git', 'diff-index', '--quiet', 'HEAD', '--']
try:
    utils_setup.run_cmd(cmd, cwd=mirror_path)
except:
    logger.debug('Updating mirror-index')
    cmd = ['git', 'commit', '-m', 'Branch (%s) and adjust index entries' % (dest_branch)]
    utils_setup.run_cmd(cmd, cwd=mirror_path)

logger.info('Done')

logger.plain('Writing branched-layer.list...')
output = open('branched-layer.list', 'wt')
for item in work_list:
    output.write("%s\n" % item)
output.close()


================================================
FILE: bin/dump_layer_dependencies.py
================================================
#!/usr/bin/env python3

# Copyright (C) 2016-2017 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
# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

# This program will dump the dependencies for one or more layers in a
# given branch.  It can be used to verify that when a branch is created
# that the dependencies have been scanned properly.

# Adjust the standard WR urls to make comparisons easier.
REPLACE = [
            ( 'git://git.wrs.com/', '#BASE_URL#' ),
            ( 'http://git.wrs.com/cgit/', '#BASE_WEB#' ),
          ]

# Note the branch can be hard coded.  This is required only when you want
# to limit the branch from a restapi-web import.  (This does not do anything
# on other input formats.)
INDEXES = [
    {
        'DESCRIPTION' : 'Wind River Developer Layer Index',
        'TYPE' : 'restapi-web',
        'URL' : 'http://layers.wrs.com/layerindex/api/',
        'CACHE' : None,
        #'BRANCH' : 'master-wr',
    },
]

import os
import sys

from layer_index import Layer_Index

def usage():
    print("usage: %s <branch>" % sys.argv[0])
    sys.exit(1)

if len(sys.argv) < 2:
    usage()

base_branch=sys.argv[1]

index = Layer_Index(INDEXES, base_branch=base_branch, replace=REPLACE)

import unicodedata
for lindex in index.index:
    dep_out = []
    branchid = index.getBranchId(lindex, index.getIndexBranch(default=base_branch, lindex=lindex))
    if branchid:
        for lb in lindex['layerBranches']:
            if lb['branch'] == branchid:
                for layer in index.find_layer(lindex, layerBranch=lb):
                    name = layer['name']
                    (required, recommended) = index.getDependencies(lindex, lb)
                    reqnames = []
                    recnames = []
                    for req in required:
                        for layer in index.find_layer(lindex, layerBranch=req):
                            reqnames.append(layer['name'])
                    for rec in recommended:
                        for layer in index.find_layer(lindex, layerBranch=rec):
                            recnames.append(layer['name'])

                    dep_out.append((name, ' '.join(sorted(reqnames)), ' '.join(sorted(recnames))))

    for (name, reqs, recs) in sorted(dep_out, key=lambda t: t[0]):
       print('%s %s (%s)' % (name, reqs, recs))


================================================
FILE: bin/dump_layer_rev.py
================================================
#!/usr/bin/env python3

# Copyright (C) 2016 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
# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

# This program will load the index and for each layer list the layer,
# branch and current commit.  This can be used to verify that the
# index and layers are in sync.

import os
import sys

import settings

from layer_index import Layer_Index

mirror_path = 'mirror-index'
if not os.path.exists(mirror_path):
    if not os.path.exists(mirror_path + '.git'):
        print('No %s found.  Is this a mirror?' % mirror_path)
        sys.exit(1)
    else:
        mirror_path = mirror_path + '.git'

index = Layer_Index(indexcfg=settings.INDEXES, base_branch=None, replace=settings.REPLACE, mirror=mirror_path)

for lindex in index.index:
    for branch in lindex['branches']:
        basebranch = branch['name']
        for litem in lindex['layerItems']:
            for lbranch in lindex['layerBranches']:
                if lbranch['layer'] == litem['id']:
                    branch = basebranch
                    if lbranch['actual_branch'] != "":
                        branch = lbranch['actual_branch']
                    print('%s %s %s %s' % (litem['name'], litem['vcs_url'], branch, lbranch['vcs_last_rev']))
                    break


================================================
FILE: bin/flatten_mirror.py
================================================
#!/usr/bin/env python3

# Copyright (C) 2016 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
# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

# This program will flatten a mirror and copy the result into a target dir.
#
# Many git servers require a single flat level of git trees in order to
# work properly.  Flattening the tree will require both renaming directories
# as well as updating the mirror-index to match.

# Format of the subset folder file is:
# <layer> <folder>
#
# <layer> is the name in the layer index of that layer
# <folder> is a directory to generate inside of the <dest>
#
# Note, if this is used, an error will be generated for any known layers
# that are not assigned to a folder.
#
# A special folder name '[SKIP]' is defined when you are intentionally
# skipping a layer.

import argparse

import os
import sys

import shutil

import subprocess

import xml.etree.ElementTree as ET

import utils_setup

from layer_index import Layer_Index

import logger_setup

import settings

def config_args(args):
    parser = argparse.ArgumentParser(description='flatten_mirror.py: Flatten a mirror.')

    parser.add_argument('dest', help='Destination Directory')

    parser.add_argument('--push-not-copy', help='Push non-bare layers, don\'t copy them.  This allows the flattened version to only have one branch.', action='store_true')
    parser.add_argument('--subset-mirror', metavar='FILE', help='Use a file that will allow the system to subset the mirror into specific subdirectories.')
    parser.add_argument('--strip-git', help='Strip the .git suffix from paths when copying.  This is needed when copying to an http server, vs a git server.', action='store_true')

    parsed_args = parser.parse_args(args)

    return (parsed_args.dest, parsed_args.push_not_copy, parsed_args.subset_mirror, parsed_args.strip_git)

def push_or_copy(_layer, _src, _dst, _branch=None):
    if subset_folders:
        if _layer not in subset_folders:
            logger.critical("Layer %s (%s) not in SUBSET_FOLDERS" % (_layer, _src))
            raise
        elif subset_folders[_layer] == "[SKIP]":
            return
        else:
            dstdir = os.path.dirname(_dst)
            dstbase = os.path.basename(_dst)
            _dst = os.path.join(dstdir, subset_folders[_layer], dstbase)

    if not os.path.exists(_src):
        _src += '.git'
        if not os.path.exists(_src):
            logger.critical("Unable to find %s!" % _src)
            raise

    # Make output consistent
    if not strip_git and not _dst.endswith('.git'):
        _dst += '.git'

    if strip_git and _dst.endswith('.git'):
        _dst = _dst[:-4]

    if not git_push or not _branch:
        logger.plain('cp %s -> %s' % (_src, _dst))
        shutil.copytree(_src, _dst, symlinks=True, ignore_dangling_symlinks=True)
    else:
        logger.plain('push %s -> %s (%s)' % (_src, _dst, _branch))
        if os.path.exists(_dst):
            logger.critical('Destination %s already exists!' % _dst)
            raise
        os.makedirs(_dst, exist_ok=True)

        # New bare repo
        _cmd = [ 'git', 'init', '--bare' ]
        utils_setup.run_cmd(_cmd, cwd=_dst)

        # Push just the one branch
        _cmd = [ 'git', 'push', os.path.abspath(_dst), _branch ]
        utils_setup.run_cmd(_cmd, cwd=_src)

# Used to subset target mirror path, if necessary

# Return the mirror_directory target for a given layer entry.
# If the target directory does not exist, we create it (git repository)
#
# This function will return None if the layer is to be skipped.
def get_mirror_dir(_layer, _dst):
    if subset_folders:
        if _layer in subset_folders:
            if subset_folders[_layer] == "[SKIP]":
                return None

            dstdir = os.path.dirname(_dst)
            dstbase = os.path.basename(_dst)
            _dst = os.path.join(dstdir, subset_folders[_layer], dstbase)
        else:
            logger.error("Layer %s not in SUBSET_FOLDERS" % _layer)
            # Use default directory

    # If the target directory does not exist, create it
    if not os.path.exists(_dst):
        cmd = ['git', 'init', _dst]
        utils_setup.run_cmd(cmd)

        if not branch or branch == "":
            logger.critical('Where did the branch val go!? %s' % branch)
            raise

        cmd = ['git', 'checkout', '-b', branch]
        try:
            utils_setup.run_cmd(cmd, cwd=_dst)
        except:
            # if we failed, then simply try to switch branches
            cmd = ['git', 'checkout', branch]
            utils_setup.run_cmd(cmd, cwd=_dst)

    return _dst

# Return the layer specific XML directory.  The XML directory
# lives inside of the mirror path.  If the mirror directory does
# not already exist it is created by callign get_mirror_dir
#
# This function will return None if the layer is to be skipped.
def get_xml_dir(_layer, _mirror):
    _mirror = get_mirror_dir(_layer, _mirror)
    if _mirror:
        return os.path.join(_mirror, 'xml')
    return _mirror

# Process and transform the specified XML files.  Return a list of
# project names referenced by this XML file.
#
# If the _dest is None, we still process the XML layer, but we never
# write out a result.  This is necessary to parse the components owned
# by the xml file so we know to skip them...
def transform_xml(_src, _dest):
    logger.plain('Processing %s' % _src)
    if not os.path.exists(_src):
        logger.warning('Not found %s' % _src)
        return []

    if _dest:
        os.makedirs(os.path.dirname(_dest), exist_ok=True)
        with open(_src, 'rt') as fin, open(_dest, 'wt') as fout:
            return transform_xml_inside(fin, fout)
    else:
        with open(_src, 'rt') as fin:
            return transform_xml_inside(fin, None)

def transform_xml_inside(_fin, _fout):
    result = []

    for _line in _fin:
        modified = False
        try:
            _root = ET.fromstring(_line)
        except:
            logger.warning('exception on: %s' % _line)
            if _fout:
                _fout.write('%s' % _line)
            continue

        # Skip linkfiles, don't warn.. we know these are valid
        if _root.tag == 'linkfile':
            if _fout:
                _fout.write('%s' % _line)
            continue

        if _root.tag != 'project':
            logger.warning('Not project: %s' % _line)
            if _fout:
                _fout.write('%s' % _line)
            continue

        for attrib in _root.attrib:
            if attrib == 'name':
                result.append(_root.attrib['name'])
                if _root.attrib['name'] != _root.attrib['name'].split('/')[-1]:
                    _root.attrib['name'] = _root.attrib['name'].split('/')[-1]
                    modified = True

        for _child in _root:
            for attrib in _child.attrib:
                if attrib == 'name':
                    result.append(_child.attrib['name'])
                    if _child.attrib['name'] != _child.attrib['name'].split('/')[-1]:
                        _child.attrib['name'] = _child.attrib['name'].split('/')[-1]
                        modified = True

        if _fout:
            if modified:
                _fout.write('    %s\n' % (ET.tostring(_root, encoding='unicode')))
            else:
                _fout.write('%s' % _line)

    return result

# Process the mirrors and add any new files to the git repo
def update_mirror(_dst_mirror):
    cmd = ['git', 'add', '-A', '.']
    utils_setup.run_cmd(cmd, cwd=_dst_mirror)

    logger.debug('Updating mirror-index')
    cmd = ['git', 'commit', '-m', 'Updated index - Flatten Mirror']
    try:
        utils_setup.run_cmd(cmd, cwd=_dst_mirror, log=2)
    except:
        # Nothing changed...
        pass

def copy_premirrors_dl(dest):
    premirrors_dl = "premirrors-dl/downloads/"
    if os.path.exists(premirrors_dl):
        logger.plain("Copying %s" % premirrors_dl)
    else:
        return
    cmd = "cp --parent -a".split()
    if os.stat(premirrors_dl).st_dev == os.stat(dest).st_dev:
        # Hard link when possible
        cmd.append("-l")
    cmd += [premirrors_dl, dest]
    utils_setup.run_cmd(cmd)

# This assumes variables 'dest', 'git_push', 'subset_file' and
# 'setup_dir' is globally set.
def main():
    global subset_folders
    global branch

    if subset_file:
        subset_folders = {}
        with open(subset_file, 'rt') as f:
            for line in f:
                if line.startswith('#'):
                    continue
                lsplit = line.split()
                if len(lsplit) == 0:
                    continue
                if len(lsplit) != 2:
                    logger.critical("Subset Folders, invalid line: %s" % (line))
                    return 1
                subset_folders[lsplit[0]] = lsplit[1]

    if os.path.exists(dest):
        logger.critical('Destination directory %s already exists.  Please choose a different destination.' % (dest))
        return 1

    # We have to run this against a mirror, check for a mirror-index
    mirror_path = 'mirror-index'
    if not os.path.exists(mirror_path):
        logger.critical('No %s found.  Is this a mirror?' % mirror_path)
        return 1

    dst_base_mirror = os.path.join(dest, mirror_path)

    # Find the base branch of the mirror-index to set a default
    cmd = ['git', 'rev-parse', '--abbrev-ref', 'HEAD']
    _ret = subprocess.Popen(cmd, cwd=mirror_path, close_fds=True, stdout=subprocess.PIPE)
    branch = ""
    output = ""
    while True:
        output = _ret.stdout.readline()
        if not output and _ret.poll() is not None:
            break
        branch += output.decode('utf-8')
    _ret.wait()
    branch = branch.strip()

    if not branch or branch == "":
        logger.critical('Unable to determine base branch.')
        return 1

    # Create the destination
    os.makedirs(dest, exist_ok=False)

    #### Load the index and create a list of things we need to parse

    # this is the list of things that MAY be in the default.xml file, we need
    # to have a list to later process that file and exclude things we've already
    # done.
    processed_list = []

    ### Create the target mirror-index...
    # Transform and export the mirror index
    logger.plain('Transforming index...')

    index = Layer_Index(indexcfg=settings.INDEXES, base_branch=branch, replace=settings.REPLACE, mirror=mirror_path)

    branchid = -1
    base_branch = branch
    bitbake_branch = branch
    for lindex in index.index:
        if 'CFG' in lindex:
            base_branch = lindex['CFG']['BRANCH']
            bitbake_branch = branch

        for b in lindex['branches']:
            if 'name' in b and b['name'] == base_branch:
                branchid = b['id']
                if 'bitbake_branch' in b and b['bitbake_branch'] != "":
                    bitbake_branch = b['bitbake_branch']
                break

        logger.info('Discovered base_branch: %s (%s)' % (base_branch, branchid))
        logger.info('Discovered bitbake_branch: %s' % bitbake_branch)

        for layer in lindex['layerItems']:
            logger.info('Processing layer %s...' % layer['name'])

            # Identify, manipulate and copy the layer...
            if 'vcs_url' in layer:
                full_url = layer['vcs_url'].replace('#BASE_URL#/', '')
                base_url = layer['vcs_url'].split('/')[-1]

                layer['vcs_url'] = '#BASE_URL#' + '/' + base_url
                layer['vcs_web_url'] = ''
                layer['vcs_web_tree_base_url'] = ''
                layer['vcs_web_file_base_url'] = ''
                layer['mailing_list_url'] = ''

                # Find actual_branch if one is there
                revision = base_branch
                for lb in lindex['layerBranches']:
                    if lb['branch'] == branchid and lb['layer'] == layer['id']:
                        if lb['actual_branch'] != "":
                            revision = lb['actual_branch']

                src = full_url
                dst = os.path.join(dest, os.path.basename(src))

                if src not in processed_list:
                    push_or_copy(layer['name'], src, dst, revision)
                    processed_list.append(src)

            xml_dir = get_xml_dir(layer['name'], dst_base_mirror)

            def xml_dest_dir(_xml_dir, _name):
                if not _xml_dir:
                    return None
                return os.path.join(_xml_dir, _name)

            src = os.path.join(mirror_path, 'xml', '%s.inc' % layer['name'])
            if os.path.exists(src):
                xml_dst = xml_dest_dir(xml_dir, '%s.inc' % layer['name'])
                for name in transform_xml(src, xml_dst):
                    dst = os.path.join(dest, os.path.basename(name))
                    if name not in processed_list:
                        push_or_copy(layer['name'], name, dst)
                        processed_list.append(name)

            src = os.path.join(mirror_path, 'xml', '%s.xml' % layer['name'])
            if os.path.exists(src):
                xml_dst = xml_dest_dir(xml_dir, '%s.xml' % layer['name'])
                for name in transform_xml(src, xml_dst):
                    dst = os.path.join(dest, os.path.basename(name))
                    if name not in processed_list:
                        push_or_copy(layer['name'], name, dst)
                        processed_list.append(name)

            # OpenEmbedded-Core is a bit unique.  There are a few items
            # that need to be grouped by this subset entry, these are
            # items NOT included in the index or default.xml
            #
            #   wrlinux-x
            #   git-repo
            #   bitbake
            if layer['name'] == 'openembedded-core':
                # wrlinux-x (or whatever it's called) convert to bare using .git
                src = os.path.join(setup_dir, '.git')
                dst = os.path.join(dest, os.path.basename(setup_dir))
                if src not in processed_list:
                    push_or_copy(layer['name'], src, dst, branch)
                    processed_list.append(src)

                # git-repo
                src = os.path.join(os.path.dirname(full_url), 'git-repo')
                dst = os.path.join(dest, os.path.basename(src))
                if src not in processed_list:
                    push_or_copy(layer['name'], src, dst)
                    processed_list.append(src)

                # bitbake
                src = os.path.join(os.path.dirname(full_url), 'bitbake')
                dst = os.path.join(dest, os.path.basename(src))
                if src not in processed_list:
                    push_or_copy(layer['name'], src, dst, bitbake_branch)
                    processed_list.append(src)

                src = os.path.join(mirror_path, 'xml', 'bitbake.inc')
                if os.path.exists(src):
                    xml_dst = xml_dest_dir(xml_dir, 'bitbake.inc')
                    for name in transform_xml(src, xml_dst):
                        dst = os.path.join(dest, os.path.basename(name))
                        if name not in processed_list:
                            push_or_copy(layer['name'], name, dst)
                            processed_list.append(name)

                src = os.path.join(mirror_path, 'xml', 'bitbake.xml')
                if os.path.exists(src):
                    xml_dst = xml_dest_dir(xml_dir, 'bitbake.xml')
                    for name in transform_xml(src, xml_dst):
                        dst = os.path.join(dest, os.path.basename(name))
                        if name not in processed_list:
                            push_or_copy(layer['name'], name, dst)
                            processed_list.append(name)

        # dst_base_mirror may not exist if we're subsetting...
        os.makedirs(dst_base_mirror, exist_ok=True)
        index.serialize_index(lindex, os.path.join(dst_base_mirror, lindex['CFG']['DESCRIPTION']), split=True, IncludeCFG=True, mirror=True, base_url=base_url)

        # Since serialize can't subset, we do it manually...
        # if the rules change in layer_index.py, adjust them here..
        if subset_folders:
            base_branch = branch
            if 'CFG' in lindex:
                base_branch = lindex['CFG']['BRANCH']

            for layer in lindex['layerItems']:
                json = "%s__%s__%s.json" % (lindex['CFG']['DESCRIPTION'], base_branch, layer['name'])
                json = json.translate(str.maketrans('/ ', '__'))

                src = os.path.join(dst_base_mirror, json)
                mirror_dir = get_mirror_dir(layer['name'], dst_base_mirror)
                if not mirror_dir:
                    # Skipped item, remove it and continue
                    logger.plain('rm %s' % src)
                    os.remove(src)
                    continue
                dst = os.path.join(mirror_dir, json)
                os.makedirs(os.path.dirname(dst), exist_ok=True)
                logger.plain('mv %s -> %s' % (src, dst))
                os.rename(src, dst)

            # Directory is expected to be empty, remove it.
            os.rmdir(dst_base_mirror)

    #### Now process anythign else we've not yet processed
    logger.info('Processing left-overs...')

    # Now process the default.xml, and process anything not previous processed...
    tree = ET.parse('default.xml')
    root = tree.getroot()

    default_revision = None
    base_url = None
    for child in root:
        if child.tag == 'remote':
            if 'fetch' in child.attrib:
                base_url = child.attrib['fetch']

        if child.tag == 'default':
            if 'revision' in child.attrib:
                default_revision = child.attrib['revision']

        if child.tag != 'project':
            continue

        src = child.attrib['name']

        if src in processed_list or src + '.git' in processed_list:
            continue

        dst = os.path.join(dest, os.path.basename(src))

        revision = None
        if not ('bare' in child.attrib and child.attrib['bare'] == 'True'):
            revision = default_revision
            if 'revision' in child.attrib:
                revision = child.attrib['revision']

        push_or_copy(os.path.basename(src), src, dst, revision)

    #### Update the mirror-index repositories (git add/git commit)
    logger.plain('Updating mirror-index repositories...')

    # git add file.
    if subset_folders:
        index_list = []
        for layer in subset_folders:
            if subset_folders[layer] == "[SKIP]":
                continue
            dst_mirror = get_mirror_dir(layer, dst_base_mirror)
            if dst_mirror not in index_list:
                index_list.append(dst_mirror)

        for dst_mirror in index_list:
            update_mirror(dst_mirror)
    else:
        update_mirror(dst_base_mirror)

    copy_premirrors_dl(dest)

    logger.plain('Done')
    return 0


# Define globals
if __name__ == '__main__':
    logger = logger_setup.setup_logging()
    dest, git_push, subset_file, strip_git = config_args(sys.argv[1:])

    subset_folders = None
    branch = None

    setup_dir = os.path.dirname(os.path.dirname(sys.argv[0]))

    ret = main()
    sys.exit(ret)


================================================
FILE: bin/layer_index.py
================================================
# Copyright (C) 2016 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
# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

import json

import sys
import os
import difflib


from collections import OrderedDict

import logger_setup

import utils_setup

import texttable as tt

# type, url/path, description, cache
# type:  restapi-web   - REST API from a LayerIndex-web
#        restapi-files - REST API, but only from files
#        export        - Exported DB from a LayerIndex-web -- reads file(s)

logger = logger_setup.setup_logging()
class Layer_Index():
    # Index in REST-API format...  This is used by external items.
    index = []

    def __init__(self, indexcfg=[], base_branch=None, replace=[], mirror=None):
        self.index = []

        # Do we have local mirror entries to load?
        m_index = {}

        if mirror:
            for (dirpath, dirnames, filenames) in os.walk(mirror):
                if dirpath.endswith('/.git') or '/.git/' in dirpath or dirpath.endswith('/xml') or '/xml/' in dirpath:
                    continue
                for filename in filenames:
                    # Serialize function, ALWAYS writes out w/ .json extension
                    if not filename.endswith('.json'):
                        continue
                    pindex = self.load_serialized_index(os.path.join(dirpath, filename), name='Mirrored Index')
                    # A mirror can be made up of multiple indexes, so we need to identify which one they belong to
                    if pindex and pindex['CFG']['DESCRIPTION'] in m_index:
                        lindex = m_index[pindex['CFG']['DESCRIPTION']]
                        for entry in pindex:
                            if 'apilinks' == entry:
                                continue
                            if 'CFG' == entry:
                                # Conflicts don't matter here, just accept it
                                lindex[entry] = pindex[entry]
                                continue
                            if entry not in lindex:
                                lindex[entry] = []
                            try:
                                lindex[entry] = self.__add_cmp_lists(pindex[entry], lindex[entry])
                            except TypeError as error:
                                raise TypeError('Merge failed of pindex[%s] and lindex[%s]: %s' % (entry, entry, error))
                    else: # Not already know
                        m_index[pindex['CFG']['DESCRIPTION']] = pindex

        for cfg in indexcfg:
            lindex = None

            branch = base_branch
            indextype = None
            indexurl = None
            indexname = None
            indexcache = None

            if 'TYPE' in cfg:
                indextype = cfg['TYPE']

            if 'URL' in cfg:
                indexurl = cfg['URL']

            if 'DESCRIPTION' in cfg:
                indexname = cfg['DESCRIPTION']

            if 'CACHE' in cfg:
                indexcache = cfg['CACHE']

            if 'BRANCH' in cfg:
                branch = cfg['BRANCH']

            # Replace magic values with real values...
            for (find, rep) in replace:
                indexurl = indexurl.replace(find, rep)
                if branch:
                    branch = branch.replace(find, rep)

            # Do we have an mirrored version? If so use it, skip regular processing
            if indexname in m_index:
                logger.plain('Using index %s from the mirror index...' % (indexname))
                lindex = m_index[indexname]
            else:
               logger.plain('Loading index %s from %s...' % (indexname, indexurl))

            # If not previously loaded from the mirror, attempt to load...
            if not lindex:
                if indextype == 'restapi-web':
                    lindex = self.load_API_Index(indexurl, indexname, branches=branch)
                elif indextype == 'restapi-files':
                    lindex = self.load_serialized_index(indexurl, name=indexname)
                elif indextype == 'export':
                    lindex = self.load_django_export(indexurl, name=indexname)
                elif not lindex:
                    # Unknown index type...
                    logger.error('Unknown index type %s' % indextype)
                    raise SyntaxError('Unknown index type %s' % indextype)

            # If we couldn't pull from the regular location, pull from the cache!
            if lindex is None and indexcache and os.path.exists(indexcache + '.json'):
                logger.plain('Falling back to the index cache %s...' % (indexcache))
                lindex = self.load_serialized_index(indexcache + '.json', name=indexname, branches=[branch])

            if not lindex or 'branches' not in lindex or 'layerItems' not in lindex or 'layerBranches' not in lindex:
                logger.warning('Index %s was empty... Ignoring.' % indexname)
                continue

            # Start data transforms...
            for entry in lindex['layerItems']:
                for obj in entry:
                    # Run replace on any 'url' items.
                    if 'url' in obj:
                        vcs_url = entry[obj]
                        for (find, rep) in replace:
                            vcs_url = vcs_url.replace(find, rep)
                        entry[obj] = vcs_url

            # Cache the data we loaded... (after replacements) if we loaded data.
            if lindex and indexcache:
                dir = os.path.dirname(indexcache)
                if dir:
                    os.makedirs(dir, exist_ok=True)
                self.serialize_index(lindex, indexcache, split=False)

            lindex['CFG'] = cfg
            lindex['CFG']['BRANCH'] = branch

            if lindex and 'distros' in lindex:
                # Default setup is actually implemented as 'nodistro'
                for (idx, dist) in enumerate(lindex['distros']):
                    if dist['name'] == "defaultsetup":
                        dist['name'] = 'nodistro'
                        lindex['distros'][idx] = dist

            # Everything works off layerBranches, so make sure to keep it sorted!
            lindex['layerBranches'] = self.sortEntry(lindex['layerBranches'])

            if lindex:
                self.index.append(lindex)


    def load_API_Index(self, url, name=None, branches=None):
        """
            Fetches layer information from a remote layer index.
            The return value is a dictionary containing API,
            layer, branch, dependency, recipe, machine, distro,
            and template information.

            url is the url to the rest api of the layer index, such as:
            http://layers.openembedded.org/layerindex/api/

            branches is a str or list of branches to filter on
        """
        lindex = {}

        assert url is not None

        logger.debug('Loading %s from url %s...' % (name, url))

        def _get_json_response(apiurl=None, retry=True):
            assert apiurl is not None

            res = utils_setup.fetch_url(apiurl)

            try:
                parsed = json.loads(res.read().decode('utf-8'))
            except ConnectionResetError:
                if retry:
                    logger.debug("%s: Connection reset by peer.  Retrying..." % url)
                    parsed = _get_json_response(apiurl=apiurl, retry=False)
                    logger.debug("%s: retry successful.")
                else:
                    logger.critical("%s: Connection reset by peer." % url)
                    logger.critical("Is there a firewall blocking your connection?")
                    sys.exit(1)
            except:
                if retry:
                    logger.debug("%s: get response failed. Retrying..." % url)
                    parsed = _get_json_response(apiurl=apiurl, retry=False)
                    logger.debug("%s: retry successful.")
                else:
                    logger.critical("%s: get response failed" % url)
                    sys.exit(1)

            return parsed

        from urllib.request import URLError
        try:
            lindex['apilinks'] = _get_json_response(url)
        except URLError as e:
            logger.warning("Index %s: could not connect to %s: %s" % (name, url, e.reason))
            return None

        filter = ""
        # If it's list, keep it, if it's a string change it to a list
        if branches and type(branches) == type(str()):
            branches = [branches]
        if branches:
            filter = "?filter=name:%s" \
                     % "OR".join(branches)
        lindex['branches'] = _get_json_response(lindex['apilinks']['branches'] + filter)

        if not lindex['branches']:
            logger.warning("No valid branches (%s) found at url %s." % (branches or "*", url))
            return lindex

        filter = ""
        if branches:
            filter = "?filter=branch__name:%s" \
                     % "OR".join(branches)
        lindex['layerBranches'] = _get_json_response(lindex['apilinks']['layerBranches'] + filter)
        if not lindex['layerBranches']:
            logger.warning("No layers on branches (%s) found at url %s." % (branches or "*", url))
            return lindex

        layerids = []
        for i, layerBranch in enumerate(lindex['layerBranches']):
            layerids.append("%s" % layerBranch['layer'])

        lindex['layerItems'] = _get_json_response(lindex['apilinks']['layerItems'])

        filter = ""
        if branches:
            filter = "?filter=layerbranch__branch__name:%s" \
                     % "OR".join(branches)
        lindex['layerDependencies'] = _get_json_response(lindex['apilinks']['layerDependencies'] + filter)

        filter = ""
        if branches:
            filter = "?filter=layerbranch__branch__name:%s" \
                     % "OR".join(branches)
        lindex['machines'] = _get_json_response(lindex['apilinks']['machines'] + filter)

        filter = ""
        if branches:
            filter = "?filter=layerbranch__branch__name:%s" \
                     % "OR".join(branches)
        lindex['recipes'] = _get_json_response(lindex['apilinks']['recipes'] + filter)

        filter = ""
        if branches:
            filter = "?filter=layerbranch__branch__name:%s" \
                     % "OR".join(branches)
        if 'distros' in lindex['apilinks']:
            lindex['distros'] = _get_json_response(lindex['apilinks']['distros'] + filter)
        else:
            # Not all layer indexes have a distribution API.  If not we need to emulate nodistro.
            lindex['distros'] = []
            idx = 1
            for branch in lindex['branches']:
                for lb in self.getLayerBranch(lindex, branch['id'], name='openembedded-core'):
                    lindex['distros'].append({"layerbranch": lb['id'], "id": idx, "description": "default", "updated": "2016-01-01T00:00:00+0000", "name": "nodistro"})
                    idx = idx + 1

        filter = ""
        if branches:
            filter = "?filter=layerbranch__branch__name:%s" \
                     % "OR".join(branches)
        if 'wrtemplates' in lindex['apilinks']:
            lindex['wrtemplates'] = _get_json_response(lindex['apilinks']['wrtemplates'] + filter)
        else:
            lindex['wrtemplates'] = []

        if 'YPCompatibleVersions' in lindex['apilinks']:
            lindex['YPCompatibleVersions'] = _get_json_response(lindex['apilinks']['YPCompatibleVersions'])
        else:
            lindex['YPCompatibleVersions'] = []

        logger.debug('...loading %s from url %s, done.' % (name, url))

        return lindex

    # Merge listone and listtwo, returning listtwo
    def __add_cmp_lists(self, listone, listtwo):
        # Copy the items from listone, into listtwo -- if it isn't already
        # there..  if it is there, verify it's the same or raise an error...

        if not listone: # List one is empty, just return listtwo
            return listtwo

        if not listtwo: # List two is empty, just return listone
            return listone

        for one in reversed(listone):
            found = False
            for two in listtwo:
                if 'id' in one and 'id' in two:
                    if one['id'] == two['id']:
                        found = True
                        # Contents need to be the same!
                        if one != two:
                            # Something is out of sync here...
                            raise TypeError('Cannot merge two objects with the same id %s, but different contents:\n%s\n%s' % (one['id'], one, two))
                        break
                else:
                    # This is not a valid object
                    if not 'id' in one and 'id' in two:
                        raise TypeError('No id in object from the first parameter list:\n%s' % (one))
                    if 'id' in one and not 'id' in two:
                        raise TypeError('No id in object from the second parameter list:\n%s' % (two))
                    if not 'id' in one and not 'id' in two:
                        raise TypeError('No id in object in either parameter list:\n%s\n%s' % (one, two))
            if not found:
                listtwo.append(one)
        return listtwo

    def load_serialized_index(self, path, name=None, branches=None):
        lindex = {}
        lindex['branches'] = []
        lindex['layerItems'] = []
        lindex['layerBranches'] = []
        lindex['layerDependencies'] = []
        lindex['recipes'] = []
        lindex['machines'] = []
        lindex['distros'] = []
        lindex['wrtemplates'] = []
        lindex['YPCompatibleVersions'] = []

        assert path is not None

        def loadCache(path):
            logger.debug('Loading json file %s' % path)
            pindex = json.load(open(path, 'rt', encoding='utf-8'))

            for entry in pindex:
                if 'apilinks' == entry:
                    continue
                if 'CFG' == entry:
                    # Conflicts don't matter here, just accept it
                    lindex[entry] = pindex[entry]
                    continue
                if entry not in lindex:
                    lindex[entry] = []
                try:
                    lindex[entry] = self.__add_cmp_lists(pindex[entry], lindex[entry])
                except TypeError as error:
                    raise TypeError('Merge failed of pindex[%s] and lindex[%s]: %s' % (entry, entry, error))

            logger.debug('...loading json file %s, done.' % path)

        if os.path.exists(path) and os.path.isdir(path):
            logger.debug('Loading %s from directory %s...' % (name, path))
            for (dirpath, dirnames, filenames) in os.walk(path):
                for filename in filenames:
                    if not filename.endswith('.json'):
                        continue
                    fpath = os.path.join(dirpath, filename)
                    loadCache(fpath)
            logger.debug('...loading %s from path %s, done.' % (name, path))
        elif os.path.exists(path):
            logger.debug('Loading %s from path %s...' % (name, path))
            loadCache(path)
            logger.debug('...loading %s from path %s, done.' % (name, path))
        else:
            logger.error("Index %s: could not find path %s" % (name, path))
            return None

        return lindex

    def load_django_export(self, path, name=None, branches=None):
        lindex = {}
        lindex['branches'] = []
        lindex['layerItems'] = []
        lindex['layerBranches'] = []
        lindex['layerDependencies'] = []
        lindex['recipes'] = []
        lindex['machines'] = []
        lindex['distros'] = []
        lindex['wrtemplates'] = []
        lindex['YPCompatibleVersions'] = []

        assert path is not None

        def loadDB(path):
            def constructObject(entry):
                obj = entry['fields'].copy()
                obj['id'] = entry['pk']
                return obj

            pindex = {}

            logger.debug('Loading json file %s' % path)
            dbindex = json.load(open(path, 'rt', encoding='utf-8'))

            # We discard anything that doesn't start with 'layerindex.'
            # the other data is adminstrative and stuff we should not mess with
            for entry in dbindex:
                if 'model' in entry:
                    model = entry['model']
                    if model.startswith('layerindex.'):
                        if 'branch' == model[11:]:
                            name = 'branches'
                        elif 'layeritem' == model[11:]:
                            name = 'layerItems'
                        elif 'layerbranch' == model[11:]:
                            name = 'layerBranches'
                        elif 'layerdependency' == model[11:]:
                            name = 'layerDependencies'
                        elif 'recipe' == model[11:]:
                            name = 'recipes'
                        elif 'machine' == model[11:]:
                            name = 'machines'
                        elif 'distro' == model[11:]:
                            name = 'distros'
                        elif 'wrtemplate' == model[11:]:
                            name = 'wrtemplates'
                        elif 'ypcompatibleversion' == model[11:]:
                            name = 'YPCompatibleVersions'
                        else:
                            name = model[11:]

                        if name not in pindex:
                            pindex[name] = []
                        pindex[name].append(constructObject(entry))

            for entry in pindex:
                if entry not in lindex:
                    lindex[entry] = []
                try:
                    lindex[entry] = self.__add_cmp_lists(pindex[entry], lindex[entry])
                except TypeError as error:
                    raise TypeError('Merge failed of pindex[%s] and lindex[%s]: %s' % (entry, entry, error))

            logger.debug('...loading json file %s, done.' % path)

        if os.path.exists(path) and os.path.isdir(path):
            logger.debug('Loading %s from path %s...' % (name, path))
            for (dirpath, dirnames, filenames) in os.walk(path):
                for filename in filenames:
                    if not filename.endswith('.json'):
                        continue
                    fpath = os.path.join(dirpath, filename)
                    loadDB(fpath)
            logger.debug('...loading %s from path %s, done.' % (name, path))
        elif os.path.exists(path):
            logger.debug('Loading %s from path %s...' % (name, path))
            loadDB(path)
            logger.debug('...loading %s from path %s, done.' % (name, path))
        else:
            logger.error("Index %s: could not find path %s" % (name, path))
            return None

        return lindex

    # Provide a function to sort layer index content (restapi format)
    # When serializing the data this is import to limit
    # changes to the files...
    def sortEntry(self, item):
        newitem = item
        try:
            if type(newitem) == type(dict()):
                newitem = OrderedDict(sorted(newitem.items(), key=lambda t: t[0]))
            elif type(newitem) == type(list()):
                newitem.sort(key=lambda obj: obj['id'])
                for index, entry in enumerate(newitem):
                    newitem[index] = self.sortEntry(newitem[index])
        except:
            pass

        return newitem

    # Sort and return a new restapi style index
    def sortRestApi(self, index):
        lindex = self.sortEntry(index)
        for entry in lindex:
            lindex[entry] = self.sortEntry(lindex[entry])
        return lindex

    # layerBranches must be a list of layerBranch entries to parse, it only affects
    # output when 'split' is True.
    def serialize_index(self, lindex, path, split=False, layerBranches=None, IncludeCFG=False, mirror=False, base_url=None):
        # If we're not splitting, we must be caching...
        if not split:
            dir = os.path.dirname(path)
            base = os.path.basename(path)
            fname = base.translate(str.maketrans('/ ', '__'))
            fpath = os.path.join(dir, fname)

            # Need to filter out local information
            pindex = {}
            for entry in lindex:
                if (IncludeCFG == False and 'CFG' == entry) or 'apilinks' == entry:
                    continue
                pindex[entry] = lindex[entry]

            json.dump(self.sortRestApi(pindex), open(fpath + '.json', 'wt'), indent=4)
            return

        # We serialize based on the layerBranches, this allows us to subset
        # everything in a logical way...
        if not layerBranches:
            layerBranches = lindex['layerBranches']
        for lb in layerBranches:
            pindex = {}

            def filter_item(lb, objects):
                filtered = []
                for obj in lindex[objects]:
                    if 'layerbranch' in obj:
                        if obj['layerbranch'] == lb['id']:
                            filtered.append(obj)
                    elif 'layer' in obj:
                        for layer in self.find_layer(lindex, layerBranch=lb):
                            if  obj['layer'] == layer['id']:
                                filtered.append(obj)
                    else:
                        # No simple filter method, just include it...
                        filtered.append(obj)
                return filtered

            for entry in lindex:
                if (IncludeCFG == False and 'CFG' == entry) or 'apilinks' == entry or 'branches' == entry or 'layerBranches' == entry or 'layerItems' == entry:
                    continue
                elif (IncludeCFG == True and 'CFG' == entry):
                    pindex[entry] = lindex[entry]
                    continue
                pindex[entry] = filter_item(lb, entry)

            for branch in lindex['branches']:
                if branch['id'] == lb['branch']:
                    pindex['branches'] = [branch]

            # We must include the layerbranch for what we are processing...
            pindex['layerBranches'] = [lb]

            # We also need to include the layerbranch for any required dependencies...
            (required, recommended) = self.getDependencies(lindex, lb)
            for req_lb in required:
                found = False
                for p_lb in pindex['layerBranches']:
                    if p_lb['id'] == req_lb['id']:
                        found = True
                        break
                if found == False:
                    pindex['layerBranches'].append(req_lb)

            # We need to include the layerItems for each layerBranch
            pindex['layerItems'] = []
            for p_lb in pindex['layerBranches']:
                for li in self.find_layer(lindex, layerBranch=p_lb):
                    found = False
                    for p_li in pindex['layerItems']:
                        if p_li['id'] == li['id']:
                            found = True
                            break
                    if found == False:
                        pindex['layerItems'].append(li)

            # If we're mirroring, we need to adjust the URL for the
            # mirror to work properly.  Replace remote with BASE_URL.
            # (This uses the same logic as the default.xml construction)
            if mirror == True:
                from urllib.parse import urlparse

                from copy import deepcopy
                pindex['layerItems'] = deepcopy(pindex['layerItems'])
                for layer in pindex['layerItems']:
                    vcs_url = layer['vcs_url']

                    if base_url and vcs_url.startswith(base_url):
                        layer['vcs_url'] = layer['vcs_url'].replace(base_url, '#BASE_URL#')
                    else:
                        url = urlparse(vcs_url)

                        if url.scheme:
                            layer['vcs_url'] = layer['vcs_url'].replace(url.scheme + '://' + url.netloc, '#BASE_URL#')

            dir = os.path.dirname(path)
            base = os.path.basename(path)
            fname = base + '__' + pindex['branches'][0]['name'] + '__' + pindex['layerItems'][0]['name']
            fname = fname.translate(str.maketrans('/ ', '__'))
            fpath = os.path.join(dir, fname)

            json.dump(self.sortRestApi(pindex), open(fpath + '.json', 'wt'), indent=4)

    # layerBranches must be a list of layerBranch entries to parse, it only affects
    # output when 'split' is True.
    def serialize_django_export(self, lindex, path, split=False, layerBranches=None, IncludeCFG=False):
        def convertToDjango(restindex):
            dbindex = []

            def constructObject(entry, model):
                obj = OrderedDict()
                obj['pk'] = entry['id']
                obj['model'] = model
                obj['fields'] = OrderedDict(sorted(entry.items(), key=lambda t: t[0]))
                del obj['fields']['id']

                if model == 'layerindex.branch' and 'update_environment' in obj['fields']:
                    if 'pythonenvironment' not in restindex:
                        # We have 'lost' the environment, so workaround it being missing...
                        obj['fields']['update_environment'] = None

                return obj

            # Convert the restindex to a dbindex
            for entry in restindex:
                if (IncludeCFG == False and 'CFG' == entry) or 'apilinks' == entry:
                    continue
                elif 'branches' == entry:
                    model = 'layerindex.branch'
                elif 'layerItems' == entry:
                    model = 'layerindex.layeritem'
                elif 'layerBranches' == entry:
                    model = 'layerindex.layerbranch'
                elif 'layerDependencies' == entry:
                    model = 'layerindex.layerdependency'
                elif 'recipes' == entry:
                    model = 'layerindex.recipe'
                elif 'machines' == entry:
                    model = 'layerindex.machine'
                elif 'distros' == entry:
                    model = 'layerindex.distro'
                elif 'wrtemplates' == entry:
                    model = 'layerindex.wrtemplate'
                else:
                    model = 'layerindex.' + entry

                for item in restindex[entry]:
                    dbindex.append(constructObject(item, model))

            return dbindex

        # Just write out a single master file..
        if not split:
            dir = os.path.dirname(path)
            base = os.path.basename(path)
            fname = base.translate(str.maketrans('/ ', '__'))
            fpath = os.path.join(dir, fname)

            # Need to filter out local information
            pindex = {}
            for entry in lindex:
                if (IncludeCFG == False and 'CFG' == entry) or 'apilinks' == entry:
                    continue
                pindex[entry] = lindex[entry]

            json.dump(convertToDjango(self.sortRestApi(pindex)), open(fpath + '.json', 'wt'), indent=4)
            return

        # We serialize based on the layerBranches, this allows us to subset
        # everything in a logical way...
        if not layerBranches:
            layerBranches = lindex['layerBranches']
        for lb in layerBranches:
            pindex = {}

            def filter_item(lb, objects):
                filtered = []
                for obj in lindex[objects]:
                    if 'layerbranch' in obj:
                        if obj['layerbranch'] == lb['id']:
                            filtered.append(obj)
                    elif 'layer' in obj:
                        for layer in self.find_layer(lindex, layerBranch=lb):
                            if obj['layer'] == layer['id']:
                                filtered.append(obj)
                    else:
                        # No simple filter method, just include it...
                        filtered.append(obj)
                return filtered

            for entry in lindex:
                if (IncludeCFG == False and 'CFG' == entry) or 'apilinks' == entry or 'branches' == entry or 'layerBranches' == entry or 'layerItems' == entry:
                    continue
                pindex[entry] = filter_item(lb, entry)

            pindex['layerBranches'] = [lb]
            pindex['layerItems'] = self.find_layer(lindex, layerBranch=lb)

            for branch in lindex['branches']:
                if branch['id'] == lb['branch']:
                    pindex['branches'] = [branch]

            dir = os.path.dirname(path)
            base = os.path.basename(path)
            fname = base + '__' + pindex['branches'][0]['name'] + '__' + pindex['layerItems'][0]['name']
            fname = fname.translate(str.maketrans('/ ', '__'))
            fpath = os.path.join(dir, fname)

            json.dump(convertToDjango(self.sortRestApi(pindex)), open(fpath + '.json', 'wt'), indent=4)

    def print_close_matches(self, key, value, full_list):
        msg = '%s "%s" not found' % (key, value)
        close_matches = difflib.get_close_matches(value, full_list)
        if close_matches:
            msg += ". Close matches:\n  %s" % '\n  '.join(list(set(close_matches)))
        logger.critical(msg + '\n')

    def find_layer(self, lindex, id=None, name=None, layerBranch=None, layerBranchId=None, distro=None, machine=None, recipe=None, wrtemplate=None):
        result = []

        if layerBranch:
            id = layerBranch['layer']

        # Only one layerItem per lindex, so break once we find it
        if id:
            for layer in lindex['layerItems']:
                if layer['id'] == id:
                    result.append(layer)
                    if layerBranch:
                        result[-1]['collection'] = layerBranch['collection']
                    else:
                        for branch in lindex['layerBranches']:
                            if branch['layer'] == id:
                                result[-1]['collection'] = branch['collection']
                                break
                    break
            return result

        if name:
            full_list = []
            found = False
            for layer in lindex['layerItems']:
                value_from_index = layer['name']
                full_list.append(value_from_index)
                if value_from_index == name:
                    result.append(layer)
                    for branch in lindex['layerBranches']:
                        if branch['layer'] == layer['id']:
                            result[-1]['collection'] = branch['collection']
                            break
                    found = True
                    break
            if not found:
                self.print_close_matches('layer', name, full_list)
            return result

        layerBranchIds = []
        if layerBranchId:
            layerBranchIds.append(layerBranchId)

        args = {
            'distros': distro,
            'machines': machine,
            'recipes': recipe,
            'wrtemplates': wrtemplate
        }

        for k, v in args.items():
            if v:
                full_list = []
                found = False
                for index_dict in lindex[k]:
                    if k == 'recipes':
                        value_from_index = index_dict['pn']
                    else:
                        value_from_index = index_dict['name']
                    full_list.append(value_from_index)
                    if value_from_index == v:
                        found = True
                        layerBranchIds.append(index_dict['layerbranch'])
                if not found:
                    self.print_close_matches(k.rstrip('s'), v, full_list)

        if layerBranchIds:
            for layerBranch in lindex['layerBranches']:
                for layerBranchId in layerBranchIds:
                    if layerBranch['id'] == layerBranchId:
                        for layer in lindex['layerItems']:
                            if layer['id'] == layerBranch['layer']:
                                result.append(layer)
                                result[-1]['collection'] = layerBranch['collection']
            return result

        return None

    def get_index_layers(self, base_branch):
        index_layers = {}
        for lindex in self.index:
            index = lindex['CFG']['DESCRIPTION'] or lindex['CFG']['URL']
            index_layers[index] = []
            branchid = self.getBranchId(lindex, self.getIndexBranch(default=base_branch, lindex=lindex))
            if branchid:
                for lb in lindex['layerBranches']:
                    if lb['branch'] == branchid:
                        index_layers[index].extend(self.find_layer(lindex, layerBranch=lb))

        return index_layers

    def list_layers(self, base_branch):
        index_layers = self.get_index_layers(base_branch)
        for index, layers in index_layers.items():
            logger.plain ('Index: %s' % index)

            table = tt.Texttable()
            table.set_deco(tt.Texttable.HEADER)
            table.set_header_align(['l', 'l'])
            table.set_cols_align(['l', 'l'])
            table.header(['layer', 'summary'])
            table.set_cols_dtype(['t', 't'])
            for layer in layers:
                name = layer['name']
                summary = layer['summary'] or name
                table.add_row([name, summary])
            s = table.draw()
            logger.plain (s)
            logger.plain ('')

    def getYPCompatibleVersion(self, lindex, id):
        if not id:
            return []
        for vers in lindex['YPCompatibleVersions']:
            if vers['id'] == id:
                return vers['name'].split()
        return []

    def list_obj(self, base_branch, object, display, compat='all'):
        for lindex in self.index:
            logger.plain ('Index: %s' % (lindex['CFG']['DESCRIPTION'] or lindex['CFG']['URL']))

            table = tt.Texttable()
            table.set_deco(tt.Texttable.HEADER)
            table.set_header_align(['l', 'l', 'l'])
            table.set_cols_align(['l', 'l', 'l'])
            table.header(['display', 'description', 'layer'])
            table.set_cols_dtype(['t', 't', 't'])
            table.set_max_width(100)
            branchid = self.getBranchId(lindex, self.getIndexBranch(default=base_branch, lindex=lindex))
            if branchid:
                # there are more layerBranches then objects (usually)...
                for lb in lindex['layerBranches']:
                    if compat != 'all':
                        if compat not in self.getYPCompatibleVersion(lindex, lb['yp_compatible_version']):
                            continue
                    for layer in self.find_layer(lindex, layerBranch=lb):
                        for obj in lindex[object]:
                            if obj['layerbranch'] == lb['id'] and lb['branch'] == branchid:
                                lname = layer['name']
                                name = obj['name']
                                description = (obj['description'] or name).strip()
                                table.add_row([name, description, lname])
                s = table.draw()
                logger.plain(s)
            logger.plain ('')

    def get_machines(self, base_branch, compat='all'):
        machines = []
        for lindex in self.index:
            branchid = self.getBranchId(lindex, self.getIndexBranch(default=base_branch, lindex=lindex))
            if branchid:
                for lb in lindex['layerBranches']:
                    if compat != 'all':
                        if compat not in self.getYPCompatibleVersion(lindex, lb['yp_compatible_version']):
                            continue
                    for layer in self.find_layer(lindex, layerBranch=lb):
                        for obj in lindex['machines']:
                            if obj['layerbranch'] == lb['id'] and lb['branch'] == branchid:
                                machines.append(obj['name'])
        return machines


    def list_distros(self, base_branch, compat):
        self.list_obj(base_branch, 'distros', 'distro', compat)

    def list_machines(self, base_branch, compat):
        self.list_obj(base_branch, 'machines', 'machine', compat)

    def list_wrtemplates(self, base_branch, compat):
        self.list_obj(base_branch, 'wrtemplates', 'templates', compat)

    def list_recipes(self, base_branch):
        for lindex in self.index:
            logger.plain ('Index: %s' % (lindex['CFG']['DESCRIPTION'] or lindex['CFG']['URL']))
            logger.plain ('%s %s %s' % (('{:15}'.format('recipe'), '{:9}'.format('version'), 'summary')))
            logger.plain ('{:-^80}'.format(""))
            branchid = self.getBranchId(lindex, self.getIndexBranch(default=base_branch, lindex=lindex))
            if branchid:
                # there are more layerBranches then objects (usually)...
                for lb in lindex['layerBranches']:
                    for layer in self.find_layer(lindex, layerBranch=lb):
                        for obj in lindex['recipes']:
                            if obj['layerbranch'] == lb['id'] and lb['branch'] == branchid:
                                lname = layer['name']
                                pn = obj['pn']
                                pv = obj['pv']
                                summary = (obj['summary'] or pn).strip()
                                logger.plain('%s %s %s' % ('{:15}'.format(pn), '{:9}'.format(pv), summary[:50]))
            logger.plain ('')

    def getBranchId(self, lindex, name):
        for branch in lindex['branches']:
            if branch['name'] == name:
                return branch['id']
        return None

    def getLayerBranch(self, lindex, branchid, layerBranchId=None, collection=None, name=None, distro=None, machine=None, recipe=None, wrtemplate=None, layerItem=None):
        result = []
        if layerBranchId:
            for lb in lindex['layerBranches']:
                if branchid == lb['branch'] and layerBranchId == lb['id']:
                    result.append(lb)
                    break
            return result

        if collection:
            for lb in lindex['layerBranches']:
                if 'collection' in lb and collection == lb['collection']:
                    result.append(lb)
                    break
            return result

        layerItems = []
        if layerItem:
            layerItems.append(layerItem)

        args = {
            'name': name,
            'distro': distro,
            'machine': machine,
            'recipe': recipe,
            'wrtemplate': wrtemplate
        }
        for k, v in args.items():
            if v:
                if k == 'name':
                    layerItem = self.find_layer(lindex, name=v)
                elif k == 'distro':
                    layerItem = self.find_layer(lindex, distro=v)
                elif k == 'machine':
                    layerItem = self.find_layer(lindex, machine=v)
                elif k == 'recipe':
                    layerItem = self.find_layer(lindex, recipe=v)
                elif k == 'wrtemplate':
                    layerItem = self.find_layer(lindex, wrtemplate=v)
                if layerItem:
                    layerItems = layerItems + layerItem

        if layerItems:
            for layerItem in layerItems:
                for lb in lindex['layerBranches']:
                    if branchid == lb['branch'] and layerItem['id'] == lb['layer']:
                        result.append(lb)
            return result

        return None

    def getDependencies(self, lindex, layerBranch):
        required = []
        recommended = []
        for ld in lindex['layerDependencies']:
            if layerBranch['id'] == ld['layerbranch']:
                layers = self.find_layer(lindex, id=ld['dependency'])
                if (not layers or layers == []) and ld['required'] == True:
                    logger.warning('%s: Unable to find dependency %s -- Skipping' % (self.find_layer(lindex, layerBranch=layerBranch)[0]['name'], ld['dependency']))
                for layer in layers:
                    for lb in self.getLayerBranch(lindex, layerBranch['branch'], layerItem=layer):
                        if not lb:
                            continue
                        if not 'required' in ld or ld['required'] == True:
                            #print('li_getdep_dep: %s (%s) req %s (%s)' % (self.find_layer(lindex, layerBranch=layerBranch)['name'], layerBranch['id'], self.find_layer(lindex, layerBranch=lb)['name'], ld['dependency']) )
                            required.append(lb)
                        else:
                            #print('li_getdep_dep: %s (%s) rec %s (%s)' % (self.find_layer(lindex, layerBranch=layerBranch)['name'], layerBranch['id'], self.find_layer(lindex, layerBranch=lb)['name'], ld['dependency']) )
                            recommended.append(lb)

        return (required, recommended)

    def getLayerInfo(self, lindex, layerBranch):
        collection = None
        name = None
        vcs_url = None
        if 'collection' in layerBranch:
            collection = layerBranch['collection']
        for layer in self.find_layer(lindex, layerBranch=layerBranch):
            if layer:
                name = layer['name']
                vcs_url = layer['vcs_url']
                break

        return (collection, name, vcs_url)

    def getBranch(self, lindex, branchid):
        for branch in lindex['branches']:
            if branch['id'] == branchid:
                return branch
        return None

    def getBitbakeBranch(self, lindex, branchid):
        branch = self.getBranch(lindex, branchid)
        if branch:
            return branch['bitbake_branch'] or branch['name']
        return None

    def getIndexBranch(self, default=None, lindex=None):
        if lindex and 'CFG' in lindex and 'BRANCH' in lindex['CFG']:
            return lindex['CFG']['BRANCH']
        return default


================================================
FILE: bin/logger_setup.py
================================================
# Copyright (C) 2016 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
# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
"""
logger_setup is the infrastructure for setup.py to log both to the screen and
to a file.  Up on initialisation, the logger will only log to the screen and
have two new log levels:
        plain = 15
        to_file = 1

plain logs will not be prefixed with the logging type when outputting to the
output passed to the setup_logging function (which defaults to sys.stdout).
"""
import logging
import sys
import time

FILE_LOG_FORMAT = '%(asctime)s %(levelname)8s [%(filename)s:%(lineno)s' \
                + ' - %(funcName)20s(): %(message)s'

# INFO = 20
PLAIN_LOG_LEVEL = 15
# DEBUG = 10
TO_FILE_LOG_LEVEL = 1
# NOTSET = 0

logger = None

def plain(self, message, *args, **kws):
    """Function to be added to the logger for plain log level support"""

    if self.isEnabledFor(PLAIN_LOG_LEVEL):
        self._log(PLAIN_LOG_LEVEL, message, args, **kws)

def to_file(self, message, *args, **kws):
    """Function to be added to the logger for to_file log level support"""
    if self.isEnabledFor(TO_FILE_LOG_LEVEL):
        self._log(TO_FILE_LOG_LEVEL, message, args, **kws)


def setup_logging(level=PLAIN_LOG_LEVEL, output=sys.stdout):
    """create the setup.py singleton logger."""
    global logger
    if logger:
        return logger

    logger = logging.getLogger('setup.py')

    formatter = ScreenFormatter("%(levelname)s: %(message)s")
    stream_h = logging.StreamHandler(output)
    stream_h.setFormatter(formatter)

    # Logging timezone is UTC
    stream_h.converter = time.gmtime

    logger.setLevel(level)
    logger.addHandler(stream_h)

    logging.addLevelName(PLAIN_LOG_LEVEL, "PLAIN")
    logging.Logger.plain = plain

    return logger

class FileFormatter(logging.Formatter):
    def format(self, record):
        # FileHandler doesn't need color
        record.levelname = record.levelname_orig
        return logging.Formatter.format(self, record)

def setup_logging_file(log_file):
    """Add a logging.FileHandler to the logger"""
    global logger
    logger.debug("Logging to %s" % log_file)
    formatter = FileFormatter(FILE_LOG_FORMAT)
    file_h = logging.FileHandler(log_file)
    # Logging timezone is UTC
    file_h.converter = time.gmtime
    file_h.setFormatter(formatter)
    file_h.setLevel(TO_FILE_LOG_LEVEL)
    logger.addHandler(file_h)
    logging.addLevelName(TO_FILE_LOG_LEVEL, 'TO_FILE')
    logging.Logger.to_file = to_file



class ScreenFormatter(logging.Formatter):
    """ScreenFormatter exists to allow printing plain messages with a different
    format than other log levels.
    """

    RED, GREEN, YELLOW, BLUE = [1, 2, 3, 4]

    RESET_SEQ = "\033[0m"
    COLOR_SEQ = "\033[1;%dm"

    COLORS = {
        'INFO': GREEN,
        'DEBUG': BLUE,
        'WARNING': YELLOW,
        'ERROR': RED,
        'CRITICAL': RED
    }

    def format(self, record):
        levelname = record.levelname
        # Save it for FileHandler
        record.levelname_orig = levelname
        if levelname == "PLAIN":
            msg = record.getMessage()
        else:
            if sys.stdout.isatty():
                fore_color = 30 + self.COLORS[levelname]
                levelname_color = self.COLOR_SEQ % fore_color + levelname + self.RESET_SEQ
                record.levelname = levelname_color
                msg = logging.Formatter.format(self, record)
            msg = logging.Formatter.format(self, record)
        return msg

# Add a class to emulate stdout/stderr
class LoggerOut:
    def __init__(self, logger, isatty):
        self.logger = logger
        self.tty = isatty

    def write(self, message):
        # We skip any lines that are simply a '\n'.
        # The logger always ends in the equivalent of a \n, and many programs
        # seem to like to insert blank lines using '\n' which makes the
        # logging confusing.
        if message != '\n':
            self.logger(message)

    def flush(self):
        # We print all messages immediately, so flush is a no-op.
        pass

    def isatty(self):
        return self.tty


================================================
FILE: bin/sanity.py
================================================
#!/usr/bin/env python3

# Copyright (C) 2019 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
# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

# Please keep these sorted.
"""
sanity.py module to help setup program to do sanity checks.
"""

import os
import sys
import logger_setup
logger = logger_setup.setup_logging()

# Fixed list of tools needed.
fixed_hosttools = """
 [ ar as awk basename bash bzip2 cat chgrp chmod chown chrpath
 cmp comm cp cpio cpp cut date dd diff diffstat dirname du echo
 egrep env expand expr false fgrep file find flock g++ gawk gcc
 getconf getopt git grep gunzip gzip head hostname iconv id install
 ld ldd ln ls make makeinfo md5sum mkdir mknod mktemp mv nm objcopy
 objdump od patch perl pod2man pr printf pwd python2 python2.7
 python3 ranlib readelf readlink realpath rm rmdir rpcgen sed
 seq sh sha256sum sleep sort split stat strings strip tail tar tee
 test touch tr true uname uniq wc wget which xargs
"""

def which(path, item, direction = 0, executable=False):
    """
    Locate `item` in the list of paths `path` (colon separated string like $PATH).
    If `direction` is non-zero then the list is reversed.
    If `executable` is True then the candidate has to be an executable file,
    otherwise the candidate simply has to exist.
    """

    if executable:
        is_candidate = lambda p: os.path.isfile(p) and os.access(p, os.X_OK)
    else:
        is_candidate = lambda p: os.path.exists(p)

    paths = (path or "").split(':')
    if direction != 0:
        paths.reverse()

    for p in paths:
        next = os.path.join(p, item)
        if is_candidate(next):
            if not os.path.isabs(next):
                next = os.path.abspath(next)
            return next

    return ""

def check_hosttools(additions = None):
    """
    Check tools on host. Error out if some tool is missing. 
    """
    host_tools = []
    notfound = []

    try:
        import settings
        host_tools = settings.REQUIRED_HOSTTOOLS.split()
        if additions:
            for tool in additions:
                if tool not in host_tools:
                    host_tools.append(tool)
    except Exception as e:
        logger.warn("Failed to get host tools from setting.py: %s" % e)
        logger.warn("Use a fixed list of host tools for checking.")
        host_tools = []
    
    if not host_tools:
        # Fall back to a fixed list of host tools
        host_tools = fixed_hosttools.split()

    path = os.environ['PATH']
    for tool in host_tools:
        srctool = which(path, tool, executable=True)
        # gcc/g++ may link to ccache on some hosts, e.g.,
        # /usr/local/bin/ccache/gcc -> /usr/bin/ccache, then which(gcc)
        # would return /usr/local/bin/ccache/gcc, but what we need is
        # /usr/bin/gcc, this code can check and fix that.
        if "ccache" in srctool:
            srctool = which(path, tool, executable=True, direction=1)
        if not srctool:
            notfound.append(tool)
    if notfound:
        logger.error("Required host tools not available: %s" % notfound)
        sys.exit(1)
    else:
        logger.info("All required host tools are available.")

# allow running sanity checks individually
if __name__ == '__main__':
    sys.exit(check_hosttools(sys.argv[1:]))


================================================
FILE: bin/settings.py
================================================
# Settings for the installer

# type:  restapi-web   - REST API from a LayerIndex-web
#        restapi-files - REST API, but only from files
#        export        - Exported DB from a LayerIndex-web -- reads file(s)

# url/path may contain:
#  #INSTALL_DIR# which is replaced by the setup directory
#  #BASE_URL# which is replaced by the base url for setup directory
#  #BASE_BRANCH# which is replaced by the base branch for the setup directory

# Since we know the url below will be mirrored to our
# internal git mirrors, change format so it can be replaced
# with the proper value(s)
REPLACE = [
    ( 'git://lxgit.wrs.com', '#BASE_URL#' )
]

INDEXES = [
    {
        'DESCRIPTION' : 'Wind River Developer Layer Index',
        'TYPE' : 'restapi-web',
        'URL' : 'http://layers.wrs.com/layerindex/api/',
        'CACHE' : 'config/index-cache/layers_wrs_com',
    },
#    {
#        'DESCRIPTION' : 'OpenEmbedded Layer Index',
#        'TYPE' : 'restapi-web',
#        'URL' : 'http://layers.openembedded.org/layerindex/api/',
#        'CACHE' : 'config/index-cache/layers_openembedded_org',
#        'BRANCH' : 'morty'
#    },
]

# Bitbake URL on the same server at openembedded-core
# bitbake is assumed to be at the same basepath as OpenEmbedded-Core
BITBAKE = "bitbake"

# Base Layers (these layers and their dependencies are -always- included)
BASE_LAYERS = "wrlinux"

DEFAULT_DISTRO = "wrlinux"
DEFAULT_MACHINE = "qemux86-64"

# Default number of repo jobs
REPO_JOBS = 4

# Repo remote name list
REMOTES = [
    ( 'git://git.openembedded.org', 'openembedded' ),
    ( 'git://git.yoctoproject.org', 'yoctoproject' ),
    ( 'http://git.yoctoproject.org', 'http_yoctoproject' ),
    ( 'git://github.com', 'github' ),
    ( 'https://github.com', 'https_github' ),
]

# The default tag used to filter the output of --list actions. 'all' means no
# filter
DEFAULT_LAYER_COMPAT_TAG = "wrl"

# required host tools to build out project
# Do not edit this manually, it is updated automatically.
REQUIRED_HOSTTOOLS = """
    [ ar as awk basename bash bzip2 cat chgrp chmod chown chrpath
    cmp comm cp cpio cpp cut date dd diff diffstat dirname du echo
    egrep env expand expr false fgrep file find flock g++ gawk gcc
    getconf getopt git grep gunzip gzip head hostname iconv id install
    ld ldd ln ls make md5sum mkdir mkfifo mknod mktemp mv nm objcopy
    objdump od patch perl pr printf pwd python3 ranlib readelf readlink
    realpath rm rmdir rpcgen sed seq sh sha1sum sha224sum sha256sum
    sha384sum sha512sum sleep sort split stat strings strip tail tar
    tee test touch tr true uname uniq wc wget which xargs
"""


================================================
FILE: bin/setup.py
================================================
#!/usr/bin/env python3

# Copyright (C) 2016 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
# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

# Please keep these sorted.
import logging
import os
import shutil
import subprocess
import sys
import time
import re

from urllib.parse import urlparse

import utils_setup

# Setup-specific modules
import logger_setup
from argparse_wrl import Argparse_Wrl

from layer_index import Layer_Index

import settings
import sanity

import xml.etree.ElementTree as ET

logger = logger_setup.setup_logging()

# Redirect stdout and stderr to the custom logger.  This allows us to use
# python modules that may output only via stdout/stderr.
isatty = sys.stdout.isatty()
sys.stdout = logger_setup.LoggerOut(logger.info, isatty)
sys.stderr = logger_setup.LoggerOut(logger.error, isatty)

class Setup():

    tool_list = ['repo', 'git']

    default_xml = 'default.xml'
    default_repo_quiet = '--quiet'

    class_config_dir = 'config'
    class_log_dir = 'log'

    check_repo_install_dir = '.repo/repo/.git'
    check_repo_sync_file = '.repo/projects/'

    replacement = {}

    BINTOOLS_SSL_DIR="/bin/buildtools/sysroots/x86_64-wrlinuxsdk-linux/usr/share/ca-certificates/mozilla"
    BINTOOLS_SSL_CERT= "/bin/buildtools/sysroots/x86_64-wrlinuxsdk-linux/etc/ssl/certs/ca-certificates.crt"

    def __init__(self):
        # Set various default values
        # Default -j for repo init
        self.jobs = str(settings.REPO_JOBS)

        # Pull in the defaults from the environment (set by setup.sh)
        self.base_url = os.getenv('OE_BASEURL')
        self.base_branch = os.getenv('OE_BASEBRANCH')
        self.buildtools_branch = os.getenv('OE_BUILDTOOLS_BRANCH')
        self.buildtools_remote = os.getenv('OE_BUILDTOOLS_REMOTE')
        self.another_buildtools_remote = os.getenv('OE_ANOTHER_BUILDTOOLS_REMOTE')

        # Real project or a mirror?
        self.mirror = False

        self.mirror_index_path = None

        # Make/Use the project mirror as PREMIRRORS for do_fetch
        self.mirror_as_premirrors = False

        # Default configuration
        self.distros = [ settings.DEFAULT_DISTRO ]
        self.machines = [ settings.DEFAULT_MACHINE ]
        self.layers = []
        self.recipes = []
        self.wrtemplates = []

        self.all_layers = False
        self.dl_layers = False
        self.local_layers = []
        self.remote_layers = []

        # The extra layer groups enabled by user
        self.use_layer_groups = []

        self.no_recommend = False

        self.no_network = False
        self.allowed_network = None

        self.remotes = {}
        self.requiredlayers = []
        self.recommendedlayers = []

        # Default quiet:
        self.quiet = self.default_repo_quiet
        self.repo_verbose = False

        # Default depth
        self.depth = None

        # Default to NOT force-sync
        self.force_sync = None

        self.repo_url = None
        if 'REPO_URL' in os.environ:
            self.repo_url = os.environ['REPO_URL']

        self.repo_rev = None
        if 'REPO_REV' in os.environ:
            self.repo_rev = os.environ['REPO_REV']

        self.debug_lvl = 0

        self.repo_no_fetch = False

        # Set the install_dir
        # Use the path from this file.  Note bin has to be dropped.
        self.install_dir = os.path.abspath(os.path.dirname(os.path.abspath(__file__)) + '/../')

        # Default location for the related XML files
        self.xml_dir = os.path.join(self.install_dir, 'data/xml')

        # Set the directory where we're running.
        self.project_dir = os.getcwd()

        self.conf_dir = os.path.join(self.project_dir, self.class_config_dir)

        # Save current base_branch to compare with next one
        self.saved_base_branch = os.path.join(self.conf_dir, 'saved_base_branch')

        # Environment setup
        self.env = os.environ.copy()

        # We do NOT want to inherit python home from the environment
        # See Issue: LIN1018-2934
        #   python3 wrapper from the buildtools sets this, which causes host
        #   python tools to fail
        if 'PYTHONHOME' in self.env:
            del self.env['PYTHONHOME']

        self.setup_env()

        # Config flags
        self.list_distros = False
        self.list_machines = None
        self.list_layers = False
        self.list_recipes = False
        self.list_wrtemplates = False

        self.premirrors_dl = os.path.join(self.project_dir, 'premirrors-dl')
        self.premirrors_dl_downloads = os.path.join(self.premirrors_dl, 'downloads')

    def exit(self, ret=0):
        logger.debug("setup.py finished (ret=%s)" % (ret))
        sys.exit(ret)

    def start_file_logging(self):
        log_dir = os.path.join(self.conf_dir, self.class_log_dir)
        if not os.path.exists(log_dir):
            os.makedirs(log_dir)

        log_file = '%s/%s.log' % (log_dir, time.strftime('%Y-%m-%d-%H:%M:%S+0000', time.gmtime()))
        logger_setup.setup_logging_file(log_file)

    def main(self, orig_args):
        parser = Argparse_Wrl(self)
        # We want to default to help mode lacking any args.
        if not orig_args or not orig_args[1:]:
            orig_args.append('--help')
        parser.evaluate_args(orig_args[1:])
        self.setup_args = " ".join(orig_args[1:])
        self.extra_group_keys = parser.extra_group_keys

        self.start_file_logging()

        logger.debug('REPO_URL = %s' % self.repo_url)
        logger.debug('REPO_BRANCH = %s' % self.repo_rev)

        if not self.base_url:
            logger.error('Unable to determine base url, you may need to specify --base-url=')

        if not self.base_branch:
            logger.error('Unable to determine base branch, you may need to specify --base-branch=')

        # Check for require host tools for real project
        if not self.mirror:
            sanity.check_hosttools(self.tool_list)

        if not self.base_url or not self.base_branch:
            self.exit(1)

        # Check for all the tools and create a dictionary of the path
        # This shouldn't fail, because sanity.check_hosttools already checked for these...
        self.tools = {i : self.get_path(i) for i in self.tool_list}
        if None in self.tools.values():
            sys.exit(1)

        self.load_layer_index()

        if len(self.index.index) == 0:
            logger.critical('No indexes could be loaded.  This could be due to an invalid branch or tag.  Exiting...')
            sys.exit(1)

        if self.list_distros:
            compat = self.list_distros
            if compat == 'default':
                compat = settings.DEFAULT_LAYER_COMPAT_TAG
            self.index.list_distros(self.base_branch, compat)

        if self.list_machines:
            compat = self.list_machines
            if compat == 'default':
                compat = settings.DEFAULT_LAYER_COMPAT_TAG
            self.index.list_machines(self.base_branch, compat)

        if self.list_layers:
            self.index.list_layers(self.base_branch)

        if self.list_recipes:
            self.index.list_recipes(self.base_branch)

        if self.list_wrtemplates:
            compat = self.list_wrtemplates
            if compat == 'default':
                compat = settings.DEFAULT_LAYER_COMPAT_TAG
            self.index.list_wrtemplates(self.base_branch, compat)

        if self.list_distros or self.list_machines or self.list_layers or self.list_recipes or self.list_wrtemplates:
            sys.exit(0)

        logger.debug('setup.py started')
        logger.debug('Calling setup main with arguments %s' % str(orig_args))

        # Log debug which may have been missed due to log level.
        logger.debug("PATH=%s" % self.env["PATH"])

        # Check saved_base_branch vs current base_branch
        self.check_base_branch()

        logger.debug("Tools are:")
        for key in self.tools:
            logger.debug("%s -> %s" % (key, self.tools[key]))

        logger.plain('Setting distro to "%s"' % (",".join(self.distros)))
        logger.plain('Setting machine to "%s"' % (",".join(self.machines)))
        if self.layers != []:
            logger.plain('Setting layers to "%s"' % (",".join(self.layers)))
        if self.recipes != []:
            logger.plain('Setting recipes to "%s"' % (",".join(self.recipes)))
        if self.wrtemplates != []:
            logger.plain('Setting templates to "%s"' % (",".join(self.wrtemplates)))

        self.process_layers()

        self.project_setup()

        self.__prep_replacements()
        if self.mirror != True:
            # We only want to do this if we're not mirroring...
            self.update_project()
        else:
            # Setup an index for others to use if we're mirroring...
            self.update_mirror()
            self.update_mirror_index()

        self.update_manifest()

        self.check_default_xml()

        self.update_gitignore()

        self.commit_files()

        self.check_project_path()

        self.repo_sync()

        if self.mirror_as_premirrors:
            if self.mirror:
                self.make_mirror_as_premirrors()
            else:
                self.use_mirror_as_premirrors()

        self.exit(0)

    def check_project_path(self):
        self.manifest_dir = os.path.join(self.project_dir, '.repo/manifests.git')
        project_dir_last = ""
        if os.path.exists(self.manifest_dir):
            cmd = [self.tools['git'], 'config', '--get', 'remote.origin.url']
            try:
                p = subprocess.run(cmd, check=True, cwd=self.manifest_dir, stdout=subprocess.PIPE)
                project_dir_last = p.stdout.decode('utf-8').strip()
            except Exception as e:
                logger.warning('Failed to run "%s": %s' % (' '.join(cmd), e))

        logger.debug('last project dir: %s' % project_dir_last)
        if project_dir_last and project_dir_last != self.project_dir:
            logger.info('project dir has been changed from %s to %s' % (project_dir_last, self.project_dir))
            logger.info('Updating config files for new project dir...')
            cmd = [self.tools['git'], 'config', 'remote.origin.url', self.project_dir]
            subprocess.run(cmd, cwd=self.manifest_dir)

    def load_mirror_index(self, remote_mirror, folder=""):
        # See if there is a mirror index available from the BASE_URL
        mirror_index = os.path.join(self.conf_dir, 'mirror-index')
        try:
            cmd = [self.tools['git'], 'ls-remote', remote_mirror, self.base_branch]
            utils_setup.run_cmd(cmd, log=2, environment=self.env, cwd=self.project_dir, stderr=subprocess.DEVNULL, stdout=subprocess.DEVNULL)
        except:
            try:
                remote_mirror += "/.git"
                cmd = [self.tools['git'], 'ls-remote', remote_mirror, self.base_branch]
                utils_setup.run_cmd(cmd, log=2, environment=self.env, cwd=self.project_dir, stderr=subprocess.DEVNULL, stdout=subprocess.DEVNULL)
            except:
                # No mirror, return
                return None

        logger.plain('Loading the mirror index from %s (%s)...' % (remote_mirror, self.base_branch))
        # This MIGHT be a valid mirror..
        if not os.path.exists(mirror_index):
            os.makedirs(mirror_index)
            cmd = [self.tools['git'], 'init' ]
            utils_setup.run_cmd(cmd, log=2, environment=self.env, cwd=mirror_index)

        try:
            # We don't know if we're fetching a branch or tag, if it's a tag we have to do this
            # in two steps anyway, so always go to 'FETCH_HEAD' and then branch it.
            cmd = [self.tools['git'], 'fetch', '-n', '-u', remote_mirror, self.base_branch]
            utils_setup.run_cmd(cmd, log=2, environment=self.env, cwd=mirror_index)
            cmd = [self.tools['git'], 'checkout', '-B', folder + self.base_branch, 'FETCH_HEAD']
            utils_setup.run_cmd(cmd, log=2, environment=self.env, cwd=mirror_index)
        except:
            # Could not fetch, return
            return None

        logger.debug('Found mirrored index.')
        cmd = [self.tools['git'], 'checkout', folder + self.base_branch ]
        utils_setup.run_cmd(cmd, log=2, environment=self.env, cwd=mirror_index)
        cmd = [self.tools['git'], 'reset', '--hard' ]
        utils_setup.run_cmd(cmd, log=2, environment=self.env, cwd=mirror_index)

        return mirror_index

    def check_base_branch(self):
        logger.debug('Checking saved_base_branch vs current base_branch')

        sync_file = os.path.join(self.project_dir, self.check_repo_sync_file)
        if not os.path.exists(sync_file):
            logger.debug("Skip the check since %s doesn't exist" % sync_file)
            return

        if not os.path.exists(self.saved_base_branch):
            logger.debug("Skip the check since %s doesn't exist" % self.saved_base_branch)
            return

        with open(self.saved_base_branch, 'r') as f:
            saved_base_branch = f.read().rstrip('\n')
        if saved_base_branch == self.base_branch:
            logger.debug('saved_base_branch and current base_branch are the same')
            return

        repo = self.tools['repo']
        cmd = [repo, 'status']
        with subprocess.Popen(cmd, stdout=subprocess.PIPE, env=self.env, cwd=self.project_dir) as proc:
            output = proc.stdout.read().decode('utf-8')
            if re.search('^project\s+layers/.*\s+branch', output, flags=re.M):
                logger.error("Found checked out branches, here is the output from 'repo status':\n%s" % output)
                logger.error('Switching base branch with checked out projects is not allowed,')
                logger.error('but you are switching from "%s" to "%s".'% (saved_base_branch, self.base_branch))
                logger.error('Consider using either of the following ways to fix the problem:')
                logger.error('- Run "git checkout m/master" in the projects')
                logger.error('- Use "repo abandon [--all | <branchname>] [<project>...]" to abandon the branch\n')
                self.exit(1)

    def load_layer_index(self):
        # Load Layer_Index

        if not (self.base_branch == "master" or self.base_branch == "master-wr"):
            from windshare import Windshare
            ws = Windshare(debug=self.debug_lvl)

            # Determine if this is a windshare install
            (ws_base_url, ws_base_folder, ws_entitlement_url) = ws.get_windshare_urls(self.base_url)
            if ws_base_url and ws_base_url != "" and ws.load_folders(ws_entitlement_url):
                logger.plain('Detected Windshare configuration.  Processing entitlements and indexes.')

                for folder in ws.folders:
                    self.mirror_index_path = ws.load_mirror_index(self, ws_base_url, folder)

                ws.write_local_mirror_index(self, self.mirror_index_path)

                # We need to adjust the base_url so everything works properly...
                self.base_url = ws_base_url

                # Adjust the location of the buildtools (was based on the original base_url)
                if self.buildtools_remote:
                    self.buildtools_remote = ws_base_folder + '/' + self.buildtools_remote
                if self.another_buildtools_remote:
                    self.another_buildtools_remote = ws_base_folder + '/' + self.another_buildtools_remote
            else:
                logger.debug('No Windshare configuration detected.')
        else:
            logger.debug('Windshare configuration disabled, building %s.' % self.base_branch)

        # Check if we have a mirror-index, and load it if we do...
        if not self.mirror_index_path:
            self.mirror_index_path = self.load_mirror_index(self.base_url + '/mirror-index')

            # Is this a tag? if so... we only pull from mirror-indexes
            if not self.mirror_index_path and self.base_branch.startswith('refs/tags/'):
                logger.error("An install from a repository tag (%s) can only be installed with a corresponding layerindex snapshot." % self.base_branch)
                logger.error("Unable to find %s" % self.base_url + '/mirror-index')
            
Download .txt
gitextract_d8ghdmvu/

├── .gitignore
├── EULA
├── LICENSE
├── README.md
├── bin/
│   ├── .pylintrc
│   ├── LICENSE.texttable
│   ├── Makefile
│   ├── argparse_setup.py
│   ├── argparse_wrl.py
│   ├── branch_mirror.py
│   ├── dump_layer_dependencies.py
│   ├── dump_layer_rev.py
│   ├── flatten_mirror.py
│   ├── layer_index.py
│   ├── logger_setup.py
│   ├── sanity.py
│   ├── settings.py
│   ├── setup.py
│   ├── test-network.py
│   ├── texttable.py
│   ├── toaster_fixture.py
│   ├── transform_index.py
│   ├── utils_setup.py
│   └── windshare.py
├── data/
│   ├── environment.d/
│   │   ├── 00_check_repo.sh
│   │   ├── 00_wrl_eula.sh
│   │   ├── 01_wrl_buildtools.sh
│   │   ├── 02_wrl_anspass.sh
│   │   ├── 03_wrl_askpass.sh
│   │   ├── 04_wrl_buildtools.sh
│   │   ├── 05_wrl_anspass.sh
│   │   ├── 06_wrl_repo.sh
│   │   ├── 07_toaster_update.sh
│   │   ├── check_update.sh
│   │   ├── kernel_type.sh
│   │   ├── setup_anspass
│   │   ├── setup_askpass
│   │   ├── setup_ssh
│   │   └── setup_utils
│   ├── local_layer/
│   │   ├── README
│   │   ├── classes/
│   │   │   └── .keepme
│   │   ├── conf/
│   │   │   └── layer.conf
│   │   ├── downloads/
│   │   │   └── .keepme
│   │   ├── git/
│   │   │   └── .keepme
│   │   ├── recipes-sample/
│   │   │   └── hello/
│   │   │       ├── hello/
│   │   │       │   └── hello.c
│   │   │       └── hello_1.0.bb
│   │   └── scripts/
│   │       └── .keepme
│   ├── samples/
│   │   ├── README-MIRROR.sample
│   │   ├── README.sample
│   │   ├── bblayers.conf.sample
│   │   ├── conf-notes.sample
│   │   ├── local.conf.sample
│   │   └── site.conf.sample
│   └── xml/
│       ├── axxiaarm-dl.xml
│       ├── bitbake.inc
│       ├── intel-socfpga-dl.xml
│       ├── meta-anaconda-dl.xml
│       ├── meta-cgl-common-dl.xml
│       ├── meta-clang-dl.xml
│       ├── meta-cloud-services-dl-3-3.xml
│       ├── meta-dpdk-dl.xml
│       ├── meta-efi-secure-boot-dl.xml
│       ├── meta-encrypted-storage-dl.xml
│       ├── meta-freescale-dl.xml
│       ├── meta-ids-dl.xml
│       ├── meta-integrity-dl.xml
│       ├── meta-intel-dl.xml
│       ├── meta-iot-cloud-dl.xml
│       ├── meta-openembedded-dl-3-3.xml
│       ├── meta-qt5-dl.xml
│       ├── meta-raspberrypi-dl.xml
│       ├── meta-realtime-dl-3-3.xml
│       ├── meta-security-compliance-dl.xml
│       ├── meta-selinux-dl.xml
│       ├── meta-signing-key-dl.xml
│       ├── meta-tensorflow-dl-3-3.xml
│       ├── meta-tpm-dl.xml
│       ├── meta-tpm2-dl.xml
│       ├── meta-virtualization-dl-3-3.xml
│       ├── nxp-imx7.xml
│       ├── nxp-s32g2xx-dl.xml
│       ├── oe-core-dl-3-3.xml
│       ├── openembedded-core.inc
│       ├── ti-j72xx-dl.xml
│       ├── wr-ostree-dl.xml
│       ├── wrlinux-dl.xml
│       ├── wrlinux.xml
│       └── xilinx-zynqmp-dl.xml
└── setup.sh
Download .txt
SYMBOL INDEX (197 symbols across 14 files)

FILE: bin/argparse_setup.py
  class Argparse_Setup (line 27) | class Argparse_Setup:
    method __init__ (line 28) | def __init__(self, setup, parser=None):
    method evaluate_args (line 46) | def evaluate_args(self, args):
    method handle_setup_args (line 51) | def handle_setup_args(self, parsed_args, args):
    method add_setup_options (line 207) | def add_setup_options(self):
    method add_repo_options (line 224) | def add_repo_options(self):
    method add_list_options (line 248) | def add_list_options(self):
    method add_layer_options (line 256) | def add_layer_options(self):
    method add_other_options (line 280) | def add_other_options(self):
    method add_options (line 283) | def add_options(self):

FILE: bin/argparse_wrl.py
  class Argparse_Wrl (line 25) | class Argparse_Wrl(Argparse_Setup):
    method __init__ (line 26) | def __init__(self, setup, parser=None):
    method handle_setup_args (line 30) | def handle_setup_args(self, parsed_args, args):
    method add_setup_options (line 77) | def add_setup_options(self):
    method add_list_options (line 90) | def add_list_options(self):
    method add_layer_options (line 94) | def add_layer_options(self):

FILE: bin/branch_mirror.py
  function usage (line 44) | def usage():
  function git_branch (line 84) | def git_branch(_dst, _orig_branch, _branch):

FILE: bin/dump_layer_dependencies.py
  function usage (line 46) | def usage():

FILE: bin/flatten_mirror.py
  function config_args (line 55) | def config_args(args):
  function push_or_copy (line 68) | def push_or_copy(_layer, _src, _dst, _branch=None):
  function get_mirror_dir (line 117) | def get_mirror_dir(_layer, _dst):
  function get_xml_dir (line 154) | def get_xml_dir(_layer, _mirror):
  function transform_xml (line 166) | def transform_xml(_src, _dest):
  function transform_xml_inside (line 180) | def transform_xml_inside(_fin, _fout):
  function update_mirror (line 229) | def update_mirror(_dst_mirror):
  function copy_premirrors_dl (line 241) | def copy_premirrors_dl(dest):
  function main (line 256) | def main():

FILE: bin/layer_index.py
  class Layer_Index (line 37) | class Layer_Index():
    method __init__ (line 41) | def __init__(self, indexcfg=[], base_branch=None, replace=[], mirror=N...
    method load_API_Index (line 168) | def load_API_Index(self, url, name=None, branches=None):
    method __add_cmp_lists (line 300) | def __add_cmp_lists(self, listone, listtwo):
    method load_serialized_index (line 333) | def load_serialized_index(self, path, name=None, branches=None):
    method load_django_export (line 386) | def load_django_export(self, path, name=None, branches=None):
    method sortEntry (line 474) | def sortEntry(self, item):
    method sortRestApi (line 489) | def sortRestApi(self, index):
    method serialize_index (line 497) | def serialize_index(self, lindex, path, split=False, layerBranches=Non...
    method serialize_django_export (line 604) | def serialize_django_export(self, lindex, path, split=False, layerBran...
    method print_close_matches (line 709) | def print_close_matches(self, key, value, full_list):
    method find_layer (line 716) | def find_layer(self, lindex, id=None, name=None, layerBranch=None, lay...
    method get_index_layers (line 794) | def get_index_layers(self, base_branch):
    method list_layers (line 807) | def list_layers(self, base_branch):
    method getYPCompatibleVersion (line 826) | def getYPCompatibleVersion(self, lindex, id):
    method list_obj (line 834) | def list_obj(self, base_branch, object, display, compat='all'):
    method get_machines (line 863) | def get_machines(self, base_branch, compat='all'):
    method list_distros (line 879) | def list_distros(self, base_branch, compat):
    method list_machines (line 882) | def list_machines(self, base_branch, compat):
    method list_wrtemplates (line 885) | def list_wrtemplates(self, base_branch, compat):
    method list_recipes (line 888) | def list_recipes(self, base_branch):
    method getBranchId (line 907) | def getBranchId(self, lindex, name):
    method getLayerBranch (line 913) | def getLayerBranch(self, lindex, branchid, layerBranchId=None, collect...
    method getDependencies (line 964) | def getDependencies(self, lindex, layerBranch):
    method getLayerInfo (line 985) | def getLayerInfo(self, lindex, layerBranch):
    method getBranch (line 999) | def getBranch(self, lindex, branchid):
    method getBitbakeBranch (line 1005) | def getBitbakeBranch(self, lindex, branchid):
    method getIndexBranch (line 1011) | def getIndexBranch(self, default=None, lindex=None):

FILE: bin/logger_setup.py
  function plain (line 41) | def plain(self, message, *args, **kws):
  function to_file (line 47) | def to_file(self, message, *args, **kws):
  function setup_logging (line 53) | def setup_logging(level=PLAIN_LOG_LEVEL, output=sys.stdout):
  class FileFormatter (line 76) | class FileFormatter(logging.Formatter):
    method format (line 77) | def format(self, record):
  function setup_logging_file (line 82) | def setup_logging_file(log_file):
  class ScreenFormatter (line 98) | class ScreenFormatter(logging.Formatter):
    method format (line 116) | def format(self, record):
  class LoggerOut (line 132) | class LoggerOut:
    method __init__ (line 133) | def __init__(self, logger, isatty):
    method write (line 137) | def write(self, message):
    method flush (line 145) | def flush(self):
    method isatty (line 149) | def isatty(self):

FILE: bin/sanity.py
  function which (line 41) | def which(path, item, direction = 0, executable=False):
  function check_hosttools (line 67) | def check_hosttools(additions = None):

FILE: bin/setup.py
  class Setup (line 50) | class Setup():
    method __init__ (line 68) | def __init__(self):
    method exit (line 171) | def exit(self, ret=0):
    method start_file_logging (line 175) | def start_file_logging(self):
    method main (line 183) | def main(self, orig_args):
    method check_project_path (line 304) | def check_project_path(self):
    method load_mirror_index (line 322) | def load_mirror_index(self, remote_mirror, folder=""):
    method check_base_branch (line 363) | def check_base_branch(self):
    method load_layer_index (line 394) | def load_layer_index(self):
    method is_group_layer (line 469) | def is_group_layer(self, layer_name):
    method is_enabled_group (line 479) | def is_enabled_group(self, layer_name):
    method process_layers (line 492) | def process_layers(self):
    method project_setup (line 812) | def project_setup(self):
    method update_project (line 829) | def update_project(self):
    method update_mirror (line 852) | def update_mirror(self):
    method __prep_replacements (line 855) | def __prep_replacements(self):
    method copySample (line 895) | def copySample(self, src, dst):
    method update_mirror_index (line 941) | def update_mirror_index(self):
    method update_manifest (line 1017) | def update_manifest(self):
    method check_default_xml (line 1160) | def check_default_xml(self):
    method get_git_premirrors_from_mirror_index (line 1197) | def get_git_premirrors_from_mirror_index(self, url, protocol):
    method make_mirror_as_premirrors (line 1240) | def make_mirror_as_premirrors(self):
    method use_mirror_as_premirrors (line 1307) | def use_mirror_as_premirrors(self):
    method update_gitignore (line 1361) | def update_gitignore(self):
    method commit_files (line 1396) | def commit_files(self):
    method repo_sync (line 1446) | def repo_sync(self):
    method __check_and_update_layerseries_compat (line 1481) | def __check_and_update_layerseries_compat(self, project_local_layer_pa...
    method __set_pnwhitelist_layers (line 1513) | def __set_pnwhitelist_layers(self):
    method __setup_local_layer (line 1549) | def __setup_local_layer(self):
    method setup_env (line 1582) | def setup_env(self):
    method add_bin_path (line 1587) | def add_bin_path(self):
    method set_repo_git_env (line 1590) | def set_repo_git_env(self):
    method set_ssl_cert (line 1595) | def set_ssl_cert(self):
    method call_repo_init (line 1606) | def call_repo_init(self, args):
    method call_initial_repo_sync (line 1634) | def call_initial_repo_sync(self, args):
    method call_repo_sync (line 1658) | def call_repo_sync(self, args):
    method get_branch (line 1674) | def get_branch(self, lindex=None):
    method get_path (line 1679) | def get_path(self, tool):
    method set_repo_verbose (line 1687) | def set_repo_verbose(self, verbose):
    method set_jobs (line 1690) | def set_jobs(self, jobs):
    method set_depth (line 1694) | def set_depth(self, depth):
    method set_force_sync (line 1701) | def set_force_sync(self, sync):
    method set_repo_url (line 1706) | def set_repo_url(self, url):
    method set_repo_rev (line 1710) | def set_repo_rev(self, rev):
    method set_debug (line 1714) | def set_debug(self):
    method set_base_url (line 1721) | def set_base_url(self, url):
    method set_base_branch (line 1725) | def set_base_branch(self, branch):
    method set_debug_env (line 1729) | def set_debug_env(self):
    method touch (line 1733) | def touch(self, fn):
    method which (line 1738) | def which(self, program):

FILE: bin/test-network.py
  function parse_args (line 34) | def parse_args():
  function dump_proxies (line 43) | def dump_proxies():
  function test_windshare (line 56) | def test_windshare(repoUrl):

FILE: bin/texttable.py
  function textwrapper (line 102) | def textwrapper(txt, width):
  function textwrapper (line 107) | def textwrapper(txt, width):
  function uchar_width (line 118) | def uchar_width(c):
  function uchar_width (line 123) | def uchar_width(c):
  function obj2unicode (line 143) | def obj2unicode(obj):
  function len (line 158) | def len(iterable):
  class ArraySizeError (line 167) | class ArraySizeError(Exception):
    method __init__ (line 171) | def __init__(self, msg):
    method __str__ (line 175) | def __str__(self):
  class FallbackToText (line 179) | class FallbackToText(Exception):
  class Texttable (line 184) | class Texttable:
    method __init__ (line 191) | def __init__(self, max_width=80):
    method reset (line 206) | def reset(self):
    method set_max_width (line 218) | def set_max_width(self, max_width):
    method set_chars (line 227) | def set_chars(self, array):
    method set_deco (line 246) | def set_deco(self, deco):
    method set_header_align (line 266) | def set_header_align(self, array):
    method set_cols_align (line 280) | def set_cols_align(self, array):
    method set_cols_valign (line 294) | def set_cols_valign(self, array):
    method set_cols_dtype (line 308) | def set_cols_dtype(self, array):
    method set_cols_width (line 328) | def set_cols_width(self, array):
    method set_precision (line 348) | def set_precision(self, width):
    method header (line 361) | def header(self, array):
    method add_row (line 369) | def add_row(self, array):
    method add_rows (line 386) | def add_rows(self, rows, header=True):
    method draw (line 407) | def draw(self):
    method _to_float (line 435) | def _to_float(cls, x):
    method _fmt_int (line 444) | def _fmt_int(cls, x, **kw):
    method _fmt_float (line 452) | def _fmt_float(cls, x, **kw):
    method _fmt_exp (line 464) | def _fmt_exp(cls, x, **kw):
    method _fmt_text (line 476) | def _fmt_text(cls, x, **kw):
    method _fmt_auto (line 481) | def _fmt_auto(cls, x, **kw):
    method _str (line 493) | def _str(self, i, x):
    method _check_row_size (line 517) | def _check_row_size(self, array):
    method _has_vlines (line 527) | def _has_vlines(self):
    method _has_hlines (line 533) | def _has_hlines(self):
    method _has_border (line 539) | def _has_border(self):
    method _has_header (line 545) | def _has_header(self):
    method _hline_header (line 551) | def _hline_header(self):
    method _hline (line 557) | def _hline(self):
    method _build_hline (line 565) | def _build_hline(self, is_header=False):
    method _len_cell (line 585) | def _len_cell(self, cell):
    method _compute_cols_width (line 604) | def _compute_cols_width(self):
    method _check_align (line 644) | def _check_align(self):
    method _draw_line (line 655) | def _draw_line(self, line, isheader=False):
    method _splitit (line 686) | def _splitit(self, line, isheader):

FILE: bin/toaster_fixture.py
  function add_field (line 57) | def add_field(obj,attr_list,value):
  function write_prolog (line 63) | def write_prolog():
  function append_setting (line 68) | def append_setting(name,value,pk):
  function append_bitbake (line 77) | def append_bitbake(name,giturl,branch,pk):
  function append_releases (line 88) | def append_releases(name,desc,bitbake_version,branch,help):
  function write_default_layer_release (line 99) | def write_default_layer_release(release,pk):
  function write_layer_release (line 110) | def write_layer_release(layer_pk,layer_version_pk,layer_source):
  function write_epilog (line 149) | def write_epilog():
  function read_default_xml (line 156) | def read_default_xml(xml_file):
  function read_layer_index_cache (line 175) | def read_layer_index_cache(json_cache):
  function find_layer2id (line 180) | def find_layer2id(layer_name):
  function find_id2layer (line 187) | def find_id2layer(layer_id):
  function find_layerBranch2layer (line 194) | def find_layerBranch2layer(layerBranch_id):
  function find_layer2layerBranch (line 205) | def find_layer2layerBranch(layer):
  function add_machine_layers (line 220) | def add_machine_layers(add_machine):
  function add_distro_layers (line 232) | def add_distro_layers(add_distro):
  function add_dependent_layers (line 244) | def add_dependent_layers(add_layer,include_optional):
  function main (line 273) | def main(argv):

FILE: bin/utils_setup.py
  function run_cmd (line 27) | def run_cmd(cmd, environment=None, cwd=None, log=1, expected_ret=0, err=...
  function query_input (line 79) | def query_input(question, interactive):
  function fetch_url (line 120) | def fetch_url(url=None, auth=False, debuglevel=0, interactive=0):

FILE: bin/windshare.py
  class Windshare (line 32) | class Windshare():
    method __init__ (line 33) | def __init__(self, debug=0):
    method get_windshare_urls (line 43) | def get_windshare_urls(self, base_url):
    method load_folders (line 79) | def load_folders(self, url=None):
    method load_mirror_index (line 142) | def load_mirror_index(self, setup, base_url, folder):
    method write_local_mirror_index (line 212) | def write_local_mirror_index(self, setup, mirror_index_path):
Condensed preview — 89 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (496K chars).
[
  {
    "path": ".gitignore",
    "chars": 68,
    "preview": "buildtools.git\n*.pyc\nbin/.venv\n*.pyo\n/*.patch\n*.swp\n*.orig\n*.rej\n*~\n"
  },
  {
    "path": "EULA",
    "chars": 40842,
    "preview": "                         WIND RIVER LINUX PLATFORM\n                         SOFTWARE LICENSE AGREEMENT\n\nThis Wind River "
  },
  {
    "path": "LICENSE",
    "chars": 17987,
    "preview": "\t\t    GNU GENERAL PUBLIC LICENSE\n\t\t       Version 2, June 1991\n\n Copyright (C) 1989, 1991 Free Software Foundation, Inc."
  },
  {
    "path": "README.md",
    "chars": 3506,
    "preview": "wrlinux setup\n=============\n\nWith this tool you can either create a new distribution builder platform\nproject, or create"
  },
  {
    "path": "bin/.pylintrc",
    "chars": 13878,
    "preview": "[MASTER]\n\n# Specify a configuration file.\n#rcfile=\n\n# Python code to execute, usually for sys.path manipulation such as\n"
  },
  {
    "path": "bin/LICENSE.texttable",
    "chars": 1083,
    "preview": "The MIT License (MIT)\n\nCopyright (c) 2018 Gerome Fournier\n\nPermission is hereby granted, free of charge, to any person o"
  },
  {
    "path": "bin/Makefile",
    "chars": 1098,
    "preview": "SHELL = /bin/bash #requires bash\nVENV = $(PWD)/.venv/\nDEPS = $(wildcard *.py)\nTMP_PIP = $(VENV)/get-pip.py\nPYTHON3 := $("
  },
  {
    "path": "bin/argparse_setup.py",
    "chars": 13154,
    "preview": "# Copyright (C) 2016 Wind River Systems, Inc.\n#\n# This program is free software; you can redistribute it and/or modify\n#"
  },
  {
    "path": "bin/argparse_wrl.py",
    "chars": 4233,
    "preview": "# Copyright (C) 2016 Wind River Systems, Inc.\n#\n# This program is free software; you can redistribute it and/or modify\n#"
  },
  {
    "path": "bin/branch_mirror.py",
    "chars": 6253,
    "preview": "#!/usr/bin/env python3\n\n# Copyright (C) 2016 Wind River Systems, Inc.\n#\n# This program is free software; you can redistr"
  },
  {
    "path": "bin/dump_layer_dependencies.py",
    "chars": 2880,
    "preview": "#!/usr/bin/env python3\n\n# Copyright (C) 2016-2017 Wind River Systems, Inc.\n#\n# This program is free software; you can re"
  },
  {
    "path": "bin/dump_layer_rev.py",
    "chars": 1851,
    "preview": "#!/usr/bin/env python3\n\n# Copyright (C) 2016 Wind River Systems, Inc.\n#\n# This program is free software; you can redistr"
  },
  {
    "path": "bin/flatten_mirror.py",
    "chars": 19839,
    "preview": "#!/usr/bin/env python3\n\n# Copyright (C) 2016 Wind River Systems, Inc.\n#\n# This program is free software; you can redistr"
  },
  {
    "path": "bin/layer_index.py",
    "chars": 43128,
    "preview": "# Copyright (C) 2016 Wind River Systems, Inc.\n#\n# This program is free software; you can redistribute it and/or modify\n#"
  },
  {
    "path": "bin/logger_setup.py",
    "chars": 4698,
    "preview": "# Copyright (C) 2016 Wind River Systems, Inc.\n#\n# This program is free software; you can redistribute it and/or modify\n#"
  },
  {
    "path": "bin/sanity.py",
    "chars": 3835,
    "preview": "#!/usr/bin/env python3\n\n# Copyright (C) 2019 Wind River Systems, Inc.\n#\n# This program is free software; you can redistr"
  },
  {
    "path": "bin/settings.py",
    "chars": 2636,
    "preview": "# Settings for the installer\n\n# type:  restapi-web   - REST API from a LayerIndex-web\n#        restapi-files - REST API,"
  },
  {
    "path": "bin/setup.py",
    "chars": 73548,
    "preview": "#!/usr/bin/env python3\n\n# Copyright (C) 2016 Wind River Systems, Inc.\n#\n# This program is free software; you can redistr"
  },
  {
    "path": "bin/test-network.py",
    "chars": 3612,
    "preview": "#!/usr/bin/env python3\n\n# Copyright (C) 2016-2017 Wind River Systems, Inc.\n#\n# This program is free software; you can re"
  },
  {
    "path": "bin/texttable.py",
    "chars": 22522,
    "preview": "# texttable - module for creating simple ASCII tables\n# Copyright (C) 2003-2018 Gerome Fournier <jef(at)foutaise.org>\n\n\""
  },
  {
    "path": "bin/toaster_fixture.py",
    "chars": 14095,
    "preview": "#!/usr/bin/env python3\n\n# Copyright (C) 2017 Wind River Systems, Inc.\n#\n# This program is free software; you can redistr"
  },
  {
    "path": "bin/transform_index.py",
    "chars": 4688,
    "preview": "#!/usr/bin/env python3\n\n# Copyright (C) 2016 Wind River Systems, Inc.\n#\n# This program is free software; you can redistr"
  },
  {
    "path": "bin/utils_setup.py",
    "chars": 7425,
    "preview": "#!/usr/bin/env python3\n\n# Copyright (C) 2016 Wind River Systems, Inc.\n#\n# This program is free software; you can redistr"
  },
  {
    "path": "bin/windshare.py",
    "chars": 11662,
    "preview": "# Copyright (C) 2016 Wind River Systems, Inc.\n#\n# This program is free software; you can redistribute it and/or modify\n#"
  },
  {
    "path": "data/environment.d/00_check_repo.sh",
    "chars": 1290,
    "preview": "# Copyright (C) 2017 Wind River Systems, Inc.\n#\n# This program is free software; you can redistribute it and/or modify\n#"
  },
  {
    "path": "data/environment.d/00_wrl_eula.sh",
    "chars": 2809,
    "preview": "# Copyright (C) 2016 - 2020 Wind River Systems, Inc.\n#\n# This program is free software; you can redistribute it and/or m"
  },
  {
    "path": "data/environment.d/01_wrl_buildtools.sh",
    "chars": 1183,
    "preview": "# Copyright (C) 2016, 2020 Wind River Systems, Inc.\n#\n# This program is free software; you can redistribute it and/or mo"
  },
  {
    "path": "data/environment.d/02_wrl_anspass.sh",
    "chars": 2312,
    "preview": "# Copyright (C) 2016 Wind River Systems, Inc.\n#\n# This program is free software; you can redistribute it and/or modify\n#"
  },
  {
    "path": "data/environment.d/03_wrl_askpass.sh",
    "chars": 3196,
    "preview": "# Copyright (C) 2016 Wind River Systems, Inc.\n#\n# This program is free software; you can redistribute it and/or modify\n#"
  },
  {
    "path": "data/environment.d/04_wrl_buildtools.sh",
    "chars": 9038,
    "preview": "# Copyright (C) 2016-2021 Wind River Systems, Inc.\n#\n# This program is free software; you can redistribute it and/or mod"
  },
  {
    "path": "data/environment.d/05_wrl_anspass.sh",
    "chars": 1425,
    "preview": "# Copyright (C) 2016 Wind River Systems, Inc.\n#\n# This program is free software; you can redistribute it and/or modify\n#"
  },
  {
    "path": "data/environment.d/06_wrl_repo.sh",
    "chars": 7449,
    "preview": "# Copyright (C) 2016 - 2021 Wind River Systems, Inc.\n#\n# This program is free software; you can redistribute it and/or m"
  },
  {
    "path": "data/environment.d/07_toaster_update.sh",
    "chars": 1064,
    "preview": "# Copyright (C) 2017 Wind River Systems, Inc.\n#\n# This program is free software; you can redistribute it and/or modify\n#"
  },
  {
    "path": "data/environment.d/check_update.sh",
    "chars": 2008,
    "preview": "# Copyright (C) 2016 Wind River Systems, Inc.\n#\n# This program is free software; you can redistribute it and/or modify\n#"
  },
  {
    "path": "data/environment.d/kernel_type.sh",
    "chars": 1182,
    "preview": "# Copyright (C) 2017 Wind River Systems, Inc.\n#\n# This program is free software; you can redistribute it and/or modify\n#"
  },
  {
    "path": "data/environment.d/setup_anspass",
    "chars": 4498,
    "preview": "# Copyright (C) 2016 Wind River Systems, Inc.\n#\n# This program is free software; you can redistribute it and/or modify\n#"
  },
  {
    "path": "data/environment.d/setup_askpass",
    "chars": 4972,
    "preview": "#! /usr/bin/env python3\n\n# Copyright (C) 2016 Wind River Systems, Inc.\n#\n# This program is free software; you can redist"
  },
  {
    "path": "data/environment.d/setup_ssh",
    "chars": 685,
    "preview": "#! /bin/sh\n#\n# Intercept the SSH calls during the installer to ensure that we have control\n# over the display and termin"
  },
  {
    "path": "data/environment.d/setup_utils",
    "chars": 2697,
    "preview": "# Copyright (C) 2016 Wind River Systems, Inc.\n#\n# This program is free software; you can redistribute it and/or modify\n#"
  },
  {
    "path": "data/local_layer/README",
    "chars": 1515,
    "preview": "local layer\n===========\n\nThis layer is intended to work as a scratch space in the default projects.\n\n\nDependencies\n-----"
  },
  {
    "path": "data/local_layer/classes/.keepme",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "data/local_layer/conf/layer.conf",
    "chars": 885,
    "preview": "# We have a conf and classes directory, add to BBPATH\nBBPATH =. \"${LAYERDIR}:\"\n\n# We have a recipe-* directory, add to B"
  },
  {
    "path": "data/local_layer/downloads/.keepme",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "data/local_layer/git/.keepme",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "data/local_layer/recipes-sample/hello/hello/hello.c",
    "chars": 108,
    "preview": "/*\n * Copyright 2012 Wind River Systems, Inc.\n */\n\n#include <stdio.h>\n\nmain() {\n\tprintf(\"Hello World\\n\");\n}\n"
  },
  {
    "path": "data/local_layer/recipes-sample/hello/hello_1.0.bb",
    "chars": 450,
    "preview": "DESCRIPTION = \"This package contains the simple Hello World program.\"\nLICENSE = \"windriver\"\nLICENSE_FLAGS = \"commercial_"
  },
  {
    "path": "data/local_layer/scripts/.keepme",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "data/samples/README-MIRROR.sample",
    "chars": 658,
    "preview": "This is a Wind River Linux Repository Mirror.  It was constructed by the setup\nprogram using the following arguments:\n\n#"
  },
  {
    "path": "data/samples/README.sample",
    "chars": 2629,
    "preview": "This is a Wind River Linux build project.  It was constructed by the\nsetup.sh tool using the following arguments:\n\n####S"
  },
  {
    "path": "data/samples/bblayers.conf.sample",
    "chars": 216,
    "preview": "# LAYER_CONF_VERSION is increased each time build/conf/bblayers.conf\n# changes incompatibly\nLCONF_VERSION = \"7\"\n\nBBPATH "
  },
  {
    "path": "data/samples/conf-notes.sample",
    "chars": 770,
    "preview": "This project was configured with the following options:\n    ####SETUP_ARGS####\n\nCommon Wind River images are:\n    wrlinu"
  },
  {
    "path": "data/samples/local.conf.sample",
    "chars": 13977,
    "preview": "#\n# This file is your local configuration file and is where all local user settings\n# are placed. The comments in this f"
  },
  {
    "path": "data/samples/site.conf.sample",
    "chars": 1208,
    "preview": "#\n# local.conf covers user settings, site.conf covers site specific information\n# such as proxy server addresses and opt"
  },
  {
    "path": "data/xml/axxiaarm-dl.xml",
    "chars": 493,
    "preview": "    <project name=\"external/yocto/github.com.lsigithub.lsi_axxia_uboot_public\" remote=\"base\" path=\"layers/axxiaarm-dl/gi"
  },
  {
    "path": "data/xml/bitbake.inc",
    "chars": 43,
    "preview": "        <linkfile src=\".\" dest=\"bitbake\"/>\n"
  },
  {
    "path": "data/xml/intel-socfpga-dl.xml",
    "chars": 572,
    "preview": "    <project name=\"external/yocto/github.com.altera-opensource.intel-rsu\" remote=\"base\" path=\"layers/intel-socfpga-dl/gi"
  },
  {
    "path": "data/xml/meta-anaconda-dl.xml",
    "chars": 684,
    "preview": "    <project name=\"external/yocto/github.com.rhinstaller.python-simpleline\" remote=\"base\" path=\"layers/meta-anaconda-dl/"
  },
  {
    "path": "data/xml/meta-cgl-common-dl.xml",
    "chars": 854,
    "preview": "    <project name=\"external/yocto/github.com.ClusterLabs.cluster-glue\" remote=\"base\" path=\"layers/meta-cgl-common-dl/git"
  },
  {
    "path": "data/xml/meta-clang-dl.xml",
    "chars": 141,
    "preview": "    <project name=\"external/yocto/github.com.iovisor.bcc\" remote=\"base\" path=\"layers/meta-clang-dl/git/github.com.ioviso"
  },
  {
    "path": "data/xml/meta-cloud-services-dl-3-3.xml",
    "chars": 318,
    "preview": "    <project name=\"external/ovp/gitlab.xiph.org.xiph.celt\" remote=\"base\" path=\"layers/meta-cloud-services-dl-3.3/git/git"
  },
  {
    "path": "data/xml/meta-dpdk-dl.xml",
    "chars": 136,
    "preview": "    <project name=\"external/yocto/dpdk.org.dpdk-stable\" remote=\"base\" path=\"layers/meta-dpdk-dl/git/dpdk.org.dpdk-stable"
  },
  {
    "path": "data/xml/meta-efi-secure-boot-dl.xml",
    "chars": 696,
    "preview": "    <project name=\"external/yocto/github.com.jiazhang0.SELoader\" remote=\"base\" path=\"layers/meta-efi-secure-boot-dl/git/"
  },
  {
    "path": "data/xml/meta-encrypted-storage-dl.xml",
    "chars": 179,
    "preview": "    <project name=\"external/yocto/github.com.jiazhang0.cryptfs-tpm2\" remote=\"base\" path=\"layers/meta-encrypted-storage-d"
  },
  {
    "path": "data/xml/meta-freescale-dl.xml",
    "chars": 2857,
    "preview": "    <project name=\"external/yocto/source.codeaurora.org.external.qoriq.qoriq-components.dpdk\" remote=\"base\" path=\"layers"
  },
  {
    "path": "data/xml/meta-ids-dl.xml",
    "chars": 165,
    "preview": "    <project name=\"external/yocto/github.com.archiecobbs.mtree-port\" remote=\"base\" path=\"layers/meta-ids-dl/git/github.c"
  },
  {
    "path": "data/xml/meta-integrity-dl.xml",
    "chars": 356,
    "preview": "    <project name=\"external/yocto/git.code.sf.net.p.linux-ima.ima-evm-utils\" remote=\"base\" path=\"layers/meta-integrity-d"
  },
  {
    "path": "data/xml/meta-intel-dl.xml",
    "chars": 366,
    "preview": "    <project name=\"external/yocto/github.com.intel.Intel-Linux-Processor-Microcode-Data-Files\" remote=\"base\" path=\"layer"
  },
  {
    "path": "data/xml/meta-iot-cloud-dl.xml",
    "chars": 3330,
    "preview": "    <project name=\"external/yocto/github.com.awslabs.aws-c-auth\" remote=\"base\" path=\"layers/meta-iot-cloud-dl/git/github"
  },
  {
    "path": "data/xml/meta-openembedded-dl-3-3.xml",
    "chars": 20853,
    "preview": "    <project name=\"external/yocto/git.code.sf.net.p.aufs.aufs-util\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/"
  },
  {
    "path": "data/xml/meta-qt5-dl.xml",
    "chars": 4158,
    "preview": "    <project name=\"external/qt5/code.qt.io.qt-labs.qt5-everywhere-demo\" remote=\"base\" path=\"layers/meta-qt5-dl/git/code."
  },
  {
    "path": "data/xml/meta-raspberrypi-dl.xml",
    "chars": 338,
    "preview": "    <project name=\"external/yocto/github.com.RPi-Distro.pi-bluetooth\" remote=\"base\" path=\"layers/meta-raspberrypi-dl/git"
  },
  {
    "path": "data/xml/meta-realtime-dl-3-3.xml",
    "chars": 168,
    "preview": "    <project name=\"external/yocto/github.com.jlelli.schedtool-dl\" remote=\"base\" path=\"layers/meta-realtime-dl-3.3/git/gi"
  },
  {
    "path": "data/xml/meta-security-compliance-dl.xml",
    "chars": 549,
    "preview": "    <project name=\"external/yocto/github.com.OpenSCAP.openscap\" remote=\"base\" path=\"layers/meta-security-compliance-dl/g"
  },
  {
    "path": "data/xml/meta-selinux-dl.xml",
    "chars": 690,
    "preview": "    <project name=\"external/yocto/github.com.SELinuxProject.refpolicy\" remote=\"base\" path=\"layers/meta-selinux-dl/git/gi"
  },
  {
    "path": "data/xml/meta-signing-key-dl.xml",
    "chars": 545,
    "preview": "    <project name=\"external/yocto/github.com.jiazhang0.libsign\" remote=\"base\" path=\"layers/meta-signing-key-dl/git/githu"
  },
  {
    "path": "data/xml/meta-tensorflow-dl-3-3.xml",
    "chars": 346,
    "preview": "    <project name=\"external/yocto/github.com.tensorflow.tensorflow\" remote=\"base\" path=\"layers/meta-tensorflow-dl-3.3/gi"
  },
  {
    "path": "data/xml/meta-tpm-dl.xml",
    "chars": 698,
    "preview": "    <project name=\"external/yocto/git.code.sf.net.p.trousers.tpm-tools\" remote=\"base\" path=\"layers/meta-tpm-dl/git/git.c"
  },
  {
    "path": "data/xml/meta-tpm2-dl.xml",
    "chars": 170,
    "preview": "    <project name=\"external/yocto/github.com.tpm2-software.tpm2-abrmd\" remote=\"base\" path=\"layers/meta-tpm2-dl/git/githu"
  },
  {
    "path": "data/xml/meta-virtualization-dl-3-3.xml",
    "chars": 5076,
    "preview": "    <project name=\"external/yocto/github.com.coreos.go-systemd\" remote=\"base\" path=\"layers/meta-virtualization-dl-3.3/gi"
  },
  {
    "path": "data/xml/nxp-imx7.xml",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "data/xml/nxp-s32g2xx-dl.xml",
    "chars": 1022,
    "preview": "    <project name=\"external/yocto/source.codeaurora.org.external.autobsps32.u-boot\" remote=\"base\" path=\"layers/nxp-s32g2"
  },
  {
    "path": "data/xml/oe-core-dl-3-3.xml",
    "chars": 25549,
    "preview": "    <project name=\"external/yocto/git.denx.de.u-boot\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/git.denx.de.u-boot.g"
  },
  {
    "path": "data/xml/openembedded-core.inc",
    "chars": 161,
    "preview": "        <linkfile src=\"oe-init-build-env\" dest=\"oe-init-build-env\"/>\n        <linkfile src=\"meta\" dest=\"meta\"/>\n        "
  },
  {
    "path": "data/xml/ti-j72xx-dl.xml",
    "chars": 1692,
    "preview": "    <project name=\"external/yocto/git.ti.com.rpmsg.ti-rpmsg-char\" remote=\"base\" path=\"layers/ti-j72xx-dl/git/git.ti.com."
  },
  {
    "path": "data/xml/wr-ostree-dl.xml",
    "chars": 628,
    "preview": "<project name=\"external/overc/github.com.ostreedev.ostree\" remote=\"base\" path=\"layers/wr-ostree-dl/git/github.com.ostree"
  },
  {
    "path": "data/xml/wrlinux-dl.xml",
    "chars": 947,
    "preview": "    <project name=\"external/yocto/github.com.WindRiver-OpenSourceLabs.anspass\" remote=\"base\" path=\"layers/wrlinux-dl/git"
  },
  {
    "path": "data/xml/wrlinux.xml",
    "chars": 228,
    "preview": "    <project name=\"yocto-kernel-cache-5.10\" remote=\"base\" path=\"layers/wrlinux/git/yocto-kernel-cache.git\" bare=\"True\"/>"
  },
  {
    "path": "data/xml/xilinx-zynqmp-dl.xml",
    "chars": 162,
    "preview": "    <project name=\"external/yocto/github.com.Xilinx.u-boot-xlnx\" remote=\"base\" path=\"layers/xilinx-zynqmp-dl/git/github."
  },
  {
    "path": "setup.sh",
    "chars": 9572,
    "preview": "#!/bin/bash\n#\n# Copyright (C) 2016 Wind River Systems, Inc.\n#\n# This program is free software; you can redistribute it a"
  }
]

About this extraction

This page contains the full source code of the WindRiver-Labs/wrlinux-x GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 89 files (460.4 KB), approximately 118.1k tokens, and a symbol index with 197 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!