[
  {
    "path": ".gitignore",
    "content": "buildtools.git\n*.pyc\nbin/.venv\n*.pyo\n/*.patch\n*.swp\n*.orig\n*.rej\n*~\n"
  },
  {
    "path": "EULA",
    "content": "                         WIND RIVER LINUX PLATFORM\n                         SOFTWARE LICENSE AGREEMENT\n\nThis Wind River Linux Platform Software License Agreement (the \n\"Agreement\"), is made between Wind River Systems, Inc. (\"Wind River\"), \non the one hand, and the individual accessing or using the Software or \nany single legal entity on behalf of which such individual is acting \n(\"Customer\"), on the other hand.  The effective date of this Agreement \nis the earlier of the date that you accept this Agreement or the date \nthat Wind River makes the Products available to you (\"Effective Date\").\n\nPLEASE READ THIS AGREEMENT CAREFULLY BEFORE DOWNLOADING, ACCESSING, \nINSTALLING OR USING THE PRODUCTS.  BY CLICKING ON THE \"I ACCEPT\" BUTTON \nYOU: ACKNOWLEDGE THAT YOU HAVE READ AND UNDERSTAND THIS AGREEMENT, \nAGREE TO BE BOUND BY ITS TERMS AND CONDITIONS, AND WARRANT YOU HAVE \nAUTHORITY TO ENTER INTO THIS AGREEMENT.  IF YOU ARE ACTING ON BEHALF OF \nAN ENTITY, YOU REPRESENT THAT YOU HAVE THE AUTHORITY TO ENTER INTO THIS \nAGREEMENT ON BEHALF OF THAT ENTITY.  IF YOU DO NOT ACCEPT THE TERMS OF \nTHIS AGREEMENT, THEN YOU MUST NOT USE THE PRODUCTS AND SERVICES AND YOU \nMUST UNINSTALL AND RETURN THE PRODUCT TO WIND RIVER WITHIN TEN (10) \nDAYS.\n\nIF YOU ARE EVALUATING THE PRODUCT, THE TERMS SPECIFIED IN APPENDIX B \nSHALL APPLY IN ADDITION OF THE TERMS OF THE AGREEMENT AND APPENDIX A.\n  \n________________________________________________________________________\n\nThe parties agree as follows:\n\n1. SCOPE. This framework Agreement governs Wind River's provision to \nCustomer of the Products and Services as detailed in the Quote or \nExhibit. Terms in initial capitalized letters, not defined elsewhere in \nthis Agreement, have the meanings set forth in Section 12 (Definitions).\n\n2. LICENSE. Each program, component or application included in the \nSoftware may be governed by one or more Open Source License(s), as \nspecified or referenced in the respective Source Code files.  Without \nlimiting the foregoing, for the convenience of Customer, Wind River will \nmake available, upon request, applicable licensing information in the \nLinux Foundation's SPDX(R) format. Tools provided to Customer shall be \nlicensed under the terms of the attached Appendix A, which is hereby \nincorporated by reference into this Agreement.  \n\n3. SERVICES.\n3.1. Support. Customer's payment of the applicable fees entitles \nCustomer to Support during the License Term. Support is provided in \naccordance with the terms of Wind River's then current Software Support \nand Maintenance Agreement, which terms are hereby incorporated by \nreference into this Agreement. A copy of the curr ent Software Support \nand Maintenance Agreement can be accessed through Wind River's website: \nhttp://www.windriver.com/support/SupportTerms.pdf\n\n\n3.2. Professional Services. Professional services, if included in a \nsigned statement of work, will be provided at additional cost and \nsubject to Wind River's then current Professional Services Terms and \nConditions, which terms are hereby incorporated by reference into this \nAgreement. A copy of the current Professional Services Terms and \nConditions can be accessed through Wind River's website: \nhttp://windriver.com/services/ProductAgreementServicesAttachment.pdf\n \n3.3. Education and Training. Education and training services (e.g., \nmentoring, live or remote classes, etc.), if included in the Quote or \nExhibit will be provided pursuant to Wind River's then current Education \nServices terms and conditions, which terms are hereby incorporated by \nreference into this Agreement. A copy of the current Education Services \nterms and conditions can be accessed through Wind River's website: \nhttp://education.windriver.com/content/public/resources/Supplemental_Education_Services_Terms_and_Conditions.pdf\n\n4. CONFIDENTIAL INFORMATION. Customer will not use or disclose any \nConfidential Information, except as expressly authorized by this \nAgreement, and will protect all such Confidential Information using the \nsame degree of care that Customer uses with respect to its own \nproprietary information, but in no event less than reasonable care. If \nConfidential Information must be disclosed to a third party by reason of \nlegal, accounting or regulatory requirements beyond the reasonable \ncontrol of Customer, Customer will: (i) assert the confidential nature \nof the information in the action or proceeding; (ii) promptly notify \nWind River of the order or request; and (iii) permit Wind River (at its \nown expense) to seek an appropriate protective order.\n\n5. TERM AND TERMINATION.  \n5.1. Term.  The term of this Agreement will commence upon the Effective \nDate and continue until expiration of the License Term unless earlier \nterminated as set forth herein. The renewal date for all Products and \nServices hereunder will be the last day of the applicable License Term, \nregardless of whether Customer chooses to license additional Products \nduring such License Term. Customer must notify Wind River at least \nthirty (30) days prior to the end of the License Term of its request to \nrenew its subscription. Unless the parties mutually agree to renew the \nsubscription, and Customer pays the then-applicable fees, Customer's \nlicense to the Tools and entitlement to Support will terminate on the \nlast day of the then-current License Term.\n\n5.2. Termination. Either party may terminate this Agreement immediately \nupon notice for the material breach of the other party, which breach is \ncurable and has remained uncured for a period of thirty (30) days from \nthe date of notice. In addition, Wind River may immediately terminate \nthis Agreement if Customer is delinquent on its payment obligations for \nthirty (30) days or more.\n\n5.3. Consequences of Expiration or Termination. Upon expiration of the \nLicense Term or termination of this Agreement, Customer will: (a) not \nuse the Tools for any purpose whatsoever; (b) no longer be entitled to \nreceive or have access to Support or other Services; (c) immediately \ndestroy or return to Wind River all material belonging to Wind River or \nits licensors, including, without limitation, all Confidential \nInformation of Wind River then in Customer's possession; and (d) \npromptly certify to Wind River in writing that Customer has completed \nthe actions described in the foregoing subsections. These remedies will \nbe cumulative and in addition to any other remedies available to Wind \nRiver. Sections 4, 5, 6, 7, 8, 9, 10, 11 and 12 will survive expiration \nor termination of this Agreement.\n\n6. DELIVERY, PAYMENT AND TAXES.\n6.1. Delivery and Payment Terms.\n6.1.1. The Product will be deemed irrevocably accepted upon shipment. \nWhen Product is made available to Customer for electronic download \nthrough access to a website and/or server, shipment will be deemed to \nhave occurred at the time of such availability.\n6.1.2. Customer will pay Wind River the fees set forth in the applicable \nExhibit or Quote.  Wind River will invoice Customer the applicable fees \nupon receipt of a correctly issued purchase order from Customer, which \nmay coincide with shipment of the Software or Tools. Payment terms \nherein are subject to prior credit approval by Wind River. Customer will \npay all invoices within thirty (30) days of the date of such invoice in \nU.S. dollars unless otherwise set forth in the applicable Exhibit or \nQuote. Interest on late payments will accrue at the rate of one and \none-half percent (1.5%) per month or partial month, or, if lower, the \nhighest rate permitted by law.  Customer is responsible for reasonable \ncosts associated with collection of overdue amounts, including without \nlimitation, reasonable attorneys' fees and court costs.  Failure to pay \nany invoice in the manner described in this Section 6 may, at Wind \nRiver's discretion, be deemed a material breach of this Agreement.\n6.1.3. If Products or Services are purchased through an authorized Wind \nRiver distributor, Customer will be invoiced directly by such \ndistributor (and not Wind River), and Customer will pay the distributor \nthe applicable fees in accordance with the payment terms agreed to \nbetween Customer and the distributor.\n\n6.2. Purchase Orders. Unless Products or Services are purchased through \nan authorized Wind River distributor, Customer will submit to Wind River \na purchase order in the amount specified in the corresponding Exhibit or \nQuote. Any additional or different terms and conditions on the purchase \norder will be of no force or effect. Wind River may reject any purchase \norder that Wind River determines to be outside the scope of this \nAgreement.\n\n6.3. Taxes. All amounts due hereunder will be paid without deduction, \nset-off or counter claim, free and clear of any restrictions or \nconditions, and without deduction for any taxes, levies, imposts, \nduties, fees, deductions, withholdings or other governmental charges.  \nIf any deduction is required to be made by law, Customer will pay the \nfull amount owed to Wind River plus the amount to be deducted, so that \nWind River will receive the same amount as it would have received had \nthe deduction not been required.  If Customer is claiming sales or use \ntax exemption, a valid and fully executed Tax Exempt Certificate must be \nattached to this Agreement or the applicable Quote or Exhibit, or the \napplicable purchase order.  Customer will promptly pay or reimburse all \ntaxes (exclusive of taxes on Wind River's net income), duties and \nassessments arising from amounts payable to Wind River under this \nAgreement, or furnish Wind River with evidence acceptable to the taxing \nauthority to sustain exemption therefrom.\n\n7. CUSTOMER COMPLIANCE.  Wind River or its designated representative \nwill have the right to: (a) require that Customer send a written \ncertification of compliance with the terms of this Agreement within \nfifteen (15) days of Wind River's request; and (b) conduct an inspection \nand audit (\"Audit\") upon reasonable notice of the relevant operational, \naccounting and sales books and records of Customer and any other \ninformation within Customer's possession or control that is reasonably \nnecessary to determine whether Customer has complied with this \nAgreement, and obtain true and correct photocopies of the foregoing \nmaterials.  Such Audit will be conducted during regular business hours \nat Customer's offices and so as not to interfere unreasonably with \nCustomer's normal business activities.  Customer will permit or provide \nfor completion of any Audit within forty-five (45) days of notice.  If \nan Audit discloses any underpayment of fees, then Wind River will \ninvoice Customer for, and Customer will promptly pay Wind River, the \nunderpaid fee amount based on the higher of the price specified in this \nAgreement or Wind River's price list in effect at the time the audit is \ncompleted, together with late payment interest in accordance with \nSection 6.1 (Delivery and Payment Terms). If an Audit discloses \nunderpayment of five percent (5%) or more, then Wind River will also \ninvoice Customer for, and Customer will promptly pay, Wind River's \nreasonable costs of conducting the Audit.\n\n8. LIMITED WARRANTY.\n\n8.1. Limited Warranty. The Software is provided \"AS IS\". In no event \ndoes Wind River warrant that the Software is error free or that the \nSoftware will satisfy Customer's own specific requirements. Customer \nassumes full responsibility for: (a) the selection of the Product; (b) \nthe proper installation and use of the Products; (c) verifying the \nresults obtained from the use of the Products; and (d) taking \nappropriate measures to prevent loss of data.\n    \n8.2. Warranty Disclaimer.  EXCEPT AS EXPRESSLY SET FORTH IN SECTION 8.1 \nABOVE, WIND RIVER AND ITS LICENSORS DISCLAIM ALL WARRANTIES, EXPRESS, \nIMPLIED AND STATUTORY INCLUDING, WITHOUT LIMITATION, THE IMPLIED \nWARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE \nAND NON-INFRINGEMENT OF THIRD PARTY RIGHTS WITH RESPECT TO THE PRODUCTS \nAND SERVICES PROVIDED UNDER THIS AGREEMENT.  NO ORAL OR WRITTEN \nINFORMATION OR ADVICE GIVEN BY WIND RIVER, ITS DEALERS, DISTRIBUTORS, \nAGENTS OR EMPLOYEES WILL IN ANY WAY INCREASE THE SCOPE OF THE WARRANTIES \nPROVIDED BY WIND RIVER IN THIS AGREEMENT OR THE APPLICABLE OPEN SOURCE \nLICENSES.  WIND RIVER DOES NOT WARRANT THAT THE QUALITY OR PERFORMANCE \nOF ANY PRODUCT AND SERVICES WILL MEET CUSTOMER'S REQUIREMENTS OR THAT \nCUSTOMER WILL BE ABLE TO ACHIEVE ANY PARTICULAR RESULTS FROM USE OR \nMODIFICATION OF THE PRODUCT, OR THAT THE PRODUCT WILL OPERATE FREE FROM \nERROR.  WIND RIVER MAKES NO WARRANTY WITH RESPECT TO ANY MALFUNCTIONS OR \nOTHER ERRORS IN ITS PRODUCTS CAUSED BY VIRUS, INFECTION, WORM OR SIMILAR \nMALICIOUS CODE NOT DEVELOPED BY WIND RIVER.  WIND RIVER MAKES NO \nWARRANTY THAT ANY PRODUCTS OF WIND RIVER WILL PROTECT AGAINST ALL \nPOSSIBLE SECURITY THREATS, INCLUDING INTENTIONAL MISCONDUCT BY THIRD \nPARTIES.  WIND RIVER IS NOT LIABLE FOR ANY DOWNTIME OR SERVICE \nINTERRUPTION, FOR ANY LOST OR STOLEN DATA OR SYSTEMS, OR FOR ANY OTHER \nDAMAGES ARISING OUT OF OR RELATING TO ANY SUCH ACTIONS OR INTRUSIONS.  \nSome jurisdictions do not allow the limitation or exclusion of implied \nwarranties or how long an implied warranty may last, so the above \nlimitations may not apply to Customer.  This warranty gives Customer \nspecific legal rights and Customer may have other rights that vary from \njurisdiction to jurisdiction.\n\n9. CUSTOMER INDEMNITY. Customer will defend at its expense Wind River \nagainst any claims, suits, or proceedings brought against Wind River by \nthird parties resulting from, in connection with, attributable to any \nCustomer product or service incorporating or using the Software, or by \nCustomer's direct or indirect end users, and will indemnify Wind River \nfor any costs, losses, damages, and expenses (including reasonable legal \nfees) resulting from or in connection with such claim, suit, or \nproceeding. Customer's obligations under this Section are conditioned on \nWind River: (a) providing Customer prompt notice of such claim, suit, or \nproceeding; (b) tendering to Customer the defense or settlement of any \nsuch claim, suit, or proceeding at Customer's expense; and (c) \ncooperating with Customer, at Customer's expense, in defending or \nsettling such claim, suit, or proceeding.\n\n10. LIMITATION OF LIABILITY. WIND RIVER AND ITS LICENSORS WILL NOT BE \nLIABLE TO CUSTOMER OR ANY THIRD PARTY FOR ANY LOSS OF PROFITS, REVENUE \nOR GOODWILL, COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, LOSS \nOR INTERRUPTION OF BUSINESS, LOSS OF ANTICIPATED SAVINGS, OR LOSS OF \nDATA, OR ANY INDIRECT, EXEMPLARY, PUNITIVE, SPECIAL, INCIDENTAL OR \nCONSEQUENTIAL DAMAGES OF ANY KIND, HOWEVER CAUSED AND REGARDLESS OF THE \nFORM OF ACTION, WHETHER IN CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT \nPRODUCT LIABILITY OR ANY OTHER LEGAL OR EQUITABLE THEORY, EVEN IF WIND \nRIVER HAS BEEN ADVISED OR SHOULD HAVE KNOWN OF THE POSSIBILITY OF SUCH \nDAMAGES. IN NO EVENT WILL WIND RIVER'S AGGREGATE CUMULATIVE LIABILITY \nFOR ANY CLAIMS ARISING OUT OF OR RELATED TO THIS AGREEMENT EXCEED THE \nAMOUNTS PAID TO WIND RIVER BY CUSTOMER FOR THE AFFECTED PRODUCT OR \nSERVICES PURSUANT TO THIS AGREEMENT IN THE TWELVE (12) MONTHS PRECEDING \nTHE CLAIM.  Some jurisdictions do not allow the exclusion or limitation \nof incidental or consequential damages so this limitation and exclusion \nmay not apply to Customer.\n\nTHE LIMITED WARRANTY, LIMITED REMEDIES, WARRANTY DISCLAIMER AND LIMITED \nLIABILITY ARE FUNDAMENTAL ELEMENTS OF THE BASIS OF THE BARGAIN BETWEEN \nWIND RIVER AND CUSTOMER. WIND RIVER WOULD NOT BE ABLE TO PROVIDE THE \nPRODUCTS OR SERVICES WITHOUT SUCH LIMITATIONS.\n\n11. GENERAL.\n11.1. Governing Law and Venue. This Agreement will be governed in all \nrespects by the laws of the United States of America and the State of \nDelaware, without reference to conflict of laws principles. The United \nNations Convention on Contracts for the International Sale of Goods is \nspecifically excluded from application to to this Agreement. All \ndisputes arising under this Agreement will be brought exclusively in the \nState of Delaware or of the Federal courts sitting therein, provided, \nhowever, that the parties will be entitled to seek injunctive relief in \nthe appropriate forum. Customer consents to the personal jurisdiction of \nthe above courts.\n\t\n11.2. Export Control. All software and technical information delivered \nunder this Agreement are subject to U.S. export controls under the \nExport Administration Regulations (the \"EAR\") or the International \nTraffic in Arms Regulations (the \"ITAR\") and may be subject to export, \nre-export or import regulations in other countries.  Customer agrees to \nstrictly comply with all such laws and regulations. Customer will not \nexport or re-export the software and technical information, directly or \nindirectly, to: (a) any countries that are subject to US export \nrestrictions (currently including, but not necessarily limited to, Cuba, \nIran, North Korea, Sudan, and Syria); (b) any end user who Customer \nknows or has reason to know will utilize them in the design, development \nor production of nuclear, chemical or biological weapons, or rocket \nsystems, space launch vehicles, and sounding rockets, or unmanned air \nvehicle systems; or (c) any end user who has been prohibited from \nparticipating in US export transactions by any federal agency of the US \ngovernment. Some of Wind River's products are classified as \"restricted\" \nencryption products under Section 740.17(b)(2) of the EAR and may not be \nexported or re-exported to government end-users (as defined in Section \n772 of the EAR) outside the countries listed in Supplement No. 3 to Part \n740 of the EAR without authorization from the U.S. government.\n\n11.3. U.S. Government End-Users. All software and any data relating \nthereto or derived therefrom are \"commercial items\" as defined in 48 \nC.F.R. 2.101, consisting of \"commercial computer software\" and \n\"commercial computer software documentation\" as such terms are used in \n48 C.F.R. 12.212.  If the end User is a U.S. Government agency, \ndepartment, or instrumentality, then the use, duplication, reproduction, \nrelease, modification, disclosure or transfer of the Software and any \ndata relating thereto or derived therefrom, is restricted in accordance \nwith 48 C.F.R. 12.211, 48 C.F.R. 12.212, 48 C.F.R. 227.7102-2, and 48 \nC.F.R. 227.7202, as applicable.  Customer will provide the Software to \nthe U.S. Government or to U.S. Government end Users only pursuant to an \nend user license agreement in accordance with the terms of this \nAgreement. This U.S. Government end users clause is in lieu of, and \nsupersedes, any Federal Acquisition Regulations (\"FAR\"), the Defense FAR \nSupplement (\"DFARS\"), or other clause or provision that addresses \nGovernment rights in computer software or technical data.\n\n11.4. Notices. All notices under this Agreement will be: (a) in writing; \n(b) delivered by personal delivery or certified or registered mail, \nreturn receipt requested, and deemed given upon personal delivery or \nfive (5) days after deposit in the mail.  Notices to Wind River will be \nsent to Wind River Systems, Inc., General Counsel, Legal Affairs, 500 \nWind River Way, Alameda, CA 94501, USA (or such other address designated \nin writing by Wind River), and notices to Customer will be sent to the \naddress identified in Customer's purchase order.\n\n11.5. Force Majeure. Neither party will be liable for any failure or \ndelay (except for the payment of money) on account of strikes, \nshortages, riots, insurrection, fires, explosions, acts of God, war, \ngovernmental action, labor conditions, material shortages or any other \ncause which is beyond the reasonable control of such party.\n\n11.6. Use of Customer's Name. Subject to Customer's approval, Wind River \nmay identify Customer as a customer of Wind River products or services.\n\n11.7. Assignment. Customer will not assign, transfer or delegate any \nright, license or obligation under this Agreement to a third party, \ndirectly or indirectly, including by operation of law or through \nbankruptcy, merger, acquisition, sale or transfer of all, substantially \nall or any part of the business or assets of Customer, or undergo a \nchange of Control, without first obtaining Wind River's prior written \nconsent, which Wind River may withhold in Wind River's sole discretion.  \nAny purported assignment, transfer, delegation or change of Control in \nviolation of this Section 11.7 (Assignment) is null and void.  Wind \nRiver may assign, transfer or delegate this Agreement or any right, \nlicense or obligation hereunder in its sole discretion.\n\n11.8. Counterparts. In the event th is Agreement is executed with \nsignatures, this Agreement may be executed in one or more counterparts, \neach of which will be deemed an original, but all of which together will \nconstitute one and the same instrument. Counterparts to this Agreement \ntransmitted by facsimile transmission, by electronic mail in \"portable \ndocument format\" (\".pdf\") form, or by any other electronic means \nintended to preserve the original graphic and pictorial appearance of a \ndocument, will have the same effect as a signed original of this \nAgreement.\n\n11.9. Waiver. The failure of either party to require performance by the \nother party of any provision hereof will not affect the full right to \nrequire such performance at any time thereafter; nor will the waiver by \neither party of a breach of any provision hereof be taken or held to be \na waiver of the provision itself.\n\n11.10. Miscellaneous. This Agreement will not create any agency, \nemployment relationship, partnership or other form of joint enterprise \nbetween the parties. This Agreement and its attachments and exhibits \nconstitute the entire agreement between Customer and Wind River and \nsupersedes all prior oral or written agreements between the parties with \nrespect to the subject matter hereof.  The terms and conditions of any \npurchase order or other instrument issued by Customer in connection with \nthis Agreement will be of no force or effect.  This Agreement may only \nbe amended by a writing signed by the parties that refers explicitly to \nthis Agreement.  If a provision of this Agreement is unenforceable or \ninvalid, the provision will be revised so as to best accomplish the \nobjectives of the parties.\n\n12. DEFINITIONS. In addition to the terms in initial capitalized letters \ndefined elsewhere in this Agreement, the following terms in initial \ncapitalized letters have the respective meanings set forth below:\n\n12.1. \"Confidential Information\" means information disclosed by Wind \nRiver to Customer, including without limitation, intellectual property, \nsoftware programs, documentation, pricing, current, future, and proposed \nproducts and services, which is (a) in tangible form and bears a \n\"confidential\", \"proprietary\" or similar legend; and (b) discussions \nrelating to that information whether those discussion occur prior to, \nconcurrent with, or following disclosure of the information. Wind River \nshall make reasonable efforts to mark its confidential information in \ntangible form with any of the aforementioned legends prior to \ndisclosure. However, Wind River's information in tangible form that does \nnot bear any of these legends, and discussions relating to that \ninformation, shall nevertheless be protected hereunder as Confidential \nInformation, if Customer knew, or should have reasonably known under the \ncircumstances, that the information was confidential and had been \ncommunicated to it in confidence. Confidential Information does not \ninclude any information that Customer reasonably demonstrates is: (i) \npublished or otherwise available to the public other than by breach of \nthis Agreement by Customer; (ii) rightfully received by Customer from a \nthird party without confidentiality limitations; (iii) independently \ndeveloped by Customer as evidenced by appropriate records; (iv) known to \nCustomer prior to its first receipt from Wind River as evidenced by \nappropriate records; (v) hereinafter disclosed by Wind River to a third \nparty without restriction on disclosure; or (vi) approved for public \nrelease by written authorization of Wind River.\n\n12.2. \"Control\" means: (a) ownership of more than fifty percent (50%) of \nthe outstanding stock or securities entitled to vote for the election of \ndirectors or similar managing authority of the subject entity; (b) \nownership of more than fifty percent (50%) of the ownership interest \nthat represents the right to make decisions for the subject entity; (c) \nany other ability to elect more than half of the board of directors or \nsimilar managing authority of the subject entity, whether by contract or \notherwise; or (d) the possession, directly or indirectly, of the power \nto direct or cause the direction of the management or policies of the \nsubject entity whether through the ownership of voting securities, \nthrough other voting rights, by contract or otherwise.\n\n12.3. \"Exhibit\" means an attachment to this Agreement that the parties \nmay elect to simultaneously or separately execute from time to time, in \naddition to the Quote, detailing Products and Services to be provided to \nCustomer, as well as other business restrictions associated with such \nProducts and Services (e.g., Project and Development Locations).\n\n12.4. \"License Term\" means the term set forth in the Quote or Exhibit or \none (1) year commencing on the Effective Date if no term is specified.\n\n12.5. \"Object Code\" means computer programming code in a form not \nreadily perceivable by humans and suitable for machine execution without \nthe intervening steps of interpretation or compilation. 1 2.6. \"Open \nSource License\" means a software license under which the Soft ware \nObject Code and/or Source Code is made available under terms that allow \nany licensee to copy, create derivative works and distribute the \nsoftware without any fee or cost, including but not limited to any open \nsource license listed by the Open Source Initiative \n(http://www.opensource.org).\n\n12.7. \"Product\" means Software and Tools. \n\n12.8. \"Quote\" means the Wind River final sales quote detailing the \nProducts and Services to be provided to Customer, as well as other \nbusiness restrictions associated with such Products and Services (e.g., \nProject and Development Locations).\n\n12.9. \"Services\" means those services provided by Wind River as detailed \nin the Quote, statement of work or Exhibit, and includes, but is not \nlimited to Support, professional services and education services.\n\n12.10. \"Software\" means the Linux operating system components (such as \nthe kernel, BSPs and drivers) and any add-on profiles and other related \nsoftware components, as specified in the Quote or Exhibit and made \navailable by Wind River to Customer in Source Code or Object Code form, \nincluding any updates thereto and all accompanying documentation \ngoverned by an Open Source License. Software does not include Tools.\n\n12.11. \"Source Code\" means computer programming code in human readable \nform that is not suitable for machine execution without the intervening \nsteps of interpretation or compilation.\n\n12.12. \"SPDX\" means the Software Package Data Exchange specification for \ncommunicating the components, licenses and copyrights associated with a \nsoftware package, as developed by the Linux Foundation.\n\n12.13. \"Support\" means the annual support and maintenance services \nspecified in the Quote or Exhibit to be provided by Wind River in \naccordance with Section 3.1 (Support & Maintenance).\n\n12.14. \"Tools\" means the proprietary Source Code and Object Code and any \naccompanying documentation provided by Wind River under this Agreement \nwhich is intended for Customer's internal use in accordance with the \nterms of the Tools Agreement in Addendum 1 (e.g., Wind River Workbench). \nTools shall be deemed \"Confidential Information\".\n\n\n                   APPENDIX A - WIND RIVER LINUX PLATFORM\n                          TOOLS ADDITIONAL TERMS\n\n1. SCOPE. These terms (\"Tools Agreement\") govern Customer's rights and \nobligations with respect to the Tools, as specified in the Quote or \nExhibit. Terms in initial capitalized letters, not defined in the \nAgreement or in this Tools Agreement, have the meanings set forth in \nSection 5 (Definitions). The terms of the Agreement hereby incorporated \nby reference into this Tools Agreement. The terms of this Tools \nAgreement shall supersede any conflicting provisions of the Agreement \nfor purposes of such Tools.\n \n2. LICENSE GRANTS. Subject to Customer's compliance with the terms and \nconditions of this Tools Agreement and any Quote or Exhibit, and payment \nof the applicable fees, Wind River grants to Customer, during the \nLicense Term, a restricted, personal, non-transferable, non-exclusive, \ninternal-use license:\n\n2.1. for Floating User Development Licenses, to reproduce and use one \n(1) copy of the Tools per Development License on the Supported \nArchitecture Family, solely for the number of licensed concurrent \nFloating Users located at each Development Location and specified as \nlicensed for such Tools in such Exhibit or Quote;\n\nOR\n\n2.2. for Named User Development Licenses, to reproduce and use one (1) \ncopy of the Tools per Development License on the Supported Architecture \nFamily, solely for the licensed Named Users located at each Development \nLocation and specified as licensed for such Tools in such Exhibit or \nQuote. Customer will use license management technology in the Tools to \nassign each Development License to a Named User and no other User may \nuse the copy of the Tools designated for that Development License \nwithout the prior written consent of Wind River; except, however, that \nCustomer may (a) transfer a Named User Development License from one \nNamed User to another individual if the Named User has left Customer's \nbusiness, and is replaced by another Named User, or (b) make legal name \nchanges or network UserID changes to the Named User profile information, \nsubject to notification to Wind River submitted to Wind River's email \nalias (CustomerReports@windriver.com);\n\nOR\n\n2.3. for Node-Lock User Development Licenses, to reproduce, access and \nuse one (1) copy of the Tools per Development License, solely on the \nnumber of \"Node-locked hosts\" licensed and located at each Development \nLocation and specified as licensed for such Tools in such Exhibit A or \nQuote.  For purposes of this Agreement, the \"Node\" means the host \ncomputer where both the Tools and license management file are physically \ninstalled.\n\n3. GENERAL RESTRICTIONS. 3.1. General.  Tools are provided to Customer \nin Object Code and are intended for Customer's internal use in \ndeveloping applications in accordance with the Development License and \nnot for distribution. Except as expressly permitted by this Tools \nAgreement, Customer will not, nor permit any third party to: (a) for \nFloating User Development Licenses: (i) permit access to or use of the \nTools in excess of the quantity of concurrent Floating Users set forth \nin the applicable Exhibit or Quote; (ii) transfer any Floating User \nDevelopment License from a Development Location in one country to a \nDevelopment Location in another country; or (iii) allow one Floating \nUser in one country to access the Tools from a licensed server in \nanother country; (b) for Named User Development License, permit \nconcurrent access to or use of a single copy of the Tools for any Named \nUser Development License, or access or use by anyone other than the \nNamed User assigned to the Development License, as set forth in the \napplicable Exhibit or Quote; (c) for Node-Lock User Development \nLicenses, install the Tools on more than the quantity of licensed Nodes \nset forth in the applicable Exhibit or Quote; (d) translate, reverse \nengineer, decompile, disassemble (except to the extent applicable laws \nspecifically prohibit such restriction) or attempt to derive the Source \nCode of any Tools Object Code provided to Customer; (e) reproduce the \nTools other than as specified in the applicable license grant set forth \nin Section 2 (License Grants); (f) sublicense, rent, lease, loan, \ntimeshare, sell, distribute, disclose, publish, assign or transfer any \nrights, grant a security interest in, transfer possession of the Tools, \nor electronically transfer the Tools from one computer to another except \nover Customer's internal network pursuant to Section 3.2 (Network \nAccess); (g) modify, distribute or otherwise use the Tools in any manner \nthat causes any portion of the Tools that is not already subject to Open \nSource License to become subject to the terms of any Open Source \nLicense; or (h) alter or remove any of Wind River's or its licensors' \ncopyright or proprietary rights notices or legends appearing on or in \nthe Tools.  Customer will reproduce such notices on any copies of the \nTools Customer is permitted to make. Customer will inform all Users of \nthe restrictions set forth in this Tools Agreement with respect to use \nof the Tools.\n\n3.2. Network Access.  Floating and Named Users who have a unique network \nlog-in (e.g., NT or Unix log-in) may access the Tools from a secure \nnetwork server located at the Development Location over a secure VPN or \nequivalent secure network.  Within thirty (30) days following Wind \nRiver's written request, Customer will disclose to Wind River the \nDevelopment Location of each network from which Tools will be accessed.  \nNode-Lock Users will not remotely access the licensed node, where \n\"remote access\" means any access to the node other than being physically \npresent at the host computer.\n\n3.3. Third Party Software. The Tools licensed under this Tools Agreement \nmay contain or be derived from materials of third party licensors such \nas materials subject to an Open Source Licenses (\"Third Party \nSoftware\"). Such third party materials may be subject to restrictions in \naddition to those listed in this Section 3 (General Restrictions), which \nrestrictions, if any, are set forth in the third party notice file that \naccompanies the Tools. Customer acknowledges and agrees that its use of \nThird Party Software is subject to its compliance with any such \nadditional terms.\n\n3.4 Copies.  Customer may make a reasonable number of copies of the \nTools for archival purposes or for use as a back-up.  Customer must copy \nall copyright legends, trademarks, trade names, and other legends on any \ncopies of the Tools.\n\n4. KEYS AND ACCESS. Wind River will provide Customer those keys that are \nreasonably necessary to permit Customer to gain access to the licensed \nTools. Any technology, ideas, know how, documentation, processes, \nalgorithms, and trade secrets disclosed to Customer by Wind River in \nconnection with or as embodied in the Tools and keys shall be considered \n\"Confidential Information\" as defined in the Agreement. Customer will \ndisclose such keys solely to authorized Users of the Tools.  The Tools \nalso contains license management technology intended to cause the Tools \nto cease operating upon expiration or termination of the license.  \nCustomer will not circumvent the license management technology, or any \nother security devices, access logs, or other protective measures \nprovided with the Tools or permit or assist any User or any third party \nto do the same.  The license management technology and any other \nprotective measures in the Tools are included solely as a matter of \nadministrative convenience, and Customer has no right or license in or \nto such protective measures.  Customer will be invoiced for any \nadditional Users who access the Tools and will pay any such invoice in \naccordance with Section 6 (Delivery, Payment and Taxes) of the \nAgreement.  Customer will follow the recommended installation procedures \nfor each Tools product licensed under this Tools Agreement.\n  \n5. DEFINITIONS. In addition to the terms in initial capitalized letters \ndefined elsewhere in this Agreement, the following terms in initial \ncapitalized letters have the respective meanings set forth below:\n\n\n5.1. \"Development License\" means the right of a User to use certain \nTools pursuant to Section 2 (License Grants) of this Tools Agreement. \nThe Development License type and quantity will be specified in an \nExhibit or Quote.\n   \n5.2. \"Development Location\" means the geographic address of each \nCustomer site or facility where the Tools are authorized to be installed \nand used in accordance with the terms of this Agreement.  Customer's \nDevelopment Location(s) will be specified in an Exhibit A or Quote.\n\n5.3. \"Floating User\" means any User who may access and use the Tools \npursuant to Section 2.1 (Floating User Development License).\n\n5.4. \"Named User\" means any User who uses the Tools pursuant to Section \n2.2 (Named User Development License).\n\n5.5. \"Node-Lock User\" means any User who uses the Tools pursuant to \nSection 2.3 (Node-Lock User Development License).\n\n5.6. \"Supported Architecture Family\" means the target architecture \nfamily or families then-supported by Wind River on which Customer may \nuse the Tools pursuant to this Agreement, as specified in an Exhibit or \nQuote.\n\n5.7. \"User\" means a Customer employee or independent contractor who (a) \nis based at a Development Location, (b) will utilize the Tools on behalf \nof Customer, and (c) has signed a confidentiality agreement with \nCustomer in which such employee or independent contractor agrees to \nprotect third party confidential information with terms no less \nstringent than those set forth herein.  A User may be either: a Floating \nUser, Named User or Node-Lock User, as such terms are further defined in \nSection 2 (License Grants). For the avoidance of doubt, a User will be \ndeemed to have utilized the Tools if such User has accessed or used any \nportion of the Tools, including without limitation, to accomplish the \ngoal of, or which results in, any of the following: (a) developing \nCustomer products, including without limitation, software systems, \ndevices, applications or API code, as further specified in Section \n2.1(License Grants); (b) using Tools to compile any code; or other \nsimilar engineering activity or result.\n\n5.8. \"Externally downloadable 3rd party components\" means third party software\nthat we don't include with our code when we ship, however we do include\nrecipes/hooks etc that enable downloading from the third party website. By\nselecting this component, you understand that it will be downloaded and\ninstalled from a third party website.  Such software may involve additional\nlicensing terms. Please contact your legal department should you have any\nquestions regarding licensing terms and obligations.\n\n\n                 APPENDIX B - WIND RIVER LINUX PLATFORM\n                      PRODUCT EVALUATION TERMS\n\n1. SCOPE. These terms govern Customer's rights and obligations with \nrespect to Products which are for Customer's limited evaluation purposes \n(\"Evaluation Software\"). These terms shall supersede any conflicting \nprovisions of the Agreement with respect to the Evaluation Software.\n\n2. LICENSE GRANTS. The following license terms and conditions set forth \nin this Section 2 (and no other terms) will solely apply to Customer's \nuse of Evaluation Software:\n\n2.1. Evaluation License. Subject to Customer's compliance with the terms \nand conditions of the Agreement, Appendix A and this Appendix B, Wind \nRiver hereby grants to Customer a restricted, personal, \nnon-transferable, non-exclusive, internal-use license, for a thirty (30) \nday period from the Effective Date (\"Evaluation Term\") to: (i) use the \nTools solely at the Development Location agreed to in writing by the \nparties and solely for the purpose of internally evaluating the Products \nand not for any other purpose (including without limitation, commercial \nor production purposes); and (ii) reproduce the Tools for archive \npurposes, consistent with Customer's standard archive procedures.\n \n2.2. Feedback. Customer may disclose any results of any evaluation of \nthe Products including, without limitation, Customer's opinions, \nobservations, comments, criticisms and suggested improvements, whether \nin written or oral form (herein, \"Feedback\") from its evaluations only \nto Wind River.  Should Customer provide Wind River with Feedback, Wind \nRiver will have the right to use such Feedback and related information \nin any manner it deems appropriate.\n \n2.3. LIMITED OBLIGATIONS. CUSTOMER ACKNOWLEDGES THAT WIND RIVER HAS NO \nOBLIGATION TO PROVIDE SUPPORT OR MAINTENANCE FOR THE EVALUATION \nSOFTWARE. IN NO EVENT WILL WIND RIVER'S AGGREGATE CUMULATIVE LIABILITY \nFOR ANY CLAIMS ARISING OUT OF OR RELATED TO EVALUATION OF THE PRODUCTS \nEXCEED $50.00.\n\n---\nLinux Click Wrap Rev Feb 2020\n"
  },
  {
    "path": "LICENSE",
    "content": "\t\t    GNU GENERAL PUBLIC LICENSE\n\t\t       Version 2, June 1991\n\n Copyright (C) 1989, 1991 Free Software Foundation, Inc.,\n 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n\t\t\t    Preamble\n\n  The licenses for most software are designed to take away your\nfreedom to share and change it.  By contrast, the GNU General Public\nLicense is intended to guarantee your freedom to share and change free\nsoftware--to make sure the software is free for all its users.  This\nGeneral Public License applies to most of the Free Software\nFoundation's software and to any other program whose authors commit to\nusing it.  (Some other Free Software Foundation software is covered by\nthe GNU Lesser General Public License instead.)  You can apply it to\nyour programs, too.\n\n  When we speak of free software, we are referring to freedom, not\nprice.  Our General Public Licenses are designed to make sure that you\nhave the freedom to distribute copies of free software (and charge for\nthis service if you wish), that you receive source code or can get it\nif you want it, that you can change the software or use pieces of it\nin new free programs; and that you know you can do these things.\n\n  To protect your rights, we need to make restrictions that forbid\nanyone to deny you these rights or to ask you to surrender the rights.\nThese restrictions translate to certain responsibilities for you if you\ndistribute copies of the software, or if you modify it.\n\n  For example, if you distribute copies of such a program, whether\ngratis or for a fee, you must give the recipients all the rights that\nyou have.  You must make sure that they, too, receive or can get the\nsource code.  And you must show them these terms so they know their\nrights.\n\n  We protect your rights with two steps: (1) copyright the software, and\n(2) offer you this license which gives you legal permission to copy,\ndistribute and/or modify the software.\n\n  Also, for each author's protection and ours, we want to make certain\nthat everyone understands that there is no warranty for this free\nsoftware.  If the software is modified by someone else and passed on, we\nwant its recipients to know that what they have is not the original, so\nthat any problems introduced by others will not reflect on the original\nauthors' reputations.\n\n  Finally, any free program is threatened constantly by software\npatents.  We wish to avoid the danger that redistributors of a free\nprogram will individually obtain patent licenses, in effect making the\nprogram proprietary.  To prevent this, we have made it clear that any\npatent must be licensed for everyone's free use or not licensed at all.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.\n\n\t\t    GNU GENERAL PUBLIC LICENSE\n   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\n\n  0. This License applies to any program or other work which contains\na notice placed by the copyright holder saying it may be distributed\nunder the terms of this General Public License.  The \"Program\", below,\nrefers to any such program or work, and a \"work based on the Program\"\nmeans either the Program or any derivative work under copyright law:\nthat is to say, a work containing the Program or a portion of it,\neither verbatim or with modifications and/or translated into another\nlanguage.  (Hereinafter, translation is included without limitation in\nthe term \"modification\".)  Each licensee is addressed as \"you\".\n\nActivities other than copying, distribution and modification are not\ncovered by this License; they are outside its scope.  The act of\nrunning the Program is not restricted, and the output from the Program\nis covered only if its contents constitute a work based on the\nProgram (independent of having been made by running the Program).\nWhether that is true depends on what the Program does.\n\n  1. You may copy and distribute verbatim copies of the Program's\nsource code as you receive it, in any medium, provided that you\nconspicuously and appropriately publish on each copy an appropriate\ncopyright notice and disclaimer of warranty; keep intact all the\nnotices that refer to this License and to the absence of any warranty;\nand give any other recipients of the Program a copy of this License\nalong with the Program.\n\nYou may charge a fee for the physical act of transferring a copy, and\nyou may at your option offer warranty protection in exchange for a fee.\n\n  2. You may modify your copy or copies of the Program or any portion\nof it, thus forming a work based on the Program, and copy and\ndistribute such modifications or work under the terms of Section 1\nabove, provided that you also meet all of these conditions:\n\n    a) You must cause the modified files to carry prominent notices\n    stating that you changed the files and the date of any change.\n\n    b) You must cause any work that you distribute or publish, that in\n    whole or in part contains or is derived from the Program or any\n    part thereof, to be licensed as a whole at no charge to all third\n    parties under the terms of this License.\n\n    c) If the modified program normally reads commands interactively\n    when run, you must cause it, when started running for such\n    interactive use in the most ordinary way, to print or display an\n    announcement including an appropriate copyright notice and a\n    notice that there is no warranty (or else, saying that you provide\n    a warranty) and that users may redistribute the program under\n    these conditions, and telling the user how to view a copy of this\n    License.  (Exception: if the Program itself is interactive but\n    does not normally print such an announcement, your work based on\n    the Program is not required to print an announcement.)\n\nThese requirements apply to the modified work as a whole.  If\nidentifiable sections of that work are not derived from the Program,\nand can be reasonably considered independent and separate works in\nthemselves, then this License, and its terms, do not apply to those\nsections when you distribute them as separate works.  But when you\ndistribute the same sections as part of a whole which is a work based\non the Program, the distribution of the whole must be on the terms of\nthis License, whose permissions for other licensees extend to the\nentire whole, and thus to each and every part regardless of who wrote it.\n\nThus, it is not the intent of this section to claim rights or contest\nyour rights to work written entirely by you; rather, the intent is to\nexercise the right to control the distribution of derivative or\ncollective works based on the Program.\n\nIn addition, mere aggregation of another work not based on the Program\nwith the Program (or with a work based on the Program) on a volume of\na storage or distribution medium does not bring the other work under\nthe scope of this License.\n\n  3. You may copy and distribute the Program (or a work based on it,\nunder Section 2) in object code or executable form under the terms of\nSections 1 and 2 above provided that you also do one of the following:\n\n    a) Accompany it with the complete corresponding machine-readable\n    source code, which must be distributed under the terms of Sections\n    1 and 2 above on a medium customarily used for software interchange; or,\n\n    b) Accompany it with a written offer, valid for at least three\n    years, to give any third party, for a charge no more than your\n    cost of physically performing source distribution, a complete\n    machine-readable copy of the corresponding source code, to be\n    distributed under the terms of Sections 1 and 2 above on a medium\n    customarily used for software interchange; or,\n\n    c) Accompany it with the information you received as to the offer\n    to distribute corresponding source code.  (This alternative is\n    allowed only for noncommercial distribution and only if you\n    received the program in object code or executable form with such\n    an offer, in accord with Subsection b above.)\n\nThe source code for a work means the preferred form of the work for\nmaking modifications to it.  For an executable work, complete source\ncode means all the source code for all modules it contains, plus any\nassociated interface definition files, plus the scripts used to\ncontrol compilation and installation of the executable.  However, as a\nspecial exception, the source code distributed need not include\nanything that is normally distributed (in either source or binary\nform) with the major components (compiler, kernel, and so on) of the\noperating system on which the executable runs, unless that component\nitself accompanies the executable.\n\nIf distribution of executable or object code is made by offering\naccess to copy from a designated place, then offering equivalent\naccess to copy the source code from the same place counts as\ndistribution of the source code, even though third parties are not\ncompelled to copy the source along with the object code.\n\n  4. You may not copy, modify, sublicense, or distribute the Program\nexcept as expressly provided under this License.  Any attempt\notherwise to copy, modify, sublicense or distribute the Program is\nvoid, and will automatically terminate your rights under this License.\nHowever, parties who have received copies, or rights, from you under\nthis License will not have their licenses terminated so long as such\nparties remain in full compliance.\n\n  5. You are not required to accept this License, since you have not\nsigned it.  However, nothing else grants you permission to modify or\ndistribute the Program or its derivative works.  These actions are\nprohibited by law if you do not accept this License.  Therefore, by\nmodifying or distributing the Program (or any work based on the\nProgram), you indicate your acceptance of this License to do so, and\nall its terms and conditions for copying, distributing or modifying\nthe Program or works based on it.\n\n  6. Each time you redistribute the Program (or any work based on the\nProgram), the recipient automatically receives a license from the\noriginal licensor to copy, distribute or modify the Program subject to\nthese terms and conditions.  You may not impose any further\nrestrictions on the recipients' exercise of the rights granted herein.\nYou are not responsible for enforcing compliance by third parties to\nthis License.\n\n  7. If, as a consequence of a court judgment or allegation of patent\ninfringement or for any other reason (not limited to patent issues),\nconditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot\ndistribute so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you\nmay not distribute the Program at all.  For example, if a patent\nlicense would not permit royalty-free redistribution of the Program by\nall those who receive copies directly or indirectly through you, then\nthe only way you could satisfy both it and this License would be to\nrefrain entirely from distribution of the Program.\n\nIf any portion of this section is held invalid or unenforceable under\nany particular circumstance, the balance of the section is intended to\napply and the section as a whole is intended to apply in other\ncircumstances.\n\nIt is not the purpose of this section to induce you to infringe any\npatents or other property right claims or to contest validity of any\nsuch claims; this section has the sole purpose of protecting the\nintegrity of the free software distribution system, which is\nimplemented by public license practices.  Many people have made\ngenerous contributions to the wide range of software distributed\nthrough that system in reliance on consistent application of that\nsystem; it is up to the author/donor to decide if he or she is willing\nto distribute software through any other system and a licensee cannot\nimpose that choice.\n\nThis section is intended to make thoroughly clear what is believed to\nbe a consequence of the rest of this License.\n\n  8. If the distribution and/or use of the Program is restricted in\ncertain countries either by patents or by copyrighted interfaces, the\noriginal copyright holder who places the Program under this License\nmay add an explicit geographical distribution limitation excluding\nthose countries, so that distribution is permitted only in or among\ncountries not thus excluded.  In such case, this License incorporates\nthe limitation as if written in the body of this License.\n\n  9. The Free Software Foundation may publish revised and/or new versions\nof the General Public License from time to time.  Such new versions will\nbe similar in spirit to the present version, but may differ in detail to\naddress new problems or concerns.\n\nEach version is given a distinguishing version number.  If the Program\nspecifies a version number of this License which applies to it and \"any\nlater version\", you have the option of following the terms and conditions\neither of that version or of any later version published by the Free\nSoftware Foundation.  If the Program does not specify a version number of\nthis License, you may choose any version ever published by the Free Software\nFoundation.\n\n  10. If you wish to incorporate parts of the Program into other free\nprograms whose distribution conditions are different, write to the author\nto ask for permission.  For software which is copyrighted by the Free\nSoftware Foundation, write to the Free Software Foundation; we sometimes\nmake exceptions for this.  Our decision will be guided by the two goals\nof preserving the free status of all derivatives of our free software and\nof promoting the sharing and reuse of software generally.\n\n\t\t\t    NO WARRANTY\n\n  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\nFOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN\nOTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\nPROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\nOR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\nMERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS\nTO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE\nPROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\nREPAIR OR CORRECTION.\n\n  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\nWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\nREDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\nINCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\nOUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\nTO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\nYOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\nPROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGES.\n\n\t\t     END OF TERMS AND CONDITIONS\n\n\t    How to Apply These Terms to Your New Programs\n\n  If you develop a new program, and you want it to be of the greatest\npossible use to the public, the best way to achieve this is to make it\nfree software which everyone can redistribute and change under these terms.\n\n  To do so, attach the following notices to the program.  It is safest\nto attach them to the start of each source file to most effectively\nconvey the exclusion of warranty; and each file should have at least\nthe \"copyright\" line and a pointer to where the full notice is found.\n\n    <one line to give the program's name and a brief idea of what it does.>\n    Copyright (C) <year>  <name of author>\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n\nAlso add information on how to contact you by electronic and paper mail.\n\nIf the program is interactive, make it output a short notice like this\nwhen it starts in an interactive mode:\n\n    Gnomovision version 69, Copyright (C) year name of author\n    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\n    This is free software, and you are welcome to redistribute it\n    under certain conditions; type `show c' for details.\n\nThe hypothetical commands `show w' and `show c' should show the appropriate\nparts of the General Public License.  Of course, the commands you use may\nbe called something other than `show w' and `show c'; they could even be\nmouse-clicks or menu items--whatever suits your program.\n\nYou should also get your employer (if you work as a programmer) or your\nschool, if any, to sign a \"copyright disclaimer\" for the program, if\nnecessary.  Here is a sample; alter the names:\n\n  Yoyodyne, Inc., hereby disclaims all copyright interest in the program\n  `Gnomovision' (which makes passes at compilers) written by James Hacker.\n\n  <signature of Ty Coon>, 1 April 1989\n  Ty Coon, President of Vice\n\nThis General Public License does not permit incorporating your program into\nproprietary programs.  If your program is a subroutine library, you may\nconsider it more useful to permit linking proprietary applications with the\nlibrary.  If this is what you want to do, use the GNU Lesser General\nPublic License instead of this License.\n"
  },
  {
    "path": "README.md",
    "content": "wrlinux setup\n=============\n\nWith this tool you can either create a new distribution builder platform\nproject, or create a mirror that other projects can be based on.\n\nIn addition, you can use the tool to obtain information about available\nproject configuration options.\n\nThe tool uses a layer index (such as layers.openembedded.org), as specified in\nthe bin/settings.py file, to determine what layers are required to construct\na distribution builder project.\n\nThe tool relies on 'repo' from the Android 'git-repo' project.  It produces\na repo style 'default.xml' file, and then calls repo to download all of\nthe layer components necessary.\n\nThe tool also configures various sample files that are used by \noe-init-build-env to construct your build directory.\n\n\nDocumentation\n-------------\n\nFor documentation, see the Wind River Knowledge Library:\nhttps://knowledge.windriver.com\n\nSelect \"Products > Operating Systems > Linux > Linux LTS\" to view all\ndocumentation categories.\n\nIt is suggested that you start with:\n_The Wind River Linux Platform Development Quick Start_.\n\nWhen following the quick start and other examples, use:\n\n    branchName: WRLINUX_10_21_BASE\n    repoURL: git://<git mirror>/git/wrlinux-x\n\n\nWorkflows\n---------\n\nBasic setup/usage workflow:\n\nThe setup program is expected to have been cloned inside of a project\ndirectory, such as:\n\n    $ mkdir my-project\n    $ cd my-project\n    $ git clone --branch <branchName> <repoURL> wrlinux-x\n\nOnce cloned, simply run the setup.sh (./wrlinux-x/setup.sh) to get a list\nof options.  The setup program will construct a new git repository in the\ncurrent working directory.  This repository is used to manage the output of\nthe setup program.\n\nYou may re-run the setup program at any time to update/change the project\nsettings.  However, your build directory will not be touched.  You will have\nto resync it with the updated project.  (Specifically bblayers.conf and\nlocal.conf to the config/*.sample versions.)\n\nTo update your project, re-run the setup program with the same arguments.\nNote the original arguments are available in the generated README file.\n\n\nMirror workflow:\n\n    $ mkdir my-mirror\n    $ cd my-mirror\n    $ git clone --branch <branchName> <repoURL> wrlinux-x\n    $ ./wrlinux-x/setup.sh --all-layers --mirror\n\nThe above command will mirror all layers, including download layers into the\ncurrent location, for the branch specified.\n\nTo update the mirror, re-run the setup.sh command with the same arguments.\nTo add additional branches to your mirror, change the branch in the wrlinux-x,\nand re-run the setup.sh with the same arguments.\n\nA user can reference this mirror by doing:\n\n    $ mkdir my-project\n    $ cd my-project\n    $ git clone --branch <branchName> <path_to_mirror>/wrlinux-x\n\nand then run the wrlinux-x/setup.sh program as described above.\n\n\nLicense\n-------\n\nCopyright (C) 2016-2017 Wind River Systems, Inc.\n\nThis program is free software; you can redistribute it and/or modify\nit under the terms of the GNU General Public License version 2 as\npublished by the Free Software Foundation.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n"
  },
  {
    "path": "bin/.pylintrc",
    "content": "[MASTER]\n\n# Specify a configuration file.\n#rcfile=\n\n# Python code to execute, usually for sys.path manipulation such as\n# pygtk.require().\n#init-hook=\n\n# Add files or directories to the blacklist. They should be base names, not\n# paths.\nignore=CVS\n\n# Add files or directories matching the regex patterns to the blacklist. The\n# regex matches against base names, not paths.\nignore-patterns=\n\n# Pickle collected data for later comparisons.\npersistent=yes\n\n# List of plugins (as comma separated values of python modules names) to load,\n# usually to register additional checkers.\nload-plugins=\n\n# Use multiple processes to speed up Pylint.\njobs=2\n\n# Allow loading of arbitrary C extensions. Extensions are imported into the\n# active Python interpreter and may run arbitrary code.\nunsafe-load-any-extension=no\n\n# A comma-separated list of package or module names from where C extensions may\n# be loaded. Extensions are loading into the active Python interpreter and may\n# run arbitrary code\nextension-pkg-whitelist=\n\n# Allow optimization of some AST trees. This will activate a peephole AST\n# optimizer, which will apply various small optimizations. For instance, it can\n# be used to obtain the result of joining multiple strings with the addition\n# operator. Joining a lot of strings can lead to a maximum recursion error in\n# Pylint and this flag can prevent that. It has one side effect, the resulting\n# AST will be different than the one from reality. This option is deprecated\n# and it will be removed in Pylint 2.0.\noptimize-ast=no\n\n\n[MESSAGES CONTROL]\n\n# Only show warnings with the listed confidence levels. Leave empty to show\n# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED\nconfidence=\n\n# Enable the message, report, category or checker with the given id(s). You can\n# either give multiple identifier separated by comma (,) or put this option\n# multiple time (only on the command line, not in the configuration file where\n# it should appear only once). See also the \"--disable\" option for examples.\n#enable=\n\n# Disable the message, report, category or checker with the given id(s). You\n# can either give multiple identifiers separated by comma (,) or put this\n# option multiple times (only on the command line, not in the configuration\n# file where it should appear only once).You can also use \"--disable=all\" to\n# disable everything first and then reenable specific checks. For example, if\n# you want to run only the similarities checker, you can use \"--disable=all\n# --enable=similarities\". If you want to run only the classes checker, but have\n# no Warning level messages displayed, use\"--disable=all --enable=classes\n# --disable=W\"\ndisable=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\n\n\n[REPORTS]\n\n# Set the output format. Available formats are text, parseable, colorized, msvs\n# (visual studio) and html. You can also give a reporter class, eg\n# mypackage.mymodule.MyReporterClass.\noutput-format=text\n\n# Put messages in a separate file for each module / package specified on the\n# command line instead of printing them on stdout. Reports (if any) will be\n# written in a file name \"pylint_global.[txt|html]\". This option is deprecated\n# and it will be removed in Pylint 2.0.\nfiles-output=no\n\n# Tells whether to display a full report or only the messages\nreports=no\n\n# Python expression which should return a note less than 10 (10 is the highest\n# note). You have access to the variables errors warning, statement which\n# respectively contain the number of errors / warnings messages and the total\n# number of statements analyzed. This is used by the global evaluation report\n# (RP0004).\nevaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)\n\n# Template used to display messages. This is a python new-style format string\n# used to format the message information. See doc for all details\n#msg-template=\n\n\n[MISCELLANEOUS]\n\n# List of note tags to take in consideration, separated by a comma.\nnotes=FIXME,XXX,TODO\n\n\n[SPELLING]\n\n# Spelling dictionary name. Available dictionaries: none. To make it working\n# install python-enchant package.\nspelling-dict=\n\n# List of comma separated words that should not be checked.\nspelling-ignore-words=\n\n# A path to a file that contains private dictionary; one word per line.\nspelling-private-dict-file=\n\n# Tells whether to store unknown words to indicated private dictionary in\n# --spelling-private-dict-file option instead of raising a message.\nspelling-store-unknown-words=no\n\n\n[LOGGING]\n\n# Logging modules to check that the string format arguments are in logging\n# function parameter format\n#logging-modules=logging\n\n\n[SIMILARITIES]\n\n# Minimum lines number of a similarity.\nmin-similarity-lines=4\n\n# Ignore comments when computing similarities.\nignore-comments=yes\n\n# Ignore docstrings when computing similarities.\nignore-docstrings=yes\n\n# Ignore imports when computing similarities.\nignore-imports=no\n\n\n[TYPECHECK]\n\n# Tells whether missing members accessed in mixin class should be ignored. A\n# mixin class is detected if its name ends with \"mixin\" (case insensitive).\nignore-mixin-members=yes\n\n# List of module names for which member attributes should not be checked\n# (useful for modules/projects where namespaces are manipulated during runtime\n# and thus existing member attributes cannot be deduced by static analysis. It\n# supports qualified module names, as well as Unix pattern matching.\nignored-modules=\n\n# List of class names for which member attributes should not be checked (useful\n# for classes with dynamically set attributes). This supports the use of\n# qualified names.\nignored-classes=optparse.Values,thread._local,_thread._local\n\n# List of members which are set dynamically and missed by pylint inference\n# system, and so shouldn't trigger E1101 when accessed. Python regular\n# expressions are accepted.\ngenerated-members=\n\n# List of decorators that produce context managers, such as\n# contextlib.contextmanager. Add to this list to register other decorators that\n# produce valid context managers.\ncontextmanager-decorators=contextlib.contextmanager\n\n\n[VARIABLES]\n\n# Tells whether we should check for unused import in __init__ files.\ninit-import=no\n\n# A regular expression matching the name of dummy variables (i.e. expectedly\n# not used).\ndummy-variables-rgx=(_+[a-zA-Z0-9]*?$)|dummy\n\n# List of additional names supposed to be defined in builtins. Remember that\n# you should avoid to define new builtins when possible.\nadditional-builtins=\n\n# List of strings which can identify a callback function by name. A callback\n# name must start or end with one of those strings.\ncallbacks=cb_,_cb\n\n# List of qualified module names which can have objects that can redefine\n# builtins.\nredefining-builtins-modules=six.moves,future.builtins\n\n\n[FORMAT]\n\n# Maximum number of characters on a single line.\nmax-line-length=100\n\n# Regexp for a line that is allowed to be longer than the limit.\nignore-long-lines=^\\s*(# )?<?https?://\\S+>?$\n\n# Allow the body of an if to be on the same line as the test if there is no\n# else.\nsingle-line-if-stmt=no\n\n# List of optional constructs for which whitespace checking is disabled. `dict-\n# separator` is used to allow tabulation in dicts, etc.: {1  : 1,\\n222: 2}.\n# `trailing-comma` allows a space between comma and closing bracket: (a, ).\n# `empty-line` allows space-only lines.\nno-space-check=trailing-comma,dict-separator\n\n# Maximum number of lines in a module\nmax-module-lines=1000\n\n# String used as indentation unit. This is usually \"    \" (4 spaces) or \"\\t\" (1\n# tab).\nindent-string='    '\n\n# Number of spaces of indent required inside a hanging  or continued line.\nindent-after-paren=4\n\n# Expected format of line ending, e.g. empty (any line ending), LF or CRLF.\nexpected-line-ending-format=\n\n\n[BASIC]\n\n# Good variable names which should always be accepted, separated by a comma\ngood-names=i,j,k,ex,Run,_\n\n# Bad variable names which should always be refused, separated by a comma\nbad-names=foo,bar,baz,toto,tutu,tata\n\n# Colon-delimited sets of names that determine each other's naming style when\n# the name regexes allow several styles.\nname-group=\n\n# Include a hint for the correct naming format with invalid-name\ninclude-naming-hint=no\n\n# List of decorators that produce properties, such as abc.abstractproperty. Add\n# to this list to register other decorators that produce valid properties.\nproperty-classes=abc.abstractproperty\n\n# Regular expression matching correct constant names\nconst-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$\n\n# Naming hint for constant names\nconst-name-hint=(([A-Z_][A-Z0-9_]*)|(__.*__))$\n\n# Regular expression matching correct class attribute names\nclass-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$\n\n# Naming hint for class attribute names\nclass-attribute-name-hint=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$\n\n# Regular expression matching correct inline iteration names\ninlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$\n\n# Naming hint for inline iteration names\ninlinevar-name-hint=[A-Za-z_][A-Za-z0-9_]*$\n\n# Regular expression matching correct argument names\nargument-rgx=[a-z_][a-z0-9_]{2,30}$\n\n# Naming hint for argument names\nargument-name-hint=[a-z_][a-z0-9_]{2,30}$\n\n# Regular expression matching correct variable names\nvariable-rgx=[a-z_][a-z0-9_]{2,30}$\n\n# Naming hint for variable names\nvariable-name-hint=[a-z_][a-z0-9_]{2,30}$\n\n# Regular expression matching correct method names\nmethod-rgx=[a-z_][a-z0-9_]{2,30}$\n\n# Naming hint for method names\nmethod-name-hint=[a-z_][a-z0-9_]{2,30}$\n\n# Regular expression matching correct module names\nmodule-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$\n\n# Naming hint for module names\nmodule-name-hint=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$\n\n# Regular expression matching correct function names\nfunction-rgx=[a-z_][a-z0-9_]{2,30}$\n\n# Naming hint for function names\nfunction-name-hint=[a-z_][a-z0-9_]{2,30}$\n\n# Regular expression matching correct class names\nclass-rgx=[A-Z_][a-zA-Z0-9]+$\n\n# Naming hint for class names\nclass-name-hint=[A-Z_][a-zA-Z0-9]+$\n\n# Regular expression matching correct attribute names\nattr-rgx=[a-z_][a-z0-9_]{2,30}$\n\n# Naming hint for attribute names\nattr-name-hint=[a-z_][a-z0-9_]{2,30}$\n\n# Regular expression which should only match function or class names that do\n# not require a docstring.\nno-docstring-rgx=^_\n\n# Minimum line length for functions/classes that require docstrings, shorter\n# ones are exempt.\ndocstring-min-length=-1\n\n\n[ELIF]\n\n# Maximum number of nested blocks for function / method body\nmax-nested-blocks=5\n\n\n[DESIGN]\n\n# Maximum number of arguments for function / method\nmax-args=10\n\n# Argument names that match this expression will be ignored. Default to name\n# with leading underscore\nignored-argument-names=_.*\n\n# Maximum number of locals for function / method body\nmax-locals=50\n\n# Maximum number of return / yield for function / method body\nmax-returns=6\n\n# Maximum number of branch for function / method body\nmax-branches=30\n\n# Maximum number of statements in function / method body\nmax-statements=50\n\n# Maximum number of parents for a class (see R0901).\nmax-parents=7\n\n# Maximum number of attributes for a class (see R0902).\nmax-attributes=7\n\n# Minimum number of public methods for a class (see R0903).\nmin-public-methods=2\n\n# Maximum number of public methods for a class (see R0904).\nmax-public-methods=20\n\n# Maximum number of boolean expressions in a if statement\nmax-bool-expr=5\n\n\n[CLASSES]\n\n# List of method names used to declare (i.e. assign) instance attributes.\ndefining-attr-methods=__init__,__new__,setUp\n\n# List of valid names for the first argument in a class method.\nvalid-classmethod-first-arg=cls\n\n# List of valid names for the first argument in a metaclass class method.\nvalid-metaclass-classmethod-first-arg=mcs\n\n# List of member names, which should be excluded from the protected access\n# warning.\nexclude-protected=_asdict,_fields,_replace,_source,_make\n\n\n[IMPORTS]\n\n# Deprecated modules which should not be used, separated by a comma\ndeprecated-modules=optparse\n\n# Create a graph of every (i.e. internal and external) dependencies in the\n# given file (report RP0402 must not be disabled)\nimport-graph=\n\n# Create a graph of external dependencies in the given file (report RP0402 must\n# not be disabled)\next-import-graph=\n\n# Create a graph of internal dependencies in the given file (report RP0402 must\n# not be disabled)\nint-import-graph=\n\n# Force import order to recognize a module as part of the standard\n# compatibility libraries.\nknown-standard-library=\n\n# Force import order to recognize a module as part of a third party library.\nknown-third-party=enchant\n\n# Analyse import fallback blocks. This can be used to support both Python 2 and\n# 3 compatible code, which means that the block might have code that exists\n# only in one or another interpreter, leading to false positives when analysed.\nanalyse-fallback-blocks=no\n\n\n[EXCEPTIONS]\n\n# Exceptions that will emit a warning when being caught. Defaults to\n# \"Exception\"\novergeneral-exceptions=Exception\n"
  },
  {
    "path": "bin/LICENSE.texttable",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2018 Gerome Fournier\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n"
  },
  {
    "path": "bin/Makefile",
    "content": "SHELL = /bin/bash #requires bash\nVENV = $(PWD)/.venv/\nDEPS = $(wildcard *.py)\nTMP_PIP = $(VENV)/get-pip.py\nPYTHON3 := $(shell command -v python3 2> /dev/null)\nWGET := $(shell command -v wget 2> /dev/null)\n\n.PHONY: setup lint clean test help\n\n.DEFAULT_GOAL := build\n\nhelp:\n\t@echo \"Make options for oe-chef development\"\n\t@echo\n\t@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = \":.*?## \"}; {printf \"\\033[36m%-10s\\033[0m %s\\n\", $$1, $$2}'\n\n$(VENV):\nifndef PYTHON3\n    $(error \"python3 is not installed.\")\nendif\nifndef WGET\n    $(error \"wget is not installed.\")\nendif\n\ttest -d $(VENV) || python3 -m venv --without-pip $(VENV); \\\n\ttouch $(VENV); \\\n\t. $(VENV)/bin/activate; \\\n\twget -O $(TMP_PIP) https://bootstrap.pypa.io/get-pip.py; \\\n\tpython3 $(TMP_PIP); \\\n\tpip3 install pylint nose flake8;\n\nsetup: $(VENV) ## Install all python dependencies in virtualenv\n\nclean: ## Delete virtualenv and all build directories\n\trm -rf $(VENV)\n\ntest: setup ## Run tests\n\t. $(VENV)/bin/activate; python3 test/test_oe_chef.py\n\nlint: setup ## Run pylint\n\t. $(VENV)/bin/activate; pylint $(DEPS)\n"
  },
  {
    "path": "bin/argparse_setup.py",
    "content": "# Copyright (C) 2016 Wind River Systems, Inc.\n#\n# This program is free software; you can redistribute it and/or modify\n# it under the terms of the GNU General Public License version 2 as\n# published by the Free Software Foundation.\n#\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n# See the GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program; if not, write to the Free Software\n# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n\n# Note this class MUST run in both python2 and python3\n\nimport argparse\nimport sys\nimport os\n\nfrom urllib.parse import urlparse\n\nimport logger_setup\nlogger = logger_setup.setup_logging()\n\nclass Argparse_Setup:\n    def __init__(self, setup, parser=None):\n        if not parser:\n            parser = argparse.ArgumentParser(description='setup.py: Application to fetch & setup a distribution project.')\n        self.layer_select = False\n        self.parser = parser\n        self.setup = setup\n        # Each group's layername must have a group keyword, for example:\n        # - meta-examplekey\n        # - meta-examplekey-layer1\n        # - meta-examplekey-layer2\n        # The examplekey is the keyword for these layers. It will be used to\n        # check against the layername from layerindex (not layer's directory\n        # name). Any layername contains the keyword is treated as an extra\n        # group layer, and they should only be enabled when\n        # --use-layer-groups=keyword or --layers=layer is specified.\n        # Add the new keyword here when there is a new extra group.\n        self.extra_group_keys=['ccm']\n\n    def evaluate_args(self, args):\n        self.add_options()\n        parsed_args = self.parser.parse_args(args)\n        self.handle_setup_args(parsed_args, args)\n\n    def handle_setup_args(self, parsed_args, args):\n        # Parse setup options\n        if (parsed_args.verbose):\n            if self.setup:\n                self.setup.set_debug()\n            del parsed_args.verbose\n\n        if (parsed_args.base_url):\n            if self.setup:\n                self.setup.set_base_url(parsed_args.base_url)\n            del parsed_args.base_url\n\n        if (parsed_args.base_branch):\n            if self.setup:\n                self.setup.set_base_branch(parsed_args.base_branch)\n            del parsed_args.base_branch\n\n        # Parse repo option\n        if (parsed_args.repo_verbose):\n            if self.setup:\n                self.setup.set_repo_verbose(parsed_args.repo_verbose)\n            del parsed_args.repo_verbose\n\n        if (parsed_args.repo_jobs):\n            if self.setup:\n                self.setup.set_jobs(parsed_args.repo_jobs)\n            del parsed_args.repo_jobs\n\n        if (parsed_args.repo_depth):\n            if self.setup:\n                self.setup.set_depth(parsed_args.repo_depth)\n            del parsed_args.repo_depth\n\n        if (parsed_args.repo_force_sync):\n            if self.setup:\n                self.setup.set_force_sync(parsed_args.repo_force_sync)\n            del parsed_args.repo_force_sync\n\n        if (parsed_args.repo_url):\n            if self.setup:\n                self.setup.set_repo_url(parsed_args.repo_url)\n            del parsed_args.repo_url\n\n        if (parsed_args.repo_branch):\n            if self.setup:\n                self.setup.set_repo_rev(parsed_args.repo_branch)\n            del parsed_args.repo_branch\n\n        # Look for list options\n        if parsed_args.list_distros:\n            if self.setup:\n                self.setup.list_distros = parsed_args.list_distros\n\n        if parsed_args.list_machines:\n            if self.setup:\n                self.setup.list_machines = parsed_args.list_machines\n\n        if parsed_args.list_layers:\n            if self.setup:\n                self.setup.list_layers = True\n\n        if parsed_args.list_recipes:\n            if self.setup:\n                self.setup.list_recipes = True\n\n        if parsed_args.repo_no_fetch:\n            if self.setup:\n                self.setup.repo_no_fetch = True\n            del parsed_args.repo_no_fetch\n\n\n        if (parsed_args.list_distros or parsed_args.list_machines or parsed_args.list_layers or parsed_args.list_recipes):\n            return\n\n        # Parse layer selection options\n        if parsed_args.distros:\n            self.layer_select = True\n            if self.setup:\n                self.setup.distros = []\n                for d in parsed_args.distros:\n                    for distro in d.split(','):\n                        self.setup.distros.append(distro)\n\n        if parsed_args.machines:\n            self.layer_select = True\n            if self.setup:\n                self.setup.machines = []\n                for m in parsed_args.machines:\n                    for machine in m.split(','):\n                        self.setup.machines.append(machine)\n\n        if parsed_args.layers:\n            self.layer_select = True\n            if self.setup:\n                self.setup.layers = []\n                for l in parsed_args.layers:\n                    for layer in l.split(','):\n                        if '://' in layer:\n                            # check if layer has a valid url scheme\n                            url = urlparse(layer)\n                            if url.scheme and url.scheme != 'file':\n                                remote_layer = {}\n                                remote_layer['branch'] = 'master'\n                                remote = layer.split('+')\n                                remote_layer['url'] = remote[0]\n                                remote_layer['path'] = 'layers/' + remote[0].split('/')[-1]\n                                for arg in remote[1:]:\n                                    if arg.startswith('branch='):\n                                        remote_layer['branch'] = arg[7:]\n\n                                self.setup.remote_layers.append(remote_layer)\n                            else:\n                                logger.warning(\"Skipping invalid remote url: %s\" % (layer))\n                        elif '/' in layer or os.path.exists(layer):\n                            layer = os.path.realpath(layer)\n                            if not os.path.isdir(layer):\n                                logger.warning(\"Skipping invalid local layer %s\" % (layer))\n                            else:\n                                self.setup.local_layers.append(layer)\n                        else:\n                            self.setup.layers.append(layer)\n\n        if parsed_args.recipes:\n            self.layer_select = True\n            if self.setup:\n                self.setup.recipes = []\n                for r in parsed_args.recipes:\n                    for recipe in r.split(','):\n                        self.setup.recipes.append(recipe)\n\n        if parsed_args.all_layers:\n            self.layer_select = True\n            if self.setup:\n                self.setup.all_layers = parsed_args.all_layers\n\n        if parsed_args.no_recommend:\n            self.layer_select = True\n            if self.setup:\n                self.setup.no_recommend = parsed_args.no_recommend\n\n        if (parsed_args.mirror):\n            if self.layer_select is not True:\n                print('ERROR: The --mirror option requires at least one Layer Section argument, see --help.')\n                sys.exit(1)\n\n            if self.setup:\n                self.setup.mirror = parsed_args.mirror\n\n        if parsed_args.use_layer_groups:\n            if self.setup:\n                self.setup.use_layer_groups = parsed_args.use_layer_groups\n\n        if self.layer_select is not True:\n            print('ERROR: You must include at least one Layer Selection argument, see --help.')\n            sys.exit(1)\n\n    def add_setup_options(self):\n        # Setup options\n        self.parser.add_argument('-v', '--verbose', help='Set the verbosity to debug', action=\"store_true\")\n\n        self.base_args = self.parser.add_argument_group('Base Settings')\n\n        setup_base_url = \"\"\n        if self.setup and self.setup.base_url:\n            setup_base_url = '(default %s)' % (self.setup.base_url)\n        self.base_args.add_argument('--base-url', metavar=\"URL\", help='URL to fetch from %s' % (setup_base_url))\n\n        setup_base_branch = \"\"\n        if self.setup and self.setup.base_branch:\n            setup_base_branch = '(default %s)' % (self.setup.base_branch)\n        self.base_args.add_argument('--base-branch', metavar=\"BRANCH\", help='Base branch identifier %s' % (setup_base_branch))\n\n        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')\n    def add_repo_options(self):\n        self.repo_args = self.parser.add_argument_group('repo Settings')\n        # Repo options\n        setup_jobs = \"\"\n        self.repo_args.add_argument('-rv', '--repo-verbose', action='store_true', help='Disables use of --quiet with repo commands')\n        if self.setup and self.setup.jobs:\n            setup_jobs = '(default %s)' % (self.setup.jobs)\n        self.repo_args.add_argument('-rj', '--repo-jobs', metavar='JOBS', help='Sets repo project to fetch simultaneously %s' % (setup_jobs))\n        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)')\n        self.repo_args.add_argument('--repo-force-sync', action='store_true', help='Sets repo --force-sync; see repo sync --help')\n        self.repo_args.add_argument('--repo-no-fetch', help='Do all the setup but do not call repo sync', action=\"store_true\")\n\n        repo_url = \"\"\n        if 'REPO_URL' in os.environ:\n            repo_url = '(default %s)' % os.environ['REPO_URL']\n\n        repo_rev = \"\"\n        if 'REPO_REV' in os.environ:\n            repo_rev = '(default %s)' % os.environ['REPO_REV']\n\n        self.repo_args.add_argument('--repo-url', metavar=\"URL\", help='Url for git-repo %s' % (repo_url))\n        self.repo_args.add_argument('--repo-branch', metavar=\"REV\", help='Url for git-repo %s' % (repo_rev))\n\n\n    def add_list_options(self):\n        self.list_args = self.parser.add_argument_group('Layer Listings')\n        # List options\n        self.list_args.add_argument('--list-distros',   metavar='all', nargs='?', const='default', help='List available distro values')\n        self.list_args.add_argument('--list-machines',  metavar='all', nargs='?', const='default', help='List available machine values')\n        self.list_args.add_argument('--list-layers',    action='store_true', help='List all available layers')\n        self.list_args.add_argument('--list-recipes',   action='store_true', help='List all available recipes')\n\n    def add_layer_options(self):\n        self.layer_args = self.parser.add_argument_group('Layer Selection')\n\n        # Layer selection and local.conf setup\n        setup_distro = \"\"\n        setup_distro_str = \"\"\n        if self.setup and self.setup.distros:\n            setup_distro = self.setup.distros[0]\n            setup_distro_str = '(default %s)' % setup_distro\n        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=\"+\")\n\n        setup_machine = \"\"\n        setup_machine_str = \"\"\n        if self.setup and self.setup.machines:\n            setup_machine = self.setup.machines[0]\n            setup_machine_str = '(default %s)' % setup_machine\n        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='+')\n\n        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='+')\n        self.layer_args.add_argument('--recipes', metavar='RECIPE', help='Select layers(s) based on recipe(s)', nargs='+')\n        self.layer_args.add_argument('--all-layers', help='Select all available layers', action='store_true')\n        self.layer_args.add_argument('--no-recommend', help='Disable recommended layers during layer resolution', action='store_true')\n        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)\n\n    def add_other_options(self):\n        pass\n\n    def add_options(self):\n        self.add_setup_options()\n        self.add_repo_options()\n        self.add_list_options()\n        self.add_layer_options()\n        self.add_other_options()\n"
  },
  {
    "path": "bin/argparse_wrl.py",
    "content": "# Copyright (C) 2016 Wind River Systems, Inc.\n#\n# This program is free software; you can redistribute it and/or modify\n# it under the terms of the GNU General Public License version 2 as\n# published by the Free Software Foundation.\n#\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n# See the GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program; if not, write to the Free Software\n# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n\n# Note this class must run in both python2 and python3\n\nimport argparse\nimport logging\nimport string\nimport sys\n\nfrom argparse_setup import Argparse_Setup\n\nclass Argparse_Wrl(Argparse_Setup):\n    def __init__(self, setup, parser=None):\n        self.parser = argparse.ArgumentParser(description='setup.py: Application to fetch & setup a WindRiver Linux project.')\n        Argparse_Setup.__init__(self, setup, parser)\n\n    def handle_setup_args(self, parsed_args, args):\n        if (parsed_args.buildtools_branch):\n            # ignore (handled by setup.sh)\n            del parsed_args.buildtools_branch\n\n        if (parsed_args.buildtools_type):\n            # ignore (handled by setup.sh)\n            del parsed_args.buildtools_type\n\n        if (parsed_args.user):\n            # ignore (handled by setup.sh)\n            del parsed_args.user\n\n        if (parsed_args.password):\n            # ignore (handled by setup.sh)\n            del parsed_args.password\n\n        if parsed_args.no_anspass:\n            # ignore (handled by setup.sh)\n            del parsed_args.no_anspass\n\n        if (parsed_args.accept_eula):\n            # ignore (handled by setup.sh)\n            del parsed_args.accept_eula\n\n        if parsed_args.list_templates:\n            if self.setup:\n                self.setup.list_wrtemplates = parsed_args.list_templates\n\n        if (parsed_args.list_templates):\n            return\n\n        if parsed_args.templates:\n            self.layer_select = True\n            if self.setup:\n                self.setup.wrtemplates = []\n                for t in parsed_args.templates:\n                    for wrtemplate in t.split(','):\n                        self.setup.wrtemplates.append(wrtemplate)\n\n        if parsed_args.dl_layers:\n            self.layer_select = True\n            if self.setup:\n                self.setup.dl_layers = parsed_args.dl_layers\n\n        Argparse_Setup.handle_setup_args(self, parsed_args, args)\n\n    def add_setup_options(self):\n        Argparse_Setup.add_setup_options(self)\n\n        setup_buildtools_branch = \"\"\n        if self.setup and self.setup.buildtools_branch:\n            setup_buildtools_branch = '(default %s)' % (self.setup.buildtools_branch)\n        self.base_args.add_argument('--buildtools-branch', metavar=\"BRANCH\", help='Buildtools branch %s' % (setup_buildtools_branch))\n        self.base_args.add_argument('--buildtools-type', metavar=\"TYPE\", help=\"Buildtools type: basic or extended (default basic), install extended buildtools with 'extended'\")\n        self.base_args.add_argument('--user', help='Specify default user for download')\n        self.base_args.add_argument('--password', help='Specify default password for download')\n        self.base_args.add_argument('--accept-eula', metavar=\"ACCEPT\", help='Accept End User License Agreement (yes|no)')\n        self.base_args.add_argument('--no-anspass', action='store_true', help='Do not use anspass to save the user name and password')\n\n    def add_list_options(self):\n        Argparse_Setup.add_list_options(self)\n        self.list_args.add_argument('--list-templates', metavar='all', nargs='?', const='default', help='List available templates')\n\n    def add_layer_options(self):\n        Argparse_Setup.add_layer_options(self)\n        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='+')\n        self.layer_args.add_argument('--dl-layers', help='Enable download layers; these layers include predownloaded items', action='store_true')\n"
  },
  {
    "path": "bin/branch_mirror.py",
    "content": "#!/usr/bin/env python3\n\n# Copyright (C) 2016 Wind River Systems, Inc.\n#\n# This program is free software; you can redistribute it and/or modify\n# it under the terms of the GNU General Public License version 2 as\n# published by the Free Software Foundation.\n#\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n# See the GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program; if not, write to the Free Software\n# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n\n# This program will identify the layers, and their current branches,\n# that need to be branched as part of the release process.\n#\n# The program will branch them and provide a list that can be used\n# to push the items.\n#\n# The program will also update the mirror index entries with the\n# branch names.\n\nimport os\nimport sys\n\nimport subprocess\n\nimport xml.etree.ElementTree as ET\n\nimport utils_setup\n\nfrom layer_index import Layer_Index\n\nimport logger_setup\n\nimport settings\n\ncompleted = []\n\ndef usage():\n    print(\"usage: %s <branch> [--force]\" % sys.argv[0])\n    sys.exit(1)\n\nif len(sys.argv) < 2:\n    usage()\n\nlogger = logger_setup.setup_logging()\n\ndest_branch = sys.argv[1]\n\nforce = False\nif len(sys.argv) > 2:\n    if sys.argv[2] != '--force':\n        usage()\n\n    force = True\n\nmirror_path = 'mirror-index'\nif not os.path.exists(mirror_path):\n    logger.critical('No mirror-index found. %s' % mirror_path)\n    sys.exit(1)\n\ncmd = ['git', 'rev-parse', '--abbrev-ref', 'HEAD']\nret = subprocess.Popen(cmd, cwd=mirror_path, close_fds=True, stdout=subprocess.PIPE)\nbranch = \"\"\noutput = \"\"\nwhile True:\n    output = ret.stdout.readline()\n    if not output and ret.poll() is not None:\n        break\n    branch += output.decode('utf-8')\nret.wait()\nbranch = branch.strip()\n\nif branch == dest_branch:\n    logger.warning('Branch is already configured!')\n\nwork_list = []\n\ndef git_branch(_dst, _orig_branch, _branch):\n    logger.info('Branching %s: %s -> %s' % (_dst, _orig_branch, _branch))\n\n    # Break this into two commands, so it will work with tags as well...\n    _cmd = [ 'git', 'fetch', '.', '%s' % (_orig_branch) ]\n    utils_setup.run_cmd(_cmd, cwd=_dst)\n\n    _cmd = [ 'git', 'branch', _branch, 'FETCH_HEAD' ]\n    if force:\n        _cmd.append('-f')\n    utils_setup.run_cmd(_cmd, cwd=_dst)\n\n    work_list.append('%s %s' % (_dst, _branch))\n\n# We assume this program is located in the bin directory\ndst = os.path.dirname(os.path.dirname(sys.argv[0]))\n\n# Branch the setup program....\ngit_branch(_dst=dst, _orig_branch=branch, _branch=dest_branch)\ncompleted.append(dst)\n\n# Transform and export the mirror index\ngit_branch(mirror_path, branch, dest_branch)\ncompleted.append(mirror_path)\n\nindex = Layer_Index(indexcfg=settings.INDEXES, base_branch=branch, replace=settings.REPLACE, mirror=mirror_path)\n\ncmd = ['git', 'checkout', dest_branch]\nutils_setup.run_cmd(cmd, cwd=mirror_path)\n\nlogger.info('Loading default.xml')\ntree = ET.parse('default.xml')\nroot = tree.getroot()\n\n\n\nlogger.info('Branching based on default.xml')\ndefault_revision = None\nbase_url = None\nfor child in root:\n    if child.tag == 'remote':\n        if 'fetch' in child.attrib:\n            base_url = child.attrib['fetch']\n\n    if child.tag == 'default':\n        if 'revision' in child.attrib:\n            default_revision = child.attrib['revision']\n\n    if child.tag != 'project':\n        continue\n\n    src = child.attrib['name']\n\n    if not os.path.exists(src):\n        if os.path.exists(src + '.git'):\n            src += '.git'\n        else:\n            logger.warning('Unable to find %s' % src)\n            continue\n\n    revision = None\n    if not ('bare' in child.attrib and child.attrib['bare'] == 'True'):\n        revision = default_revision\n        if 'revision' in child.attrib:\n            revision = child.attrib['revision']\n\n    if revision:\n        git_branch(src, revision, dest_branch)\n    completed.append(src)\n\n\n\nlogger.info('Transforming default.xml')\nfor child in root:\n    if 'revision' in child.attrib:\n        child.attrib['revision'] = dest_branch\nopen('default.xml', 'wt').write(ET.tostring(root, encoding='unicode'))\n\n\n\nlogger.info('Transforming index...')\n\nbitbake_branch = branch\nbranchid = None\nfor lindex in index.index:\n    for branches in lindex['branches']:\n        if 'name' in branches and branches['name'] == branch:\n            branches['name'] = dest_branch\n            if 'bitbake_branch' in branches and branches['bitbake_branch'] != '':\n                bitbake_branch = branches['bitbake_branch']\n                branches['bitbake_branch'] = dest_branch\n            branchid = branches['id']\n\n    for layer in lindex['layerItems']:\n        if layer['vcs_url']:\n            for lb in lindex['layerBranches']:\n                if layer['id'] == lb['layer'] and lb['branch'] == branchid:\n                    if 'actual_branch' in lb and lb['actual_branch'] != \"\":\n                        lb['actual_branch'] = ''\n\n    # Remove older entries\n    for (dirpath, dirnames, filenames) in os.walk(mirror_path):\n        if dirpath.endswith('/.git') or '/.git/' in dirpath or dirpath.endswith('/xml') or '/xml/' in dirpath:\n            continue\n        for filename in filenames:\n            if filename.startswith(lindex['CFG']['DESCRIPTION'].translate(str.maketrans('/ ', '__'))):\n                os.remove(os.path.join(dirpath, filename))\n\n    index.serialize_index(lindex, os.path.join(mirror_path, lindex['CFG']['DESCRIPTION']), split=True, IncludeCFG=True, mirror=True, base_url=base_url)\n\n# git add file.\ncmd = ['git', 'add', '-A', '.']\nutils_setup.run_cmd(cmd, cwd=mirror_path)\n\ncmd = ['git', 'diff-index', '--quiet', 'HEAD', '--']\ntry:\n    utils_setup.run_cmd(cmd, cwd=mirror_path)\nexcept:\n    logger.debug('Updating mirror-index')\n    cmd = ['git', 'commit', '-m', 'Branch (%s) and adjust index entries' % (dest_branch)]\n    utils_setup.run_cmd(cmd, cwd=mirror_path)\n\nlogger.info('Done')\n\nlogger.plain('Writing branched-layer.list...')\noutput = open('branched-layer.list', 'wt')\nfor item in work_list:\n    output.write(\"%s\\n\" % item)\noutput.close()\n"
  },
  {
    "path": "bin/dump_layer_dependencies.py",
    "content": "#!/usr/bin/env python3\n\n# Copyright (C) 2016-2017 Wind River Systems, Inc.\n#\n# This program is free software; you can redistribute it and/or modify\n# it under the terms of the GNU General Public License version 2 as\n# published by the Free Software Foundation.\n#\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n# See the GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program; if not, write to the Free Software\n# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n\n# This program will dump the dependencies for one or more layers in a\n# given branch.  It can be used to verify that when a branch is created\n# that the dependencies have been scanned properly.\n\n# Adjust the standard WR urls to make comparisons easier.\nREPLACE = [\n            ( 'git://git.wrs.com/', '#BASE_URL#' ),\n            ( 'http://git.wrs.com/cgit/', '#BASE_WEB#' ),\n          ]\n\n# Note the branch can be hard coded.  This is required only when you want\n# to limit the branch from a restapi-web import.  (This does not do anything\n# on other input formats.)\nINDEXES = [\n    {\n        'DESCRIPTION' : 'Wind River Developer Layer Index',\n        'TYPE' : 'restapi-web',\n        'URL' : 'http://layers.wrs.com/layerindex/api/',\n        'CACHE' : None,\n        #'BRANCH' : 'master-wr',\n    },\n]\n\nimport os\nimport sys\n\nfrom layer_index import Layer_Index\n\ndef usage():\n    print(\"usage: %s <branch>\" % sys.argv[0])\n    sys.exit(1)\n\nif len(sys.argv) < 2:\n    usage()\n\nbase_branch=sys.argv[1]\n\nindex = Layer_Index(INDEXES, base_branch=base_branch, replace=REPLACE)\n\nimport unicodedata\nfor lindex in index.index:\n    dep_out = []\n    branchid = index.getBranchId(lindex, index.getIndexBranch(default=base_branch, lindex=lindex))\n    if branchid:\n        for lb in lindex['layerBranches']:\n            if lb['branch'] == branchid:\n                for layer in index.find_layer(lindex, layerBranch=lb):\n                    name = layer['name']\n                    (required, recommended) = index.getDependencies(lindex, lb)\n                    reqnames = []\n                    recnames = []\n                    for req in required:\n                        for layer in index.find_layer(lindex, layerBranch=req):\n                            reqnames.append(layer['name'])\n                    for rec in recommended:\n                        for layer in index.find_layer(lindex, layerBranch=rec):\n                            recnames.append(layer['name'])\n\n                    dep_out.append((name, ' '.join(sorted(reqnames)), ' '.join(sorted(recnames))))\n\n    for (name, reqs, recs) in sorted(dep_out, key=lambda t: t[0]):\n       print('%s %s (%s)' % (name, reqs, recs))\n"
  },
  {
    "path": "bin/dump_layer_rev.py",
    "content": "#!/usr/bin/env python3\n\n# Copyright (C) 2016 Wind River Systems, Inc.\n#\n# This program is free software; you can redistribute it and/or modify\n# it under the terms of the GNU General Public License version 2 as\n# published by the Free Software Foundation.\n#\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n# See the GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program; if not, write to the Free Software\n# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n\n# This program will load the index and for each layer list the layer,\n# branch and current commit.  This can be used to verify that the\n# index and layers are in sync.\n\nimport os\nimport sys\n\nimport settings\n\nfrom layer_index import Layer_Index\n\nmirror_path = 'mirror-index'\nif not os.path.exists(mirror_path):\n    if not os.path.exists(mirror_path + '.git'):\n        print('No %s found.  Is this a mirror?' % mirror_path)\n        sys.exit(1)\n    else:\n        mirror_path = mirror_path + '.git'\n\nindex = Layer_Index(indexcfg=settings.INDEXES, base_branch=None, replace=settings.REPLACE, mirror=mirror_path)\n\nfor lindex in index.index:\n    for branch in lindex['branches']:\n        basebranch = branch['name']\n        for litem in lindex['layerItems']:\n            for lbranch in lindex['layerBranches']:\n                if lbranch['layer'] == litem['id']:\n                    branch = basebranch\n                    if lbranch['actual_branch'] != \"\":\n                        branch = lbranch['actual_branch']\n                    print('%s %s %s %s' % (litem['name'], litem['vcs_url'], branch, lbranch['vcs_last_rev']))\n                    break\n"
  },
  {
    "path": "bin/flatten_mirror.py",
    "content": "#!/usr/bin/env python3\n\n# Copyright (C) 2016 Wind River Systems, Inc.\n#\n# This program is free software; you can redistribute it and/or modify\n# it under the terms of the GNU General Public License version 2 as\n# published by the Free Software Foundation.\n#\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n# See the GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program; if not, write to the Free Software\n# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n\n# This program will flatten a mirror and copy the result into a target dir.\n#\n# Many git servers require a single flat level of git trees in order to\n# work properly.  Flattening the tree will require both renaming directories\n# as well as updating the mirror-index to match.\n\n# Format of the subset folder file is:\n# <layer> <folder>\n#\n# <layer> is the name in the layer index of that layer\n# <folder> is a directory to generate inside of the <dest>\n#\n# Note, if this is used, an error will be generated for any known layers\n# that are not assigned to a folder.\n#\n# A special folder name '[SKIP]' is defined when you are intentionally\n# skipping a layer.\n\nimport argparse\n\nimport os\nimport sys\n\nimport shutil\n\nimport subprocess\n\nimport xml.etree.ElementTree as ET\n\nimport utils_setup\n\nfrom layer_index import Layer_Index\n\nimport logger_setup\n\nimport settings\n\ndef config_args(args):\n    parser = argparse.ArgumentParser(description='flatten_mirror.py: Flatten a mirror.')\n\n    parser.add_argument('dest', help='Destination Directory')\n\n    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')\n    parser.add_argument('--subset-mirror', metavar='FILE', help='Use a file that will allow the system to subset the mirror into specific subdirectories.')\n    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')\n\n    parsed_args = parser.parse_args(args)\n\n    return (parsed_args.dest, parsed_args.push_not_copy, parsed_args.subset_mirror, parsed_args.strip_git)\n\ndef push_or_copy(_layer, _src, _dst, _branch=None):\n    if subset_folders:\n        if _layer not in subset_folders:\n            logger.critical(\"Layer %s (%s) not in SUBSET_FOLDERS\" % (_layer, _src))\n            raise\n        elif subset_folders[_layer] == \"[SKIP]\":\n            return\n        else:\n            dstdir = os.path.dirname(_dst)\n            dstbase = os.path.basename(_dst)\n            _dst = os.path.join(dstdir, subset_folders[_layer], dstbase)\n\n    if not os.path.exists(_src):\n        _src += '.git'\n        if not os.path.exists(_src):\n            logger.critical(\"Unable to find %s!\" % _src)\n            raise\n\n    # Make output consistent\n    if not strip_git and not _dst.endswith('.git'):\n        _dst += '.git'\n\n    if strip_git and _dst.endswith('.git'):\n        _dst = _dst[:-4]\n\n    if not git_push or not _branch:\n        logger.plain('cp %s -> %s' % (_src, _dst))\n        shutil.copytree(_src, _dst, symlinks=True, ignore_dangling_symlinks=True)\n    else:\n        logger.plain('push %s -> %s (%s)' % (_src, _dst, _branch))\n        if os.path.exists(_dst):\n            logger.critical('Destination %s already exists!' % _dst)\n            raise\n        os.makedirs(_dst, exist_ok=True)\n\n        # New bare repo\n        _cmd = [ 'git', 'init', '--bare' ]\n        utils_setup.run_cmd(_cmd, cwd=_dst)\n\n        # Push just the one branch\n        _cmd = [ 'git', 'push', os.path.abspath(_dst), _branch ]\n        utils_setup.run_cmd(_cmd, cwd=_src)\n\n# Used to subset target mirror path, if necessary\n\n# Return the mirror_directory target for a given layer entry.\n# If the target directory does not exist, we create it (git repository)\n#\n# This function will return None if the layer is to be skipped.\ndef get_mirror_dir(_layer, _dst):\n    if subset_folders:\n        if _layer in subset_folders:\n            if subset_folders[_layer] == \"[SKIP]\":\n                return None\n\n            dstdir = os.path.dirname(_dst)\n            dstbase = os.path.basename(_dst)\n            _dst = os.path.join(dstdir, subset_folders[_layer], dstbase)\n        else:\n            logger.error(\"Layer %s not in SUBSET_FOLDERS\" % _layer)\n            # Use default directory\n\n    # If the target directory does not exist, create it\n    if not os.path.exists(_dst):\n        cmd = ['git', 'init', _dst]\n        utils_setup.run_cmd(cmd)\n\n        if not branch or branch == \"\":\n            logger.critical('Where did the branch val go!? %s' % branch)\n            raise\n\n        cmd = ['git', 'checkout', '-b', branch]\n        try:\n            utils_setup.run_cmd(cmd, cwd=_dst)\n        except:\n            # if we failed, then simply try to switch branches\n            cmd = ['git', 'checkout', branch]\n            utils_setup.run_cmd(cmd, cwd=_dst)\n\n    return _dst\n\n# Return the layer specific XML directory.  The XML directory\n# lives inside of the mirror path.  If the mirror directory does\n# not already exist it is created by callign get_mirror_dir\n#\n# This function will return None if the layer is to be skipped.\ndef get_xml_dir(_layer, _mirror):\n    _mirror = get_mirror_dir(_layer, _mirror)\n    if _mirror:\n        return os.path.join(_mirror, 'xml')\n    return _mirror\n\n# Process and transform the specified XML files.  Return a list of\n# project names referenced by this XML file.\n#\n# If the _dest is None, we still process the XML layer, but we never\n# write out a result.  This is necessary to parse the components owned\n# by the xml file so we know to skip them...\ndef transform_xml(_src, _dest):\n    logger.plain('Processing %s' % _src)\n    if not os.path.exists(_src):\n        logger.warning('Not found %s' % _src)\n        return []\n\n    if _dest:\n        os.makedirs(os.path.dirname(_dest), exist_ok=True)\n        with open(_src, 'rt') as fin, open(_dest, 'wt') as fout:\n            return transform_xml_inside(fin, fout)\n    else:\n        with open(_src, 'rt') as fin:\n            return transform_xml_inside(fin, None)\n\ndef transform_xml_inside(_fin, _fout):\n    result = []\n\n    for _line in _fin:\n        modified = False\n        try:\n            _root = ET.fromstring(_line)\n        except:\n            logger.warning('exception on: %s' % _line)\n            if _fout:\n                _fout.write('%s' % _line)\n            continue\n\n        # Skip linkfiles, don't warn.. we know these are valid\n        if _root.tag == 'linkfile':\n            if _fout:\n                _fout.write('%s' % _line)\n            continue\n\n        if _root.tag != 'project':\n            logger.warning('Not project: %s' % _line)\n            if _fout:\n                _fout.write('%s' % _line)\n            continue\n\n        for attrib in _root.attrib:\n            if attrib == 'name':\n                result.append(_root.attrib['name'])\n                if _root.attrib['name'] != _root.attrib['name'].split('/')[-1]:\n                    _root.attrib['name'] = _root.attrib['name'].split('/')[-1]\n                    modified = True\n\n        for _child in _root:\n            for attrib in _child.attrib:\n                if attrib == 'name':\n                    result.append(_child.attrib['name'])\n                    if _child.attrib['name'] != _child.attrib['name'].split('/')[-1]:\n                        _child.attrib['name'] = _child.attrib['name'].split('/')[-1]\n                        modified = True\n\n        if _fout:\n            if modified:\n                _fout.write('    %s\\n' % (ET.tostring(_root, encoding='unicode')))\n            else:\n                _fout.write('%s' % _line)\n\n    return result\n\n# Process the mirrors and add any new files to the git repo\ndef update_mirror(_dst_mirror):\n    cmd = ['git', 'add', '-A', '.']\n    utils_setup.run_cmd(cmd, cwd=_dst_mirror)\n\n    logger.debug('Updating mirror-index')\n    cmd = ['git', 'commit', '-m', 'Updated index - Flatten Mirror']\n    try:\n        utils_setup.run_cmd(cmd, cwd=_dst_mirror, log=2)\n    except:\n        # Nothing changed...\n        pass\n\ndef copy_premirrors_dl(dest):\n    premirrors_dl = \"premirrors-dl/downloads/\"\n    if os.path.exists(premirrors_dl):\n        logger.plain(\"Copying %s\" % premirrors_dl)\n    else:\n        return\n    cmd = \"cp --parent -a\".split()\n    if os.stat(premirrors_dl).st_dev == os.stat(dest).st_dev:\n        # Hard link when possible\n        cmd.append(\"-l\")\n    cmd += [premirrors_dl, dest]\n    utils_setup.run_cmd(cmd)\n\n# This assumes variables 'dest', 'git_push', 'subset_file' and\n# 'setup_dir' is globally set.\ndef main():\n    global subset_folders\n    global branch\n\n    if subset_file:\n        subset_folders = {}\n        with open(subset_file, 'rt') as f:\n            for line in f:\n                if line.startswith('#'):\n                    continue\n                lsplit = line.split()\n                if len(lsplit) == 0:\n                    continue\n                if len(lsplit) != 2:\n                    logger.critical(\"Subset Folders, invalid line: %s\" % (line))\n                    return 1\n                subset_folders[lsplit[0]] = lsplit[1]\n\n    if os.path.exists(dest):\n        logger.critical('Destination directory %s already exists.  Please choose a different destination.' % (dest))\n        return 1\n\n    # We have to run this against a mirror, check for a mirror-index\n    mirror_path = 'mirror-index'\n    if not os.path.exists(mirror_path):\n        logger.critical('No %s found.  Is this a mirror?' % mirror_path)\n        return 1\n\n    dst_base_mirror = os.path.join(dest, mirror_path)\n\n    # Find the base branch of the mirror-index to set a default\n    cmd = ['git', 'rev-parse', '--abbrev-ref', 'HEAD']\n    _ret = subprocess.Popen(cmd, cwd=mirror_path, close_fds=True, stdout=subprocess.PIPE)\n    branch = \"\"\n    output = \"\"\n    while True:\n        output = _ret.stdout.readline()\n        if not output and _ret.poll() is not None:\n            break\n        branch += output.decode('utf-8')\n    _ret.wait()\n    branch = branch.strip()\n\n    if not branch or branch == \"\":\n        logger.critical('Unable to determine base branch.')\n        return 1\n\n    # Create the destination\n    os.makedirs(dest, exist_ok=False)\n\n    #### Load the index and create a list of things we need to parse\n\n    # this is the list of things that MAY be in the default.xml file, we need\n    # to have a list to later process that file and exclude things we've already\n    # done.\n    processed_list = []\n\n    ### Create the target mirror-index...\n    # Transform and export the mirror index\n    logger.plain('Transforming index...')\n\n    index = Layer_Index(indexcfg=settings.INDEXES, base_branch=branch, replace=settings.REPLACE, mirror=mirror_path)\n\n    branchid = -1\n    base_branch = branch\n    bitbake_branch = branch\n    for lindex in index.index:\n        if 'CFG' in lindex:\n            base_branch = lindex['CFG']['BRANCH']\n            bitbake_branch = branch\n\n        for b in lindex['branches']:\n            if 'name' in b and b['name'] == base_branch:\n                branchid = b['id']\n                if 'bitbake_branch' in b and b['bitbake_branch'] != \"\":\n                    bitbake_branch = b['bitbake_branch']\n                break\n\n        logger.info('Discovered base_branch: %s (%s)' % (base_branch, branchid))\n        logger.info('Discovered bitbake_branch: %s' % bitbake_branch)\n\n        for layer in lindex['layerItems']:\n            logger.info('Processing layer %s...' % layer['name'])\n\n            # Identify, manipulate and copy the layer...\n            if 'vcs_url' in layer:\n                full_url = layer['vcs_url'].replace('#BASE_URL#/', '')\n                base_url = layer['vcs_url'].split('/')[-1]\n\n                layer['vcs_url'] = '#BASE_URL#' + '/' + base_url\n                layer['vcs_web_url'] = ''\n                layer['vcs_web_tree_base_url'] = ''\n                layer['vcs_web_file_base_url'] = ''\n                layer['mailing_list_url'] = ''\n\n                # Find actual_branch if one is there\n                revision = base_branch\n                for lb in lindex['layerBranches']:\n                    if lb['branch'] == branchid and lb['layer'] == layer['id']:\n                        if lb['actual_branch'] != \"\":\n                            revision = lb['actual_branch']\n\n                src = full_url\n                dst = os.path.join(dest, os.path.basename(src))\n\n                if src not in processed_list:\n                    push_or_copy(layer['name'], src, dst, revision)\n                    processed_list.append(src)\n\n            xml_dir = get_xml_dir(layer['name'], dst_base_mirror)\n\n            def xml_dest_dir(_xml_dir, _name):\n                if not _xml_dir:\n                    return None\n                return os.path.join(_xml_dir, _name)\n\n            src = os.path.join(mirror_path, 'xml', '%s.inc' % layer['name'])\n            if os.path.exists(src):\n                xml_dst = xml_dest_dir(xml_dir, '%s.inc' % layer['name'])\n                for name in transform_xml(src, xml_dst):\n                    dst = os.path.join(dest, os.path.basename(name))\n                    if name not in processed_list:\n                        push_or_copy(layer['name'], name, dst)\n                        processed_list.append(name)\n\n            src = os.path.join(mirror_path, 'xml', '%s.xml' % layer['name'])\n            if os.path.exists(src):\n                xml_dst = xml_dest_dir(xml_dir, '%s.xml' % layer['name'])\n                for name in transform_xml(src, xml_dst):\n                    dst = os.path.join(dest, os.path.basename(name))\n                    if name not in processed_list:\n                        push_or_copy(layer['name'], name, dst)\n                        processed_list.append(name)\n\n            # OpenEmbedded-Core is a bit unique.  There are a few items\n            # that need to be grouped by this subset entry, these are\n            # items NOT included in the index or default.xml\n            #\n            #   wrlinux-x\n            #   git-repo\n            #   bitbake\n            if layer['name'] == 'openembedded-core':\n                # wrlinux-x (or whatever it's called) convert to bare using .git\n                src = os.path.join(setup_dir, '.git')\n                dst = os.path.join(dest, os.path.basename(setup_dir))\n                if src not in processed_list:\n                    push_or_copy(layer['name'], src, dst, branch)\n                    processed_list.append(src)\n\n                # git-repo\n                src = os.path.join(os.path.dirname(full_url), 'git-repo')\n                dst = os.path.join(dest, os.path.basename(src))\n                if src not in processed_list:\n                    push_or_copy(layer['name'], src, dst)\n                    processed_list.append(src)\n\n                # bitbake\n                src = os.path.join(os.path.dirname(full_url), 'bitbake')\n                dst = os.path.join(dest, os.path.basename(src))\n                if src not in processed_list:\n                    push_or_copy(layer['name'], src, dst, bitbake_branch)\n                    processed_list.append(src)\n\n                src = os.path.join(mirror_path, 'xml', 'bitbake.inc')\n                if os.path.exists(src):\n                    xml_dst = xml_dest_dir(xml_dir, 'bitbake.inc')\n                    for name in transform_xml(src, xml_dst):\n                        dst = os.path.join(dest, os.path.basename(name))\n                        if name not in processed_list:\n                            push_or_copy(layer['name'], name, dst)\n                            processed_list.append(name)\n\n                src = os.path.join(mirror_path, 'xml', 'bitbake.xml')\n                if os.path.exists(src):\n                    xml_dst = xml_dest_dir(xml_dir, 'bitbake.xml')\n                    for name in transform_xml(src, xml_dst):\n                        dst = os.path.join(dest, os.path.basename(name))\n                        if name not in processed_list:\n                            push_or_copy(layer['name'], name, dst)\n                            processed_list.append(name)\n\n        # dst_base_mirror may not exist if we're subsetting...\n        os.makedirs(dst_base_mirror, exist_ok=True)\n        index.serialize_index(lindex, os.path.join(dst_base_mirror, lindex['CFG']['DESCRIPTION']), split=True, IncludeCFG=True, mirror=True, base_url=base_url)\n\n        # Since serialize can't subset, we do it manually...\n        # if the rules change in layer_index.py, adjust them here..\n        if subset_folders:\n            base_branch = branch\n            if 'CFG' in lindex:\n                base_branch = lindex['CFG']['BRANCH']\n\n            for layer in lindex['layerItems']:\n                json = \"%s__%s__%s.json\" % (lindex['CFG']['DESCRIPTION'], base_branch, layer['name'])\n                json = json.translate(str.maketrans('/ ', '__'))\n\n                src = os.path.join(dst_base_mirror, json)\n                mirror_dir = get_mirror_dir(layer['name'], dst_base_mirror)\n                if not mirror_dir:\n                    # Skipped item, remove it and continue\n                    logger.plain('rm %s' % src)\n                    os.remove(src)\n                    continue\n                dst = os.path.join(mirror_dir, json)\n                os.makedirs(os.path.dirname(dst), exist_ok=True)\n                logger.plain('mv %s -> %s' % (src, dst))\n                os.rename(src, dst)\n\n            # Directory is expected to be empty, remove it.\n            os.rmdir(dst_base_mirror)\n\n    #### Now process anythign else we've not yet processed\n    logger.info('Processing left-overs...')\n\n    # Now process the default.xml, and process anything not previous processed...\n    tree = ET.parse('default.xml')\n    root = tree.getroot()\n\n    default_revision = None\n    base_url = None\n    for child in root:\n        if child.tag == 'remote':\n            if 'fetch' in child.attrib:\n                base_url = child.attrib['fetch']\n\n        if child.tag == 'default':\n            if 'revision' in child.attrib:\n                default_revision = child.attrib['revision']\n\n        if child.tag != 'project':\n            continue\n\n        src = child.attrib['name']\n\n        if src in processed_list or src + '.git' in processed_list:\n            continue\n\n        dst = os.path.join(dest, os.path.basename(src))\n\n        revision = None\n        if not ('bare' in child.attrib and child.attrib['bare'] == 'True'):\n            revision = default_revision\n            if 'revision' in child.attrib:\n                revision = child.attrib['revision']\n\n        push_or_copy(os.path.basename(src), src, dst, revision)\n\n    #### Update the mirror-index repositories (git add/git commit)\n    logger.plain('Updating mirror-index repositories...')\n\n    # git add file.\n    if subset_folders:\n        index_list = []\n        for layer in subset_folders:\n            if subset_folders[layer] == \"[SKIP]\":\n                continue\n            dst_mirror = get_mirror_dir(layer, dst_base_mirror)\n            if dst_mirror not in index_list:\n                index_list.append(dst_mirror)\n\n        for dst_mirror in index_list:\n            update_mirror(dst_mirror)\n    else:\n        update_mirror(dst_base_mirror)\n\n    copy_premirrors_dl(dest)\n\n    logger.plain('Done')\n    return 0\n\n\n# Define globals\nif __name__ == '__main__':\n    logger = logger_setup.setup_logging()\n    dest, git_push, subset_file, strip_git = config_args(sys.argv[1:])\n\n    subset_folders = None\n    branch = None\n\n    setup_dir = os.path.dirname(os.path.dirname(sys.argv[0]))\n\n    ret = main()\n    sys.exit(ret)\n"
  },
  {
    "path": "bin/layer_index.py",
    "content": "# Copyright (C) 2016 Wind River Systems, Inc.\n#\n# This program is free software; you can redistribute it and/or modify\n# it under the terms of the GNU General Public License version 2 as\n# published by the Free Software Foundation.\n#\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n# See the GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program; if not, write to the Free Software\n# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n\nimport json\n\nimport sys\nimport os\nimport difflib\n\n\nfrom collections import OrderedDict\n\nimport logger_setup\n\nimport utils_setup\n\nimport texttable as tt\n\n# type, url/path, description, cache\n# type:  restapi-web   - REST API from a LayerIndex-web\n#        restapi-files - REST API, but only from files\n#        export        - Exported DB from a LayerIndex-web -- reads file(s)\n\nlogger = logger_setup.setup_logging()\nclass Layer_Index():\n    # Index in REST-API format...  This is used by external items.\n    index = []\n\n    def __init__(self, indexcfg=[], base_branch=None, replace=[], mirror=None):\n        self.index = []\n\n        # Do we have local mirror entries to load?\n        m_index = {}\n\n        if mirror:\n            for (dirpath, dirnames, filenames) in os.walk(mirror):\n                if dirpath.endswith('/.git') or '/.git/' in dirpath or dirpath.endswith('/xml') or '/xml/' in dirpath:\n                    continue\n                for filename in filenames:\n                    # Serialize function, ALWAYS writes out w/ .json extension\n                    if not filename.endswith('.json'):\n                        continue\n                    pindex = self.load_serialized_index(os.path.join(dirpath, filename), name='Mirrored Index')\n                    # A mirror can be made up of multiple indexes, so we need to identify which one they belong to\n                    if pindex and pindex['CFG']['DESCRIPTION'] in m_index:\n                        lindex = m_index[pindex['CFG']['DESCRIPTION']]\n                        for entry in pindex:\n                            if 'apilinks' == entry:\n                                continue\n                            if 'CFG' == entry:\n                                # Conflicts don't matter here, just accept it\n                                lindex[entry] = pindex[entry]\n                                continue\n                            if entry not in lindex:\n                                lindex[entry] = []\n                            try:\n                                lindex[entry] = self.__add_cmp_lists(pindex[entry], lindex[entry])\n                            except TypeError as error:\n                                raise TypeError('Merge failed of pindex[%s] and lindex[%s]: %s' % (entry, entry, error))\n                    else: # Not already know\n                        m_index[pindex['CFG']['DESCRIPTION']] = pindex\n\n        for cfg in indexcfg:\n            lindex = None\n\n            branch = base_branch\n            indextype = None\n            indexurl = None\n            indexname = None\n            indexcache = None\n\n            if 'TYPE' in cfg:\n                indextype = cfg['TYPE']\n\n            if 'URL' in cfg:\n                indexurl = cfg['URL']\n\n            if 'DESCRIPTION' in cfg:\n                indexname = cfg['DESCRIPTION']\n\n            if 'CACHE' in cfg:\n                indexcache = cfg['CACHE']\n\n            if 'BRANCH' in cfg:\n                branch = cfg['BRANCH']\n\n            # Replace magic values with real values...\n            for (find, rep) in replace:\n                indexurl = indexurl.replace(find, rep)\n                if branch:\n                    branch = branch.replace(find, rep)\n\n            # Do we have an mirrored version? If so use it, skip regular processing\n            if indexname in m_index:\n                logger.plain('Using index %s from the mirror index...' % (indexname))\n                lindex = m_index[indexname]\n            else:\n               logger.plain('Loading index %s from %s...' % (indexname, indexurl))\n\n            # If not previously loaded from the mirror, attempt to load...\n            if not lindex:\n                if indextype == 'restapi-web':\n                    lindex = self.load_API_Index(indexurl, indexname, branches=branch)\n                elif indextype == 'restapi-files':\n                    lindex = self.load_serialized_index(indexurl, name=indexname)\n                elif indextype == 'export':\n                    lindex = self.load_django_export(indexurl, name=indexname)\n                elif not lindex:\n                    # Unknown index type...\n                    logger.error('Unknown index type %s' % indextype)\n                    raise SyntaxError('Unknown index type %s' % indextype)\n\n            # If we couldn't pull from the regular location, pull from the cache!\n            if lindex is None and indexcache and os.path.exists(indexcache + '.json'):\n                logger.plain('Falling back to the index cache %s...' % (indexcache))\n                lindex = self.load_serialized_index(indexcache + '.json', name=indexname, branches=[branch])\n\n            if not lindex or 'branches' not in lindex or 'layerItems' not in lindex or 'layerBranches' not in lindex:\n                logger.warning('Index %s was empty... Ignoring.' % indexname)\n                continue\n\n            # Start data transforms...\n            for entry in lindex['layerItems']:\n                for obj in entry:\n                    # Run replace on any 'url' items.\n                    if 'url' in obj:\n                        vcs_url = entry[obj]\n                        for (find, rep) in replace:\n                            vcs_url = vcs_url.replace(find, rep)\n                        entry[obj] = vcs_url\n\n            # Cache the data we loaded... (after replacements) if we loaded data.\n            if lindex and indexcache:\n                dir = os.path.dirname(indexcache)\n                if dir:\n                    os.makedirs(dir, exist_ok=True)\n                self.serialize_index(lindex, indexcache, split=False)\n\n            lindex['CFG'] = cfg\n            lindex['CFG']['BRANCH'] = branch\n\n            if lindex and 'distros' in lindex:\n                # Default setup is actually implemented as 'nodistro'\n                for (idx, dist) in enumerate(lindex['distros']):\n                    if dist['name'] == \"defaultsetup\":\n                        dist['name'] = 'nodistro'\n                        lindex['distros'][idx] = dist\n\n            # Everything works off layerBranches, so make sure to keep it sorted!\n            lindex['layerBranches'] = self.sortEntry(lindex['layerBranches'])\n\n            if lindex:\n                self.index.append(lindex)\n\n\n    def load_API_Index(self, url, name=None, branches=None):\n        \"\"\"\n            Fetches layer information from a remote layer index.\n            The return value is a dictionary containing API,\n            layer, branch, dependency, recipe, machine, distro,\n            and template information.\n\n            url is the url to the rest api of the layer index, such as:\n            http://layers.openembedded.org/layerindex/api/\n\n            branches is a str or list of branches to filter on\n        \"\"\"\n        lindex = {}\n\n        assert url is not None\n\n        logger.debug('Loading %s from url %s...' % (name, url))\n\n        def _get_json_response(apiurl=None, retry=True):\n            assert apiurl is not None\n\n            res = utils_setup.fetch_url(apiurl)\n\n            try:\n                parsed = json.loads(res.read().decode('utf-8'))\n            except ConnectionResetError:\n                if retry:\n                    logger.debug(\"%s: Connection reset by peer.  Retrying...\" % url)\n                    parsed = _get_json_response(apiurl=apiurl, retry=False)\n                    logger.debug(\"%s: retry successful.\")\n                else:\n                    logger.critical(\"%s: Connection reset by peer.\" % url)\n                    logger.critical(\"Is there a firewall blocking your connection?\")\n                    sys.exit(1)\n            except:\n                if retry:\n                    logger.debug(\"%s: get response failed. Retrying...\" % url)\n                    parsed = _get_json_response(apiurl=apiurl, retry=False)\n                    logger.debug(\"%s: retry successful.\")\n                else:\n                    logger.critical(\"%s: get response failed\" % url)\n                    sys.exit(1)\n\n            return parsed\n\n        from urllib.request import URLError\n        try:\n            lindex['apilinks'] = _get_json_response(url)\n        except URLError as e:\n            logger.warning(\"Index %s: could not connect to %s: %s\" % (name, url, e.reason))\n            return None\n\n        filter = \"\"\n        # If it's list, keep it, if it's a string change it to a list\n        if branches and type(branches) == type(str()):\n            branches = [branches]\n        if branches:\n            filter = \"?filter=name:%s\" \\\n                     % \"OR\".join(branches)\n        lindex['branches'] = _get_json_response(lindex['apilinks']['branches'] + filter)\n\n        if not lindex['branches']:\n            logger.warning(\"No valid branches (%s) found at url %s.\" % (branches or \"*\", url))\n            return lindex\n\n        filter = \"\"\n        if branches:\n            filter = \"?filter=branch__name:%s\" \\\n                     % \"OR\".join(branches)\n        lindex['layerBranches'] = _get_json_response(lindex['apilinks']['layerBranches'] + filter)\n        if not lindex['layerBranches']:\n            logger.warning(\"No layers on branches (%s) found at url %s.\" % (branches or \"*\", url))\n            return lindex\n\n        layerids = []\n        for i, layerBranch in enumerate(lindex['layerBranches']):\n            layerids.append(\"%s\" % layerBranch['layer'])\n\n        lindex['layerItems'] = _get_json_response(lindex['apilinks']['layerItems'])\n\n        filter = \"\"\n        if branches:\n            filter = \"?filter=layerbranch__branch__name:%s\" \\\n                     % \"OR\".join(branches)\n        lindex['layerDependencies'] = _get_json_response(lindex['apilinks']['layerDependencies'] + filter)\n\n        filter = \"\"\n        if branches:\n            filter = \"?filter=layerbranch__branch__name:%s\" \\\n                     % \"OR\".join(branches)\n        lindex['machines'] = _get_json_response(lindex['apilinks']['machines'] + filter)\n\n        filter = \"\"\n        if branches:\n            filter = \"?filter=layerbranch__branch__name:%s\" \\\n                     % \"OR\".join(branches)\n        lindex['recipes'] = _get_json_response(lindex['apilinks']['recipes'] + filter)\n\n        filter = \"\"\n        if branches:\n            filter = \"?filter=layerbranch__branch__name:%s\" \\\n                     % \"OR\".join(branches)\n        if 'distros' in lindex['apilinks']:\n            lindex['distros'] = _get_json_response(lindex['apilinks']['distros'] + filter)\n        else:\n            # Not all layer indexes have a distribution API.  If not we need to emulate nodistro.\n            lindex['distros'] = []\n            idx = 1\n            for branch in lindex['branches']:\n                for lb in self.getLayerBranch(lindex, branch['id'], name='openembedded-core'):\n                    lindex['distros'].append({\"layerbranch\": lb['id'], \"id\": idx, \"description\": \"default\", \"updated\": \"2016-01-01T00:00:00+0000\", \"name\": \"nodistro\"})\n                    idx = idx + 1\n\n        filter = \"\"\n        if branches:\n            filter = \"?filter=layerbranch__branch__name:%s\" \\\n                     % \"OR\".join(branches)\n        if 'wrtemplates' in lindex['apilinks']:\n            lindex['wrtemplates'] = _get_json_response(lindex['apilinks']['wrtemplates'] + filter)\n        else:\n            lindex['wrtemplates'] = []\n\n        if 'YPCompatibleVersions' in lindex['apilinks']:\n            lindex['YPCompatibleVersions'] = _get_json_response(lindex['apilinks']['YPCompatibleVersions'])\n        else:\n            lindex['YPCompatibleVersions'] = []\n\n        logger.debug('...loading %s from url %s, done.' % (name, url))\n\n        return lindex\n\n    # Merge listone and listtwo, returning listtwo\n    def __add_cmp_lists(self, listone, listtwo):\n        # Copy the items from listone, into listtwo -- if it isn't already\n        # there..  if it is there, verify it's the same or raise an error...\n\n        if not listone: # List one is empty, just return listtwo\n            return listtwo\n\n        if not listtwo: # List two is empty, just return listone\n            return listone\n\n        for one in reversed(listone):\n            found = False\n            for two in listtwo:\n                if 'id' in one and 'id' in two:\n                    if one['id'] == two['id']:\n                        found = True\n                        # Contents need to be the same!\n                        if one != two:\n                            # Something is out of sync here...\n                            raise TypeError('Cannot merge two objects with the same id %s, but different contents:\\n%s\\n%s' % (one['id'], one, two))\n                        break\n                else:\n                    # This is not a valid object\n                    if not 'id' in one and 'id' in two:\n                        raise TypeError('No id in object from the first parameter list:\\n%s' % (one))\n                    if 'id' in one and not 'id' in two:\n                        raise TypeError('No id in object from the second parameter list:\\n%s' % (two))\n                    if not 'id' in one and not 'id' in two:\n                        raise TypeError('No id in object in either parameter list:\\n%s\\n%s' % (one, two))\n            if not found:\n                listtwo.append(one)\n        return listtwo\n\n    def load_serialized_index(self, path, name=None, branches=None):\n        lindex = {}\n        lindex['branches'] = []\n        lindex['layerItems'] = []\n        lindex['layerBranches'] = []\n        lindex['layerDependencies'] = []\n        lindex['recipes'] = []\n        lindex['machines'] = []\n        lindex['distros'] = []\n        lindex['wrtemplates'] = []\n        lindex['YPCompatibleVersions'] = []\n\n        assert path is not None\n\n        def loadCache(path):\n            logger.debug('Loading json file %s' % path)\n            pindex = json.load(open(path, 'rt', encoding='utf-8'))\n\n            for entry in pindex:\n                if 'apilinks' == entry:\n                    continue\n                if 'CFG' == entry:\n                    # Conflicts don't matter here, just accept it\n                    lindex[entry] = pindex[entry]\n                    continue\n                if entry not in lindex:\n                    lindex[entry] = []\n                try:\n                    lindex[entry] = self.__add_cmp_lists(pindex[entry], lindex[entry])\n                except TypeError as error:\n                    raise TypeError('Merge failed of pindex[%s] and lindex[%s]: %s' % (entry, entry, error))\n\n            logger.debug('...loading json file %s, done.' % path)\n\n        if os.path.exists(path) and os.path.isdir(path):\n            logger.debug('Loading %s from directory %s...' % (name, path))\n            for (dirpath, dirnames, filenames) in os.walk(path):\n                for filename in filenames:\n                    if not filename.endswith('.json'):\n                        continue\n                    fpath = os.path.join(dirpath, filename)\n                    loadCache(fpath)\n            logger.debug('...loading %s from path %s, done.' % (name, path))\n        elif os.path.exists(path):\n            logger.debug('Loading %s from path %s...' % (name, path))\n            loadCache(path)\n            logger.debug('...loading %s from path %s, done.' % (name, path))\n        else:\n            logger.error(\"Index %s: could not find path %s\" % (name, path))\n            return None\n\n        return lindex\n\n    def load_django_export(self, path, name=None, branches=None):\n        lindex = {}\n        lindex['branches'] = []\n        lindex['layerItems'] = []\n        lindex['layerBranches'] = []\n        lindex['layerDependencies'] = []\n        lindex['recipes'] = []\n        lindex['machines'] = []\n        lindex['distros'] = []\n        lindex['wrtemplates'] = []\n        lindex['YPCompatibleVersions'] = []\n\n        assert path is not None\n\n        def loadDB(path):\n            def constructObject(entry):\n                obj = entry['fields'].copy()\n                obj['id'] = entry['pk']\n                return obj\n\n            pindex = {}\n\n            logger.debug('Loading json file %s' % path)\n            dbindex = json.load(open(path, 'rt', encoding='utf-8'))\n\n            # We discard anything that doesn't start with 'layerindex.'\n            # the other data is adminstrative and stuff we should not mess with\n            for entry in dbindex:\n                if 'model' in entry:\n                    model = entry['model']\n                    if model.startswith('layerindex.'):\n                        if 'branch' == model[11:]:\n                            name = 'branches'\n                        elif 'layeritem' == model[11:]:\n                            name = 'layerItems'\n                        elif 'layerbranch' == model[11:]:\n                            name = 'layerBranches'\n                        elif 'layerdependency' == model[11:]:\n                            name = 'layerDependencies'\n                        elif 'recipe' == model[11:]:\n                            name = 'recipes'\n                        elif 'machine' == model[11:]:\n                            name = 'machines'\n                        elif 'distro' == model[11:]:\n                            name = 'distros'\n                        elif 'wrtemplate' == model[11:]:\n                            name = 'wrtemplates'\n                        elif 'ypcompatibleversion' == model[11:]:\n                            name = 'YPCompatibleVersions'\n                        else:\n                            name = model[11:]\n\n                        if name not in pindex:\n                            pindex[name] = []\n                        pindex[name].append(constructObject(entry))\n\n            for entry in pindex:\n                if entry not in lindex:\n                    lindex[entry] = []\n                try:\n                    lindex[entry] = self.__add_cmp_lists(pindex[entry], lindex[entry])\n                except TypeError as error:\n                    raise TypeError('Merge failed of pindex[%s] and lindex[%s]: %s' % (entry, entry, error))\n\n            logger.debug('...loading json file %s, done.' % path)\n\n        if os.path.exists(path) and os.path.isdir(path):\n            logger.debug('Loading %s from path %s...' % (name, path))\n            for (dirpath, dirnames, filenames) in os.walk(path):\n                for filename in filenames:\n                    if not filename.endswith('.json'):\n                        continue\n                    fpath = os.path.join(dirpath, filename)\n                    loadDB(fpath)\n            logger.debug('...loading %s from path %s, done.' % (name, path))\n        elif os.path.exists(path):\n            logger.debug('Loading %s from path %s...' % (name, path))\n            loadDB(path)\n            logger.debug('...loading %s from path %s, done.' % (name, path))\n        else:\n            logger.error(\"Index %s: could not find path %s\" % (name, path))\n            return None\n\n        return lindex\n\n    # Provide a function to sort layer index content (restapi format)\n    # When serializing the data this is import to limit\n    # changes to the files...\n    def sortEntry(self, item):\n        newitem = item\n        try:\n            if type(newitem) == type(dict()):\n                newitem = OrderedDict(sorted(newitem.items(), key=lambda t: t[0]))\n            elif type(newitem) == type(list()):\n                newitem.sort(key=lambda obj: obj['id'])\n                for index, entry in enumerate(newitem):\n                    newitem[index] = self.sortEntry(newitem[index])\n        except:\n            pass\n\n        return newitem\n\n    # Sort and return a new restapi style index\n    def sortRestApi(self, index):\n        lindex = self.sortEntry(index)\n        for entry in lindex:\n            lindex[entry] = self.sortEntry(lindex[entry])\n        return lindex\n\n    # layerBranches must be a list of layerBranch entries to parse, it only affects\n    # output when 'split' is True.\n    def serialize_index(self, lindex, path, split=False, layerBranches=None, IncludeCFG=False, mirror=False, base_url=None):\n        # If we're not splitting, we must be caching...\n        if not split:\n            dir = os.path.dirname(path)\n            base = os.path.basename(path)\n            fname = base.translate(str.maketrans('/ ', '__'))\n            fpath = os.path.join(dir, fname)\n\n            # Need to filter out local information\n            pindex = {}\n            for entry in lindex:\n                if (IncludeCFG == False and 'CFG' == entry) or 'apilinks' == entry:\n                    continue\n                pindex[entry] = lindex[entry]\n\n            json.dump(self.sortRestApi(pindex), open(fpath + '.json', 'wt'), indent=4)\n            return\n\n        # We serialize based on the layerBranches, this allows us to subset\n        # everything in a logical way...\n        if not layerBranches:\n            layerBranches = lindex['layerBranches']\n        for lb in layerBranches:\n            pindex = {}\n\n            def filter_item(lb, objects):\n                filtered = []\n                for obj in lindex[objects]:\n                    if 'layerbranch' in obj:\n                        if obj['layerbranch'] == lb['id']:\n                            filtered.append(obj)\n                    elif 'layer' in obj:\n                        for layer in self.find_layer(lindex, layerBranch=lb):\n                            if  obj['layer'] == layer['id']:\n                                filtered.append(obj)\n                    else:\n                        # No simple filter method, just include it...\n                        filtered.append(obj)\n                return filtered\n\n            for entry in lindex:\n                if (IncludeCFG == False and 'CFG' == entry) or 'apilinks' == entry or 'branches' == entry or 'layerBranches' == entry or 'layerItems' == entry:\n                    continue\n                elif (IncludeCFG == True and 'CFG' == entry):\n                    pindex[entry] = lindex[entry]\n                    continue\n                pindex[entry] = filter_item(lb, entry)\n\n            for branch in lindex['branches']:\n                if branch['id'] == lb['branch']:\n                    pindex['branches'] = [branch]\n\n            # We must include the layerbranch for what we are processing...\n            pindex['layerBranches'] = [lb]\n\n            # We also need to include the layerbranch for any required dependencies...\n            (required, recommended) = self.getDependencies(lindex, lb)\n            for req_lb in required:\n                found = False\n                for p_lb in pindex['layerBranches']:\n                    if p_lb['id'] == req_lb['id']:\n                        found = True\n                        break\n                if found == False:\n                    pindex['layerBranches'].append(req_lb)\n\n            # We need to include the layerItems for each layerBranch\n            pindex['layerItems'] = []\n            for p_lb in pindex['layerBranches']:\n                for li in self.find_layer(lindex, layerBranch=p_lb):\n                    found = False\n                    for p_li in pindex['layerItems']:\n                        if p_li['id'] == li['id']:\n                            found = True\n                            break\n                    if found == False:\n                        pindex['layerItems'].append(li)\n\n            # If we're mirroring, we need to adjust the URL for the\n            # mirror to work properly.  Replace remote with BASE_URL.\n            # (This uses the same logic as the default.xml construction)\n            if mirror == True:\n                from urllib.parse import urlparse\n\n                from copy import deepcopy\n                pindex['layerItems'] = deepcopy(pindex['layerItems'])\n                for layer in pindex['layerItems']:\n                    vcs_url = layer['vcs_url']\n\n                    if base_url and vcs_url.startswith(base_url):\n                        layer['vcs_url'] = layer['vcs_url'].replace(base_url, '#BASE_URL#')\n                    else:\n                        url = urlparse(vcs_url)\n\n                        if url.scheme:\n                            layer['vcs_url'] = layer['vcs_url'].replace(url.scheme + '://' + url.netloc, '#BASE_URL#')\n\n            dir = os.path.dirname(path)\n            base = os.path.basename(path)\n            fname = base + '__' + pindex['branches'][0]['name'] + '__' + pindex['layerItems'][0]['name']\n            fname = fname.translate(str.maketrans('/ ', '__'))\n            fpath = os.path.join(dir, fname)\n\n            json.dump(self.sortRestApi(pindex), open(fpath + '.json', 'wt'), indent=4)\n\n    # layerBranches must be a list of layerBranch entries to parse, it only affects\n    # output when 'split' is True.\n    def serialize_django_export(self, lindex, path, split=False, layerBranches=None, IncludeCFG=False):\n        def convertToDjango(restindex):\n            dbindex = []\n\n            def constructObject(entry, model):\n                obj = OrderedDict()\n                obj['pk'] = entry['id']\n                obj['model'] = model\n                obj['fields'] = OrderedDict(sorted(entry.items(), key=lambda t: t[0]))\n                del obj['fields']['id']\n\n                if model == 'layerindex.branch' and 'update_environment' in obj['fields']:\n                    if 'pythonenvironment' not in restindex:\n                        # We have 'lost' the environment, so workaround it being missing...\n                        obj['fields']['update_environment'] = None\n\n                return obj\n\n            # Convert the restindex to a dbindex\n            for entry in restindex:\n                if (IncludeCFG == False and 'CFG' == entry) or 'apilinks' == entry:\n                    continue\n                elif 'branches' == entry:\n                    model = 'layerindex.branch'\n                elif 'layerItems' == entry:\n                    model = 'layerindex.layeritem'\n                elif 'layerBranches' == entry:\n                    model = 'layerindex.layerbranch'\n                elif 'layerDependencies' == entry:\n                    model = 'layerindex.layerdependency'\n                elif 'recipes' == entry:\n                    model = 'layerindex.recipe'\n                elif 'machines' == entry:\n                    model = 'layerindex.machine'\n                elif 'distros' == entry:\n                    model = 'layerindex.distro'\n                elif 'wrtemplates' == entry:\n                    model = 'layerindex.wrtemplate'\n                else:\n                    model = 'layerindex.' + entry\n\n                for item in restindex[entry]:\n                    dbindex.append(constructObject(item, model))\n\n            return dbindex\n\n        # Just write out a single master file..\n        if not split:\n            dir = os.path.dirname(path)\n            base = os.path.basename(path)\n            fname = base.translate(str.maketrans('/ ', '__'))\n            fpath = os.path.join(dir, fname)\n\n            # Need to filter out local information\n            pindex = {}\n            for entry in lindex:\n                if (IncludeCFG == False and 'CFG' == entry) or 'apilinks' == entry:\n                    continue\n                pindex[entry] = lindex[entry]\n\n            json.dump(convertToDjango(self.sortRestApi(pindex)), open(fpath + '.json', 'wt'), indent=4)\n            return\n\n        # We serialize based on the layerBranches, this allows us to subset\n        # everything in a logical way...\n        if not layerBranches:\n            layerBranches = lindex['layerBranches']\n        for lb in layerBranches:\n            pindex = {}\n\n            def filter_item(lb, objects):\n                filtered = []\n                for obj in lindex[objects]:\n                    if 'layerbranch' in obj:\n                        if obj['layerbranch'] == lb['id']:\n                            filtered.append(obj)\n                    elif 'layer' in obj:\n                        for layer in self.find_layer(lindex, layerBranch=lb):\n                            if obj['layer'] == layer['id']:\n                                filtered.append(obj)\n                    else:\n                        # No simple filter method, just include it...\n                        filtered.append(obj)\n                return filtered\n\n            for entry in lindex:\n                if (IncludeCFG == False and 'CFG' == entry) or 'apilinks' == entry or 'branches' == entry or 'layerBranches' == entry or 'layerItems' == entry:\n                    continue\n                pindex[entry] = filter_item(lb, entry)\n\n            pindex['layerBranches'] = [lb]\n            pindex['layerItems'] = self.find_layer(lindex, layerBranch=lb)\n\n            for branch in lindex['branches']:\n                if branch['id'] == lb['branch']:\n                    pindex['branches'] = [branch]\n\n            dir = os.path.dirname(path)\n            base = os.path.basename(path)\n            fname = base + '__' + pindex['branches'][0]['name'] + '__' + pindex['layerItems'][0]['name']\n            fname = fname.translate(str.maketrans('/ ', '__'))\n            fpath = os.path.join(dir, fname)\n\n            json.dump(convertToDjango(self.sortRestApi(pindex)), open(fpath + '.json', 'wt'), indent=4)\n\n    def print_close_matches(self, key, value, full_list):\n        msg = '%s \"%s\" not found' % (key, value)\n        close_matches = difflib.get_close_matches(value, full_list)\n        if close_matches:\n            msg += \". Close matches:\\n  %s\" % '\\n  '.join(list(set(close_matches)))\n        logger.critical(msg + '\\n')\n\n    def find_layer(self, lindex, id=None, name=None, layerBranch=None, layerBranchId=None, distro=None, machine=None, recipe=None, wrtemplate=None):\n        result = []\n\n        if layerBranch:\n            id = layerBranch['layer']\n\n        # Only one layerItem per lindex, so break once we find it\n        if id:\n            for layer in lindex['layerItems']:\n                if layer['id'] == id:\n                    result.append(layer)\n                    if layerBranch:\n                        result[-1]['collection'] = layerBranch['collection']\n                    else:\n                        for branch in lindex['layerBranches']:\n                            if branch['layer'] == id:\n                                result[-1]['collection'] = branch['collection']\n                                break\n                    break\n            return result\n\n        if name:\n            full_list = []\n            found = False\n            for layer in lindex['layerItems']:\n                value_from_index = layer['name']\n                full_list.append(value_from_index)\n                if value_from_index == name:\n                    result.append(layer)\n                    for branch in lindex['layerBranches']:\n                        if branch['layer'] == layer['id']:\n                            result[-1]['collection'] = branch['collection']\n                            break\n                    found = True\n                    break\n            if not found:\n                self.print_close_matches('layer', name, full_list)\n            return result\n\n        layerBranchIds = []\n        if layerBranchId:\n            layerBranchIds.append(layerBranchId)\n\n        args = {\n            'distros': distro,\n            'machines': machine,\n            'recipes': recipe,\n            'wrtemplates': wrtemplate\n        }\n\n        for k, v in args.items():\n            if v:\n                full_list = []\n                found = False\n                for index_dict in lindex[k]:\n                    if k == 'recipes':\n                        value_from_index = index_dict['pn']\n                    else:\n                        value_from_index = index_dict['name']\n                    full_list.append(value_from_index)\n                    if value_from_index == v:\n                        found = True\n                        layerBranchIds.append(index_dict['layerbranch'])\n                if not found:\n                    self.print_close_matches(k.rstrip('s'), v, full_list)\n\n        if layerBranchIds:\n            for layerBranch in lindex['layerBranches']:\n                for layerBranchId in layerBranchIds:\n                    if layerBranch['id'] == layerBranchId:\n                        for layer in lindex['layerItems']:\n                            if layer['id'] == layerBranch['layer']:\n                                result.append(layer)\n                                result[-1]['collection'] = layerBranch['collection']\n            return result\n\n        return None\n\n    def get_index_layers(self, base_branch):\n        index_layers = {}\n        for lindex in self.index:\n            index = lindex['CFG']['DESCRIPTION'] or lindex['CFG']['URL']\n            index_layers[index] = []\n            branchid = self.getBranchId(lindex, self.getIndexBranch(default=base_branch, lindex=lindex))\n            if branchid:\n                for lb in lindex['layerBranches']:\n                    if lb['branch'] == branchid:\n                        index_layers[index].extend(self.find_layer(lindex, layerBranch=lb))\n\n        return index_layers\n\n    def list_layers(self, base_branch):\n        index_layers = self.get_index_layers(base_branch)\n        for index, layers in index_layers.items():\n            logger.plain ('Index: %s' % index)\n\n            table = tt.Texttable()\n            table.set_deco(tt.Texttable.HEADER)\n            table.set_header_align(['l', 'l'])\n            table.set_cols_align(['l', 'l'])\n            table.header(['layer', 'summary'])\n            table.set_cols_dtype(['t', 't'])\n            for layer in layers:\n                name = layer['name']\n                summary = layer['summary'] or name\n                table.add_row([name, summary])\n            s = table.draw()\n            logger.plain (s)\n            logger.plain ('')\n\n    def getYPCompatibleVersion(self, lindex, id):\n        if not id:\n            return []\n        for vers in lindex['YPCompatibleVersions']:\n            if vers['id'] == id:\n                return vers['name'].split()\n        return []\n\n    def list_obj(self, base_branch, object, display, compat='all'):\n        for lindex in self.index:\n            logger.plain ('Index: %s' % (lindex['CFG']['DESCRIPTION'] or lindex['CFG']['URL']))\n\n            table = tt.Texttable()\n            table.set_deco(tt.Texttable.HEADER)\n            table.set_header_align(['l', 'l', 'l'])\n            table.set_cols_align(['l', 'l', 'l'])\n            table.header(['display', 'description', 'layer'])\n            table.set_cols_dtype(['t', 't', 't'])\n            table.set_max_width(100)\n            branchid = self.getBranchId(lindex, self.getIndexBranch(default=base_branch, lindex=lindex))\n            if branchid:\n                # there are more layerBranches then objects (usually)...\n                for lb in lindex['layerBranches']:\n                    if compat != 'all':\n                        if compat not in self.getYPCompatibleVersion(lindex, lb['yp_compatible_version']):\n                            continue\n                    for layer in self.find_layer(lindex, layerBranch=lb):\n                        for obj in lindex[object]:\n                            if obj['layerbranch'] == lb['id'] and lb['branch'] == branchid:\n                                lname = layer['name']\n                                name = obj['name']\n                                description = (obj['description'] or name).strip()\n                                table.add_row([name, description, lname])\n                s = table.draw()\n                logger.plain(s)\n            logger.plain ('')\n\n    def get_machines(self, base_branch, compat='all'):\n        machines = []\n        for lindex in self.index:\n            branchid = self.getBranchId(lindex, self.getIndexBranch(default=base_branch, lindex=lindex))\n            if branchid:\n                for lb in lindex['layerBranches']:\n                    if compat != 'all':\n                        if compat not in self.getYPCompatibleVersion(lindex, lb['yp_compatible_version']):\n                            continue\n                    for layer in self.find_layer(lindex, layerBranch=lb):\n                        for obj in lindex['machines']:\n                            if obj['layerbranch'] == lb['id'] and lb['branch'] == branchid:\n                                machines.append(obj['name'])\n        return machines\n\n\n    def list_distros(self, base_branch, compat):\n        self.list_obj(base_branch, 'distros', 'distro', compat)\n\n    def list_machines(self, base_branch, compat):\n        self.list_obj(base_branch, 'machines', 'machine', compat)\n\n    def list_wrtemplates(self, base_branch, compat):\n        self.list_obj(base_branch, 'wrtemplates', 'templates', compat)\n\n    def list_recipes(self, base_branch):\n        for lindex in self.index:\n            logger.plain ('Index: %s' % (lindex['CFG']['DESCRIPTION'] or lindex['CFG']['URL']))\n            logger.plain ('%s %s %s' % (('{:15}'.format('recipe'), '{:9}'.format('version'), 'summary')))\n            logger.plain ('{:-^80}'.format(\"\"))\n            branchid = self.getBranchId(lindex, self.getIndexBranch(default=base_branch, lindex=lindex))\n            if branchid:\n                # there are more layerBranches then objects (usually)...\n                for lb in lindex['layerBranches']:\n                    for layer in self.find_layer(lindex, layerBranch=lb):\n                        for obj in lindex['recipes']:\n                            if obj['layerbranch'] == lb['id'] and lb['branch'] == branchid:\n                                lname = layer['name']\n                                pn = obj['pn']\n                                pv = obj['pv']\n                                summary = (obj['summary'] or pn).strip()\n                                logger.plain('%s %s %s' % ('{:15}'.format(pn), '{:9}'.format(pv), summary[:50]))\n            logger.plain ('')\n\n    def getBranchId(self, lindex, name):\n        for branch in lindex['branches']:\n            if branch['name'] == name:\n                return branch['id']\n        return None\n\n    def getLayerBranch(self, lindex, branchid, layerBranchId=None, collection=None, name=None, distro=None, machine=None, recipe=None, wrtemplate=None, layerItem=None):\n        result = []\n        if layerBranchId:\n            for lb in lindex['layerBranches']:\n                if branchid == lb['branch'] and layerBranchId == lb['id']:\n                    result.append(lb)\n                    break\n            return result\n\n        if collection:\n            for lb in lindex['layerBranches']:\n                if 'collection' in lb and collection == lb['collection']:\n                    result.append(lb)\n                    break\n            return result\n\n        layerItems = []\n        if layerItem:\n            layerItems.append(layerItem)\n\n        args = {\n            'name': name,\n            'distro': distro,\n            'machine': machine,\n            'recipe': recipe,\n            'wrtemplate': wrtemplate\n        }\n        for k, v in args.items():\n            if v:\n                if k == 'name':\n                    layerItem = self.find_layer(lindex, name=v)\n                elif k == 'distro':\n                    layerItem = self.find_layer(lindex, distro=v)\n                elif k == 'machine':\n                    layerItem = self.find_layer(lindex, machine=v)\n                elif k == 'recipe':\n                    layerItem = self.find_layer(lindex, recipe=v)\n                elif k == 'wrtemplate':\n                    layerItem = self.find_layer(lindex, wrtemplate=v)\n                if layerItem:\n                    layerItems = layerItems + layerItem\n\n        if layerItems:\n            for layerItem in layerItems:\n                for lb in lindex['layerBranches']:\n                    if branchid == lb['branch'] and layerItem['id'] == lb['layer']:\n                        result.append(lb)\n            return result\n\n        return None\n\n    def getDependencies(self, lindex, layerBranch):\n        required = []\n        recommended = []\n        for ld in lindex['layerDependencies']:\n            if layerBranch['id'] == ld['layerbranch']:\n                layers = self.find_layer(lindex, id=ld['dependency'])\n                if (not layers or layers == []) and ld['required'] == True:\n                    logger.warning('%s: Unable to find dependency %s -- Skipping' % (self.find_layer(lindex, layerBranch=layerBranch)[0]['name'], ld['dependency']))\n                for layer in layers:\n                    for lb in self.getLayerBranch(lindex, layerBranch['branch'], layerItem=layer):\n                        if not lb:\n                            continue\n                        if not 'required' in ld or ld['required'] == True:\n                            #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']) )\n                            required.append(lb)\n                        else:\n                            #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']) )\n                            recommended.append(lb)\n\n        return (required, recommended)\n\n    def getLayerInfo(self, lindex, layerBranch):\n        collection = None\n        name = None\n        vcs_url = None\n        if 'collection' in layerBranch:\n            collection = layerBranch['collection']\n        for layer in self.find_layer(lindex, layerBranch=layerBranch):\n            if layer:\n                name = layer['name']\n                vcs_url = layer['vcs_url']\n                break\n\n        return (collection, name, vcs_url)\n\n    def getBranch(self, lindex, branchid):\n        for branch in lindex['branches']:\n            if branch['id'] == branchid:\n                return branch\n        return None\n\n    def getBitbakeBranch(self, lindex, branchid):\n        branch = self.getBranch(lindex, branchid)\n        if branch:\n            return branch['bitbake_branch'] or branch['name']\n        return None\n\n    def getIndexBranch(self, default=None, lindex=None):\n        if lindex and 'CFG' in lindex and 'BRANCH' in lindex['CFG']:\n            return lindex['CFG']['BRANCH']\n        return default\n"
  },
  {
    "path": "bin/logger_setup.py",
    "content": "# Copyright (C) 2016 Wind River Systems, Inc.\n#\n# This program is free software; you can redistribute it and/or modify\n# it under the terms of the GNU General Public License version 2 as\n# published by the Free Software Foundation.\n#\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n# See the GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program; if not, write to the Free Software\n# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n#\n\"\"\"\nlogger_setup is the infrastructure for setup.py to log both to the screen and\nto a file.  Up on initialisation, the logger will only log to the screen and\nhave two new log levels:\n        plain = 15\n        to_file = 1\n\nplain logs will not be prefixed with the logging type when outputting to the\noutput passed to the setup_logging function (which defaults to sys.stdout).\n\"\"\"\nimport logging\nimport sys\nimport time\n\nFILE_LOG_FORMAT = '%(asctime)s %(levelname)8s [%(filename)s:%(lineno)s' \\\n                + ' - %(funcName)20s(): %(message)s'\n\n# INFO = 20\nPLAIN_LOG_LEVEL = 15\n# DEBUG = 10\nTO_FILE_LOG_LEVEL = 1\n# NOTSET = 0\n\nlogger = None\n\ndef plain(self, message, *args, **kws):\n    \"\"\"Function to be added to the logger for plain log level support\"\"\"\n\n    if self.isEnabledFor(PLAIN_LOG_LEVEL):\n        self._log(PLAIN_LOG_LEVEL, message, args, **kws)\n\ndef to_file(self, message, *args, **kws):\n    \"\"\"Function to be added to the logger for to_file log level support\"\"\"\n    if self.isEnabledFor(TO_FILE_LOG_LEVEL):\n        self._log(TO_FILE_LOG_LEVEL, message, args, **kws)\n\n\ndef setup_logging(level=PLAIN_LOG_LEVEL, output=sys.stdout):\n    \"\"\"create the setup.py singleton logger.\"\"\"\n    global logger\n    if logger:\n        return logger\n\n    logger = logging.getLogger('setup.py')\n\n    formatter = ScreenFormatter(\"%(levelname)s: %(message)s\")\n    stream_h = logging.StreamHandler(output)\n    stream_h.setFormatter(formatter)\n\n    # Logging timezone is UTC\n    stream_h.converter = time.gmtime\n\n    logger.setLevel(level)\n    logger.addHandler(stream_h)\n\n    logging.addLevelName(PLAIN_LOG_LEVEL, \"PLAIN\")\n    logging.Logger.plain = plain\n\n    return logger\n\nclass FileFormatter(logging.Formatter):\n    def format(self, record):\n        # FileHandler doesn't need color\n        record.levelname = record.levelname_orig\n        return logging.Formatter.format(self, record)\n\ndef setup_logging_file(log_file):\n    \"\"\"Add a logging.FileHandler to the logger\"\"\"\n    global logger\n    logger.debug(\"Logging to %s\" % log_file)\n    formatter = FileFormatter(FILE_LOG_FORMAT)\n    file_h = logging.FileHandler(log_file)\n    # Logging timezone is UTC\n    file_h.converter = time.gmtime\n    file_h.setFormatter(formatter)\n    file_h.setLevel(TO_FILE_LOG_LEVEL)\n    logger.addHandler(file_h)\n    logging.addLevelName(TO_FILE_LOG_LEVEL, 'TO_FILE')\n    logging.Logger.to_file = to_file\n\n\n\nclass ScreenFormatter(logging.Formatter):\n    \"\"\"ScreenFormatter exists to allow printing plain messages with a different\n    format than other log levels.\n    \"\"\"\n\n    RED, GREEN, YELLOW, BLUE = [1, 2, 3, 4]\n\n    RESET_SEQ = \"\\033[0m\"\n    COLOR_SEQ = \"\\033[1;%dm\"\n\n    COLORS = {\n        'INFO': GREEN,\n        'DEBUG': BLUE,\n        'WARNING': YELLOW,\n        'ERROR': RED,\n        'CRITICAL': RED\n    }\n\n    def format(self, record):\n        levelname = record.levelname\n        # Save it for FileHandler\n        record.levelname_orig = levelname\n        if levelname == \"PLAIN\":\n            msg = record.getMessage()\n        else:\n            if sys.stdout.isatty():\n                fore_color = 30 + self.COLORS[levelname]\n                levelname_color = self.COLOR_SEQ % fore_color + levelname + self.RESET_SEQ\n                record.levelname = levelname_color\n                msg = logging.Formatter.format(self, record)\n            msg = logging.Formatter.format(self, record)\n        return msg\n\n# Add a class to emulate stdout/stderr\nclass LoggerOut:\n    def __init__(self, logger, isatty):\n        self.logger = logger\n        self.tty = isatty\n\n    def write(self, message):\n        # We skip any lines that are simply a '\\n'.\n        # The logger always ends in the equivalent of a \\n, and many programs\n        # seem to like to insert blank lines using '\\n' which makes the\n        # logging confusing.\n        if message != '\\n':\n            self.logger(message)\n\n    def flush(self):\n        # We print all messages immediately, so flush is a no-op.\n        pass\n\n    def isatty(self):\n        return self.tty\n"
  },
  {
    "path": "bin/sanity.py",
    "content": "#!/usr/bin/env python3\n\n# Copyright (C) 2019 Wind River Systems, Inc.\n#\n# This program is free software; you can redistribute it and/or modify\n# it under the terms of the GNU General Public License version 2 as\n# published by the Free Software Foundation.\n#\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n# See the GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program; if not, write to the Free Software\n# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n\n# Please keep these sorted.\n\"\"\"\nsanity.py module to help setup program to do sanity checks.\n\"\"\"\n\nimport os\nimport sys\nimport logger_setup\nlogger = logger_setup.setup_logging()\n\n# Fixed list of tools needed.\nfixed_hosttools = \"\"\"\n [ ar as awk basename bash bzip2 cat chgrp chmod chown chrpath\n cmp comm cp cpio cpp cut date dd diff diffstat dirname du echo\n egrep env expand expr false fgrep file find flock g++ gawk gcc\n getconf getopt git grep gunzip gzip head hostname iconv id install\n ld ldd ln ls make makeinfo md5sum mkdir mknod mktemp mv nm objcopy\n objdump od patch perl pod2man pr printf pwd python2 python2.7\n python3 ranlib readelf readlink realpath rm rmdir rpcgen sed\n seq sh sha256sum sleep sort split stat strings strip tail tar tee\n test touch tr true uname uniq wc wget which xargs\n\"\"\"\n\ndef which(path, item, direction = 0, executable=False):\n    \"\"\"\n    Locate `item` in the list of paths `path` (colon separated string like $PATH).\n    If `direction` is non-zero then the list is reversed.\n    If `executable` is True then the candidate has to be an executable file,\n    otherwise the candidate simply has to exist.\n    \"\"\"\n\n    if executable:\n        is_candidate = lambda p: os.path.isfile(p) and os.access(p, os.X_OK)\n    else:\n        is_candidate = lambda p: os.path.exists(p)\n\n    paths = (path or \"\").split(':')\n    if direction != 0:\n        paths.reverse()\n\n    for p in paths:\n        next = os.path.join(p, item)\n        if is_candidate(next):\n            if not os.path.isabs(next):\n                next = os.path.abspath(next)\n            return next\n\n    return \"\"\n\ndef check_hosttools(additions = None):\n    \"\"\"\n    Check tools on host. Error out if some tool is missing. \n    \"\"\"\n    host_tools = []\n    notfound = []\n\n    try:\n        import settings\n        host_tools = settings.REQUIRED_HOSTTOOLS.split()\n        if additions:\n            for tool in additions:\n                if tool not in host_tools:\n                    host_tools.append(tool)\n    except Exception as e:\n        logger.warn(\"Failed to get host tools from setting.py: %s\" % e)\n        logger.warn(\"Use a fixed list of host tools for checking.\")\n        host_tools = []\n    \n    if not host_tools:\n        # Fall back to a fixed list of host tools\n        host_tools = fixed_hosttools.split()\n\n    path = os.environ['PATH']\n    for tool in host_tools:\n        srctool = which(path, tool, executable=True)\n        # gcc/g++ may link to ccache on some hosts, e.g.,\n        # /usr/local/bin/ccache/gcc -> /usr/bin/ccache, then which(gcc)\n        # would return /usr/local/bin/ccache/gcc, but what we need is\n        # /usr/bin/gcc, this code can check and fix that.\n        if \"ccache\" in srctool:\n            srctool = which(path, tool, executable=True, direction=1)\n        if not srctool:\n            notfound.append(tool)\n    if notfound:\n        logger.error(\"Required host tools not available: %s\" % notfound)\n        sys.exit(1)\n    else:\n        logger.info(\"All required host tools are available.\")\n\n# allow running sanity checks individually\nif __name__ == '__main__':\n    sys.exit(check_hosttools(sys.argv[1:]))\n"
  },
  {
    "path": "bin/settings.py",
    "content": "# Settings for the installer\n\n# type:  restapi-web   - REST API from a LayerIndex-web\n#        restapi-files - REST API, but only from files\n#        export        - Exported DB from a LayerIndex-web -- reads file(s)\n\n# url/path may contain:\n#  #INSTALL_DIR# which is replaced by the setup directory\n#  #BASE_URL# which is replaced by the base url for setup directory\n#  #BASE_BRANCH# which is replaced by the base branch for the setup directory\n\n# Since we know the url below will be mirrored to our\n# internal git mirrors, change format so it can be replaced\n# with the proper value(s)\nREPLACE = [\n    ( 'git://lxgit.wrs.com', '#BASE_URL#' )\n]\n\nINDEXES = [\n    {\n        'DESCRIPTION' : 'Wind River Developer Layer Index',\n        'TYPE' : 'restapi-web',\n        'URL' : 'http://layers.wrs.com/layerindex/api/',\n        'CACHE' : 'config/index-cache/layers_wrs_com',\n    },\n#    {\n#        'DESCRIPTION' : 'OpenEmbedded Layer Index',\n#        'TYPE' : 'restapi-web',\n#        'URL' : 'http://layers.openembedded.org/layerindex/api/',\n#        'CACHE' : 'config/index-cache/layers_openembedded_org',\n#        'BRANCH' : 'morty'\n#    },\n]\n\n# Bitbake URL on the same server at openembedded-core\n# bitbake is assumed to be at the same basepath as OpenEmbedded-Core\nBITBAKE = \"bitbake\"\n\n# Base Layers (these layers and their dependencies are -always- included)\nBASE_LAYERS = \"wrlinux\"\n\nDEFAULT_DISTRO = \"wrlinux\"\nDEFAULT_MACHINE = \"qemux86-64\"\n\n# Default number of repo jobs\nREPO_JOBS = 4\n\n# Repo remote name list\nREMOTES = [\n    ( 'git://git.openembedded.org', 'openembedded' ),\n    ( 'git://git.yoctoproject.org', 'yoctoproject' ),\n    ( 'http://git.yoctoproject.org', 'http_yoctoproject' ),\n    ( 'git://github.com', 'github' ),\n    ( 'https://github.com', 'https_github' ),\n]\n\n# The default tag used to filter the output of --list actions. 'all' means no\n# filter\nDEFAULT_LAYER_COMPAT_TAG = \"wrl\"\n\n# required host tools to build out project\n# Do not edit this manually, it is updated automatically.\nREQUIRED_HOSTTOOLS = \"\"\"\n    [ ar as awk basename bash bzip2 cat chgrp chmod chown chrpath\n    cmp comm cp cpio cpp cut date dd diff diffstat dirname du echo\n    egrep env expand expr false fgrep file find flock g++ gawk gcc\n    getconf getopt git grep gunzip gzip head hostname iconv id install\n    ld ldd ln ls make md5sum mkdir mkfifo mknod mktemp mv nm objcopy\n    objdump od patch perl pr printf pwd python3 ranlib readelf readlink\n    realpath rm rmdir rpcgen sed seq sh sha1sum sha224sum sha256sum\n    sha384sum sha512sum sleep sort split stat strings strip tail tar\n    tee test touch tr true uname uniq wc wget which xargs\n\"\"\"\n"
  },
  {
    "path": "bin/setup.py",
    "content": "#!/usr/bin/env python3\n\n# Copyright (C) 2016 Wind River Systems, Inc.\n#\n# This program is free software; you can redistribute it and/or modify\n# it under the terms of the GNU General Public License version 2 as\n# published by the Free Software Foundation.\n#\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n# See the GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program; if not, write to the Free Software\n# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n\n# Please keep these sorted.\nimport logging\nimport os\nimport shutil\nimport subprocess\nimport sys\nimport time\nimport re\n\nfrom urllib.parse import urlparse\n\nimport utils_setup\n\n# Setup-specific modules\nimport logger_setup\nfrom argparse_wrl import Argparse_Wrl\n\nfrom layer_index import Layer_Index\n\nimport settings\nimport sanity\n\nimport xml.etree.ElementTree as ET\n\nlogger = logger_setup.setup_logging()\n\n# Redirect stdout and stderr to the custom logger.  This allows us to use\n# python modules that may output only via stdout/stderr.\nisatty = sys.stdout.isatty()\nsys.stdout = logger_setup.LoggerOut(logger.info, isatty)\nsys.stderr = logger_setup.LoggerOut(logger.error, isatty)\n\nclass Setup():\n\n    tool_list = ['repo', 'git']\n\n    default_xml = 'default.xml'\n    default_repo_quiet = '--quiet'\n\n    class_config_dir = 'config'\n    class_log_dir = 'log'\n\n    check_repo_install_dir = '.repo/repo/.git'\n    check_repo_sync_file = '.repo/projects/'\n\n    replacement = {}\n\n    BINTOOLS_SSL_DIR=\"/bin/buildtools/sysroots/x86_64-wrlinuxsdk-linux/usr/share/ca-certificates/mozilla\"\n    BINTOOLS_SSL_CERT= \"/bin/buildtools/sysroots/x86_64-wrlinuxsdk-linux/etc/ssl/certs/ca-certificates.crt\"\n\n    def __init__(self):\n        # Set various default values\n        # Default -j for repo init\n        self.jobs = str(settings.REPO_JOBS)\n\n        # Pull in the defaults from the environment (set by setup.sh)\n        self.base_url = os.getenv('OE_BASEURL')\n        self.base_branch = os.getenv('OE_BASEBRANCH')\n        self.buildtools_branch = os.getenv('OE_BUILDTOOLS_BRANCH')\n        self.buildtools_remote = os.getenv('OE_BUILDTOOLS_REMOTE')\n        self.another_buildtools_remote = os.getenv('OE_ANOTHER_BUILDTOOLS_REMOTE')\n\n        # Real project or a mirror?\n        self.mirror = False\n\n        self.mirror_index_path = None\n\n        # Make/Use the project mirror as PREMIRRORS for do_fetch\n        self.mirror_as_premirrors = False\n\n        # Default configuration\n        self.distros = [ settings.DEFAULT_DISTRO ]\n        self.machines = [ settings.DEFAULT_MACHINE ]\n        self.layers = []\n        self.recipes = []\n        self.wrtemplates = []\n\n        self.all_layers = False\n        self.dl_layers = False\n        self.local_layers = []\n        self.remote_layers = []\n\n        # The extra layer groups enabled by user\n        self.use_layer_groups = []\n\n        self.no_recommend = False\n\n        self.no_network = False\n        self.allowed_network = None\n\n        self.remotes = {}\n        self.requiredlayers = []\n        self.recommendedlayers = []\n\n        # Default quiet:\n        self.quiet = self.default_repo_quiet\n        self.repo_verbose = False\n\n        # Default depth\n        self.depth = None\n\n        # Default to NOT force-sync\n        self.force_sync = None\n\n        self.repo_url = None\n        if 'REPO_URL' in os.environ:\n            self.repo_url = os.environ['REPO_URL']\n\n        self.repo_rev = None\n        if 'REPO_REV' in os.environ:\n            self.repo_rev = os.environ['REPO_REV']\n\n        self.debug_lvl = 0\n\n        self.repo_no_fetch = False\n\n        # Set the install_dir\n        # Use the path from this file.  Note bin has to be dropped.\n        self.install_dir = os.path.abspath(os.path.dirname(os.path.abspath(__file__)) + '/../')\n\n        # Default location for the related XML files\n        self.xml_dir = os.path.join(self.install_dir, 'data/xml')\n\n        # Set the directory where we're running.\n        self.project_dir = os.getcwd()\n\n        self.conf_dir = os.path.join(self.project_dir, self.class_config_dir)\n\n        # Save current base_branch to compare with next one\n        self.saved_base_branch = os.path.join(self.conf_dir, 'saved_base_branch')\n\n        # Environment setup\n        self.env = os.environ.copy()\n\n        # We do NOT want to inherit python home from the environment\n        # See Issue: LIN1018-2934\n        #   python3 wrapper from the buildtools sets this, which causes host\n        #   python tools to fail\n        if 'PYTHONHOME' in self.env:\n            del self.env['PYTHONHOME']\n\n        self.setup_env()\n\n        # Config flags\n        self.list_distros = False\n        self.list_machines = None\n        self.list_layers = False\n        self.list_recipes = False\n        self.list_wrtemplates = False\n\n        self.premirrors_dl = os.path.join(self.project_dir, 'premirrors-dl')\n        self.premirrors_dl_downloads = os.path.join(self.premirrors_dl, 'downloads')\n\n    def exit(self, ret=0):\n        logger.debug(\"setup.py finished (ret=%s)\" % (ret))\n        sys.exit(ret)\n\n    def start_file_logging(self):\n        log_dir = os.path.join(self.conf_dir, self.class_log_dir)\n        if not os.path.exists(log_dir):\n            os.makedirs(log_dir)\n\n        log_file = '%s/%s.log' % (log_dir, time.strftime('%Y-%m-%d-%H:%M:%S+0000', time.gmtime()))\n        logger_setup.setup_logging_file(log_file)\n\n    def main(self, orig_args):\n        parser = Argparse_Wrl(self)\n        # We want to default to help mode lacking any args.\n        if not orig_args or not orig_args[1:]:\n            orig_args.append('--help')\n        parser.evaluate_args(orig_args[1:])\n        self.setup_args = \" \".join(orig_args[1:])\n        self.extra_group_keys = parser.extra_group_keys\n\n        self.start_file_logging()\n\n        logger.debug('REPO_URL = %s' % self.repo_url)\n        logger.debug('REPO_BRANCH = %s' % self.repo_rev)\n\n        if not self.base_url:\n            logger.error('Unable to determine base url, you may need to specify --base-url=')\n\n        if not self.base_branch:\n            logger.error('Unable to determine base branch, you may need to specify --base-branch=')\n\n        # Check for require host tools for real project\n        if not self.mirror:\n            sanity.check_hosttools(self.tool_list)\n\n        if not self.base_url or not self.base_branch:\n            self.exit(1)\n\n        # Check for all the tools and create a dictionary of the path\n        # This shouldn't fail, because sanity.check_hosttools already checked for these...\n        self.tools = {i : self.get_path(i) for i in self.tool_list}\n        if None in self.tools.values():\n            sys.exit(1)\n\n        self.load_layer_index()\n\n        if len(self.index.index) == 0:\n            logger.critical('No indexes could be loaded.  This could be due to an invalid branch or tag.  Exiting...')\n            sys.exit(1)\n\n        if self.list_distros:\n            compat = self.list_distros\n            if compat == 'default':\n                compat = settings.DEFAULT_LAYER_COMPAT_TAG\n            self.index.list_distros(self.base_branch, compat)\n\n        if self.list_machines:\n            compat = self.list_machines\n            if compat == 'default':\n                compat = settings.DEFAULT_LAYER_COMPAT_TAG\n            self.index.list_machines(self.base_branch, compat)\n\n        if self.list_layers:\n            self.index.list_layers(self.base_branch)\n\n        if self.list_recipes:\n            self.index.list_recipes(self.base_branch)\n\n        if self.list_wrtemplates:\n            compat = self.list_wrtemplates\n            if compat == 'default':\n                compat = settings.DEFAULT_LAYER_COMPAT_TAG\n            self.index.list_wrtemplates(self.base_branch, compat)\n\n        if self.list_distros or self.list_machines or self.list_layers or self.list_recipes or self.list_wrtemplates:\n            sys.exit(0)\n\n        logger.debug('setup.py started')\n        logger.debug('Calling setup main with arguments %s' % str(orig_args))\n\n        # Log debug which may have been missed due to log level.\n        logger.debug(\"PATH=%s\" % self.env[\"PATH\"])\n\n        # Check saved_base_branch vs current base_branch\n        self.check_base_branch()\n\n        logger.debug(\"Tools are:\")\n        for key in self.tools:\n            logger.debug(\"%s -> %s\" % (key, self.tools[key]))\n\n        logger.plain('Setting distro to \"%s\"' % (\",\".join(self.distros)))\n        logger.plain('Setting machine to \"%s\"' % (\",\".join(self.machines)))\n        if self.layers != []:\n            logger.plain('Setting layers to \"%s\"' % (\",\".join(self.layers)))\n        if self.recipes != []:\n            logger.plain('Setting recipes to \"%s\"' % (\",\".join(self.recipes)))\n        if self.wrtemplates != []:\n            logger.plain('Setting templates to \"%s\"' % (\",\".join(self.wrtemplates)))\n\n        self.process_layers()\n\n        self.project_setup()\n\n        self.__prep_replacements()\n        if self.mirror != True:\n            # We only want to do this if we're not mirroring...\n            self.update_project()\n        else:\n            # Setup an index for others to use if we're mirroring...\n            self.update_mirror()\n            self.update_mirror_index()\n\n        self.update_manifest()\n\n        self.check_default_xml()\n\n        self.update_gitignore()\n\n        self.commit_files()\n\n        self.check_project_path()\n\n        self.repo_sync()\n\n        if self.mirror_as_premirrors:\n            if self.mirror:\n                self.make_mirror_as_premirrors()\n            else:\n                self.use_mirror_as_premirrors()\n\n        self.exit(0)\n\n    def check_project_path(self):\n        self.manifest_dir = os.path.join(self.project_dir, '.repo/manifests.git')\n        project_dir_last = \"\"\n        if os.path.exists(self.manifest_dir):\n            cmd = [self.tools['git'], 'config', '--get', 'remote.origin.url']\n            try:\n                p = subprocess.run(cmd, check=True, cwd=self.manifest_dir, stdout=subprocess.PIPE)\n                project_dir_last = p.stdout.decode('utf-8').strip()\n            except Exception as e:\n                logger.warning('Failed to run \"%s\": %s' % (' '.join(cmd), e))\n\n        logger.debug('last project dir: %s' % project_dir_last)\n        if project_dir_last and project_dir_last != self.project_dir:\n            logger.info('project dir has been changed from %s to %s' % (project_dir_last, self.project_dir))\n            logger.info('Updating config files for new project dir...')\n            cmd = [self.tools['git'], 'config', 'remote.origin.url', self.project_dir]\n            subprocess.run(cmd, cwd=self.manifest_dir)\n\n    def load_mirror_index(self, remote_mirror, folder=\"\"):\n        # See if there is a mirror index available from the BASE_URL\n        mirror_index = os.path.join(self.conf_dir, 'mirror-index')\n        try:\n            cmd = [self.tools['git'], 'ls-remote', remote_mirror, self.base_branch]\n            utils_setup.run_cmd(cmd, log=2, environment=self.env, cwd=self.project_dir, stderr=subprocess.DEVNULL, stdout=subprocess.DEVNULL)\n        except:\n            try:\n                remote_mirror += \"/.git\"\n                cmd = [self.tools['git'], 'ls-remote', remote_mirror, self.base_branch]\n                utils_setup.run_cmd(cmd, log=2, environment=self.env, cwd=self.project_dir, stderr=subprocess.DEVNULL, stdout=subprocess.DEVNULL)\n            except:\n                # No mirror, return\n                return None\n\n        logger.plain('Loading the mirror index from %s (%s)...' % (remote_mirror, self.base_branch))\n        # This MIGHT be a valid mirror..\n        if not os.path.exists(mirror_index):\n            os.makedirs(mirror_index)\n            cmd = [self.tools['git'], 'init' ]\n            utils_setup.run_cmd(cmd, log=2, environment=self.env, cwd=mirror_index)\n\n        try:\n            # We don't know if we're fetching a branch or tag, if it's a tag we have to do this\n            # in two steps anyway, so always go to 'FETCH_HEAD' and then branch it.\n            cmd = [self.tools['git'], 'fetch', '-n', '-u', remote_mirror, self.base_branch]\n            utils_setup.run_cmd(cmd, log=2, environment=self.env, cwd=mirror_index)\n            cmd = [self.tools['git'], 'checkout', '-B', folder + self.base_branch, 'FETCH_HEAD']\n            utils_setup.run_cmd(cmd, log=2, environment=self.env, cwd=mirror_index)\n        except:\n            # Could not fetch, return\n            return None\n\n        logger.debug('Found mirrored index.')\n        cmd = [self.tools['git'], 'checkout', folder + self.base_branch ]\n        utils_setup.run_cmd(cmd, log=2, environment=self.env, cwd=mirror_index)\n        cmd = [self.tools['git'], 'reset', '--hard' ]\n        utils_setup.run_cmd(cmd, log=2, environment=self.env, cwd=mirror_index)\n\n        return mirror_index\n\n    def check_base_branch(self):\n        logger.debug('Checking saved_base_branch vs current base_branch')\n\n        sync_file = os.path.join(self.project_dir, self.check_repo_sync_file)\n        if not os.path.exists(sync_file):\n            logger.debug(\"Skip the check since %s doesn't exist\" % sync_file)\n            return\n\n        if not os.path.exists(self.saved_base_branch):\n            logger.debug(\"Skip the check since %s doesn't exist\" % self.saved_base_branch)\n            return\n\n        with open(self.saved_base_branch, 'r') as f:\n            saved_base_branch = f.read().rstrip('\\n')\n        if saved_base_branch == self.base_branch:\n            logger.debug('saved_base_branch and current base_branch are the same')\n            return\n\n        repo = self.tools['repo']\n        cmd = [repo, 'status']\n        with subprocess.Popen(cmd, stdout=subprocess.PIPE, env=self.env, cwd=self.project_dir) as proc:\n            output = proc.stdout.read().decode('utf-8')\n            if re.search('^project\\s+layers/.*\\s+branch', output, flags=re.M):\n                logger.error(\"Found checked out branches, here is the output from 'repo status':\\n%s\" % output)\n                logger.error('Switching base branch with checked out projects is not allowed,')\n                logger.error('but you are switching from \"%s\" to \"%s\".'% (saved_base_branch, self.base_branch))\n                logger.error('Consider using either of the following ways to fix the problem:')\n                logger.error('- Run \"git checkout m/master\" in the projects')\n                logger.error('- Use \"repo abandon [--all | <branchname>] [<project>...]\" to abandon the branch\\n')\n                self.exit(1)\n\n    def load_layer_index(self):\n        # Load Layer_Index\n\n        if not (self.base_branch == \"master\" or self.base_branch == \"master-wr\"):\n            from windshare import Windshare\n            ws = Windshare(debug=self.debug_lvl)\n\n            # Determine if this is a windshare install\n            (ws_base_url, ws_base_folder, ws_entitlement_url) = ws.get_windshare_urls(self.base_url)\n            if ws_base_url and ws_base_url != \"\" and ws.load_folders(ws_entitlement_url):\n                logger.plain('Detected Windshare configuration.  Processing entitlements and indexes.')\n\n                for folder in ws.folders:\n                    self.mirror_index_path = ws.load_mirror_index(self, ws_base_url, folder)\n\n                ws.write_local_mirror_index(self, self.mirror_index_path)\n\n                # We need to adjust the base_url so everything works properly...\n                self.base_url = ws_base_url\n\n                # Adjust the location of the buildtools (was based on the original base_url)\n                if self.buildtools_remote:\n                    self.buildtools_remote = ws_base_folder + '/' + self.buildtools_remote\n                if self.another_buildtools_remote:\n                    self.another_buildtools_remote = ws_base_folder + '/' + self.another_buildtools_remote\n            else:\n                logger.debug('No Windshare configuration detected.')\n        else:\n            logger.debug('Windshare configuration disabled, building %s.' % self.base_branch)\n\n        # Check if we have a mirror-index, and load it if we do...\n        if not self.mirror_index_path:\n            self.mirror_index_path = self.load_mirror_index(self.base_url + '/mirror-index')\n\n            # Is this a tag? if so... we only pull from mirror-indexes\n            if not self.mirror_index_path and self.base_branch.startswith('refs/tags/'):\n                logger.error(\"An install from a repository tag (%s) can only be installed with a corresponding layerindex snapshot.\" % self.base_branch)\n                logger.error(\"Unable to find %s\" % self.base_url + '/mirror-index')\n                sys.exit(1)\n\n        # Mirror also has a copy of the associated XML bits\n        if self.mirror_index_path:\n            self.xml_dir = os.path.join(self.mirror_index_path, 'xml')\n\n        # Setup replace strings as late as possible.  The various self.* values\n        # may be modified prior to this place.\n        replace = []\n        replace = replace + settings.REPLACE\n        replace = replace + [\n                   ( '#INSTALL_DIR#', self.install_dir ),\n                   ( '#BASE_URL#', self.base_url ),\n                   ( '#BASE_BRANCH#', self.base_branch ),\n                  ]\n\n        self.index = Layer_Index(indexcfg=settings.INDEXES, base_branch=self.base_branch, replace=replace, mirror=self.mirror_index_path)\n\n        # Is this a Wind River tag? if so... we need to modify the 'branches' entries to be the same as the tag\n        if self.base_branch.startswith('refs/tags/vWRLINUX'):\n            if '_RCPL' in self.base_branch or '_UPDATE' in self.base_branch:\n                # vWRLINUX_<something>_UPDATExxxx\n                # vWRLINUX_<something>_RCPLxxxx\n                new_base_branch = self.base_branch[11:]\n            else:\n                # vWRLINUX_<something>_10.19.25.0\n                new_base_branch_pos = self.base_branch.find('10.')\n                new_base_branch = self.base_branch[:(new_base_branch_pos-1)][11:]\n\n            logger.debug('Detected a WR tag, replacing %s with %s...' % (self.base_branch[11:], new_base_branch))\n            for lindex in self.index.index:\n                for branch in lindex['branches']:\n                    if branch and branch['bitbake_branch'] == new_base_branch:\n                        branch['bitbake_branch'] = self.base_branch\n                    if branch and branch['name'] == new_base_branch:\n                        branch['name'] = self.base_branch\n\n    def is_group_layer(self, layer_name):\n        \"\"\"\n        Is it an extra group layer?\n        \"\"\"\n        for group_key in self.extra_group_keys:\n            if '-%s-' % group_key in layer_name or layer_name.endswith('-%s' % group_key):\n                return True\n\n        return False\n\n    def is_enabled_group(self, layer_name):\n        \"\"\"\n        Is it an extra group layer which is enabled by user?\n        \"\"\"\n        if layer_name in self.layers:\n            return True\n\n        for group_key in self.extra_group_keys:\n            if group_key in self.use_layer_groups:\n                return True\n\n        return False\n\n    def process_layers(self):\n        from collections import deque\n\n        # We allow duplicates in the queue, they're filtered later\n        # Queue of required objects\n        requiredQueue = deque([])\n        # Queue of recommended objects\n        recommendedQueue = deque([])\n\n        logger.debug('Starting')\n        # if this switches to false, we have to exit at the end of this function\n        allfound = True\n\n        # It all starts with BASE_LAYERS, so always include this. (only from index 0)\n        lindex = self.index.index[0]\n        branchid = self.index.getBranchId(lindex, self.get_branch(lindex=lindex))\n        if branchid:\n            for lname in settings.BASE_LAYERS.split():\n                base_layerBranch = self.index.getLayerBranch(lindex, branchid, name=lname)\n\n                if not base_layerBranch or not branchid:\n                    raise Exception('Unable to find base layer: %s in the Layer_Index' % (lname))\n\n                for lb in base_layerBranch:\n                    requiredQueue.append( (lindex, lb) )\n\n        # process the configuration arguments (find the layers we need for the project)\n        # if an item is 'layer:item', then the 'foo' part must match a layer name.\n        def procConfig(layer=None, distro=None, machine=None, recipe=None, wrtemplate=None):\n            item = [\"\", layer][layer != None]\n            item = item + [\"\", distro][distro != None]\n            item = item + [\"\", machine][machine != None]\n            item = item + [\"\", recipe][recipe != None]\n            item = item + [\"\", wrtemplate][wrtemplate != None]\n\n            type = [\"\", 'layer'][layer != None]\n            type = type + [\"\", 'distro'][distro != None]\n            type = type + [\"\", 'machine'][machine != None]\n            type = type + [\"\", 'recipe'][recipe != None]\n            type = type + [\"\", 'template'][wrtemplate != None]\n\n            if (':' in item):\n                # User told us which layer, so ignore the other bits -- they can be used later...\n                layer = item.split(':')[0]\n                distro = None\n                machine = None\n                recipe = None\n                wrtemplate = None\n\n            # TODO: We do not actually verify the item we asked for (if a layer was specified) is available\n            found = False\n            for lindex in self.index.index:\n                branchid = self.index.getBranchId(lindex, self.get_branch(lindex=lindex))\n                if not branchid:\n                    continue\n                for layerBranch in self.index.getLayerBranch(lindex, branchid, name=layer, distro=distro, machine=machine, recipe=recipe, wrtemplate=wrtemplate) or []:\n                    requiredQueue.append( (lindex, layerBranch) )\n                    found = True\n                if found:\n                    break\n\n            if not found:\n                return False\n\n            return True\n\n        for l in self.layers:\n            if not procConfig(layer=l):\n                allfound = False\n\n        for l in self.distros:\n            if not procConfig(distro=l):\n                allfound = False\n\n        for l in self.machines:\n            if not procConfig(machine=l):\n                if self.local_layers or self.remote_layers:\n                    logger.info(\"Machine %s not found but validation disabled due to local or remote layers specified.\", l)\n                else:\n                    allfound = False\n            else:\n                if l not in self.index.get_machines(self.base_branch, settings.DEFAULT_LAYER_COMPAT_TAG):\n                    logger.critical('Unsupported machine: %s' % l)\n                    self.exit(1)\n\n        for l in self.recipes:\n            if not procConfig(recipe=l):\n                allfound = False\n\n        for l in self.wrtemplates:\n            if not procConfig(wrtemplate=l):\n                allfound = False\n\n        if not allfound:\n            logger.critical('Please correct the missing items, exiting.')\n            self.exit(1)\n\n        # Add all layers -- if necessary\n        if self.all_layers == True:\n            for lindex in self.index.index:\n                branchid = self.index.getBranchId(lindex, self.get_branch(lindex=lindex))\n                if not branchid:\n                    continue\n                for l in lindex['layerItems']:\n                    l_name = l['name']\n                    if self.is_group_layer(l_name) and not self.is_enabled_group(l_name):\n                        logger.info('Skipping extra group layer %s' % l_name)\n                        continue\n\n                    for layerBranch in self.index.getLayerBranch(lindex, branchid, layerItem=l) or []:\n                        # dl layers are always added as recommends in an --all-layers mode\n                        if '-dl-' in l_name or l_name.endswith('-dl'):\n                            recommendedQueue.append( (lindex, layerBranch) )\n                        else:\n                            requiredQueue.append( (lindex, layerBranch) )\n\n        # Compute requires and recommended layers...\n\n        # List of 'collection' and layer 'name'.  This list is used to avoid\n        # including duplicates.  Collection is matched first, then name -- as not\n        # all layer indexes may contain 'collection'\n        depCacheCol = []\n        depCacheName = []\n\n        def checkCache(lindex, layerBranch, addCache=False):\n            (collection, name, vcs_url) = self.index.getLayerInfo(lindex, layerBranch=layerBranch)\n\n            if collection in depCacheCol or name in depCacheName:\n                return True\n\n            if addCache:\n                if collection:\n                    depCacheCol.append(collection)\n                if name:\n                    depCacheName.append(name)\n            return False\n\n        def resolveIndexOrder(lindex, layerBranch, Queue):\n            # We want to recompute the dependency in INDEXES order...\n            (collection, name, vcs_url) = self.index.getLayerInfo(lindex, layerBranch)\n            found = False\n            for pindex in self.index.index:\n                # We already know it'll be in this index, so we just use it as-is...\n                if pindex == lindex:\n                    break\n\n                # Look for the collection (or name if no collection) in the indexes in\n                # priority order...\n                pbranchid = self.index.getBranchId(pindex, self.get_branch(lindex=pindex))\n                if collection:\n                    new_layerBranches = self.index.getLayerBranch(pindex, pbranchid, collection=collection)\n                    if new_layerBranches and new_layerBranches != []:\n                        for lb in new_layerBranches:\n                            logger.info('Resolving dependency %s from %s to %s from %s' % (name, lindex['CFG']['DESCRIPTION'], name, pindex['CFG']['DESCRIPTION']))\n                            Queue.append( (pindex, lb) )\n                        lindex = None\n                        layerBranch = None\n                        break\n\n                if name:\n                    new_layerBranches = self.index.getLayerBranch(pindex, pbranchid, name=name)\n                    if new_layerBranches and new_layerBranches != []:\n                        for lb in new_layerBranches:\n                            logger.info('Resolving dependency %s from %s to %s from %s' % (name, lindex['CFG']['DESCRIPTION'], name, pindex['CFG']['DESCRIPTION']))\n                            Queue.append( (pindex, lb) )\n                        lindex = None\n                        layerBranch = None\n                        break\n\n            return (lindex, layerBranch)\n\n        while requiredQueue:\n            (lindex, layerBranch) = requiredQueue.popleft()\n\n            (lindex, layerBranch) = resolveIndexOrder(lindex, layerBranch, requiredQueue)\n\n            if not lindex or not layerBranch:\n                continue\n\n            if not checkCache(lindex, layerBranch, True):\n                self.requiredlayers.append( (lindex, layerBranch) )\n                (required, recommended) = self.index.getDependencies(lindex, layerBranch)\n                for dep in required:\n                    requiredQueue.append( (lindex, dep) )\n\n                for dep in recommended:\n                    recommendedQueue.append( (lindex, dep) )\n\n        while recommendedQueue:\n            (lindex, layerBranch) = recommendedQueue.popleft()\n\n            (lindex, layerBranch) = resolveIndexOrder(lindex, layerBranch, recommendedQueue)\n\n            if not lindex or not layerBranch:\n                continue\n\n            if not checkCache(lindex, layerBranch, True):\n                if self.dl_layers != True:\n                    layers = self.index.find_layer(lindex, id=layerBranch['layer'])\n                    if layers and ('-dl-' in layers[0]['name'] or layers[0]['name'].endswith('-dl')):\n                        # Skip the download layer\n                        continue\n                self.recommendedlayers.append( (lindex, layerBranch) )\n                (required, recommended) = self.index.getDependencies(lindex, layerBranch)\n                for dep in required + recommended:\n                    recommendedQueue.append( (lindex, dep) )\n\n        unexpected_groups = []\n        for (lindex, layerBranch) in self.requiredlayers + self.recommendedlayers:\n            for layer in self.index.find_layer(lindex, id=layerBranch['layer']):\n                l_name = layer['name']\n                if self.is_group_layer(l_name) and not self.is_enabled_group(l_name):\n                    if not l_name in unexpected_groups:\n                        unexpected_groups.append(l_name)\n        unexpected_groups.sort()\n\n        if unexpected_groups:\n            logger.error('The following layer(s) need --use-layer-group=<group> or --layers=<layer>:\\n%s' % '\\n'.join(unexpected_groups))\n            logger.error('Try to rerun with one of the options?')\n            self.exit(1)\n\n        # Also compute the various remotes\n        self.remotes['base'] = self.base_url\n\n        def process_remote(lindex, layerBranch):\n            for layer in self.index.find_layer(lindex, id=layerBranch['layer']):\n                add_remote_entry(layer['vcs_url'])\n\n            for remote_layer in self.remote_layers:\n                add_remote_entry(remote_layer.get('url'))\n\n        def add_remote_entry(vcs_url):\n            found = False\n            for remote in self.remotes:\n                if vcs_url.startswith(self.remotes[remote]):\n                    found = True\n                    break\n            if not found:\n                url = urlparse(vcs_url)\n                if not url.scheme:\n                    self.remotes['local'] = '/'\n                    found = True\n\n                if not found:\n                    for (remoteurl, remotename) in settings.REMOTES:\n                        if vcs_url.startswith(remoteurl):\n                            self.remotes[remotename] = remoteurl\n                            found = True\n                            break\n\n                if not found:\n                    self.remotes[url.scheme + '_' + url.netloc.translate(str.maketrans('/:', '__'))] = url.scheme + '://' + url.netloc\n\n        for (lindex, layerBranch) in self.requiredlayers + self.recommendedlayers:\n            process_remote(lindex, layerBranch)\n\n        def display_layer(lindex, layerBranch):\n            branchid = self.index.getBranchId(lindex, self.get_branch(lindex=lindex))\n\n            for layer in self.index.find_layer(lindex, id=layerBranch['layer']):\n                vcs_url = layer['vcs_url']\n\n                path = 'layers/' + \"\".join(vcs_url.split('/')[-1:])\n\n                if (layer['name'] == 'openembedded-core'):\n                    bitbakeBranch = self.index.getBranch(lindex, layerBranch['branch'])['bitbake_branch']\n                    logger.debug('bitbake: %s %s %s' % ( settings.BITBAKE, path + '/bitbake', bitbakeBranch ))\n\n                actual_branch = layerBranch['actual_branch'] or self.index.getBranch(lindex, branchid)['name']\n                logger.debug('%s: %s %s %s' % (layer['name'], vcs_url, path, actual_branch ))\n\n\n        logger.debug('Computed required layers:')\n        for (lindex, layerBranch) in self.requiredlayers:\n            display_layer(lindex, layerBranch)\n\n        logger.debug('Computed recommended layers:%s' % ([\"\", ' (skipping)'][self.no_recommend == True]))\n        for (lindex, layerBranch) in self.recommendedlayers:\n            display_layer(lindex, layerBranch)\n\n        # Recommends are disabled, filter it...\n        if self.no_recommend == True:\n            if self.dl_layers == True:\n                newRecommendedlayers = []\n                for (lindex, layerBranch) in self.recommendedlayers:\n                    layers = self.index.find_layer(lindex, id=layerBranch['layer'])\n                    if layers and ('-dl-' in layers[0]['name'] or layers[0]['name'].endswith('-dl')):\n                        newRecommendedlayers.append( (lindex, layerBranch) )\n                self.recommendedlayers = newRecommendedlayers\n            else:\n                self.recommendedlayers = []\n\n        # if any of the remote layers have the same path as one of the\n        # layerindex layers override the vcs_url and\n        # actual_branch. Keep a list of remote layers that were not\n        # overrides so the final list of remote layers will have them\n        # removed. Cannot modify a list while iterating over it\n        additional_remote_layers = []\n        for remote_layer in self.remote_layers:\n            found = False\n            for (lindex, layerBranch) in self.requiredlayers + self.recommendedlayers:\n                for layer in self.index.find_layer(lindex, id=layerBranch['layer']):\n                    vcs_url = layer['vcs_url']\n                    path = 'layers/' + \"\".join(vcs_url.split('/')[-1:])\n                    if remote_layer.get('path') == path:\n                        layer['vcs_url'] = remote_layer.get('url')\n                        layerBranch['actual_branch'] = remote_layer.get('branch')\n                        found = True\n                        break\n                if found:\n                    break\n\n            if not found and remote_layer not in additional_remote_layers:\n                additional_remote_layers.append(remote_layer)\n\n        # remote layers with the overrides removed\n        self.remote_layers = additional_remote_layers\n\n        logger.debug('Done')\n\n    def project_setup(self):\n        logger.debug('Starting')\n        self.__setup_local_layer()\n\n        if self.mirror != True:\n            # We need to make sure the environment-setup link is always current\n            for (dirpath, dirnames, filenames) in os.walk(os.path.join(self.project_dir, 'bin/buildtools')):\n                for filename in filenames:\n                    if filename.startswith('environment-setup-'):\n                        src = os.path.relpath(os.path.join(dirpath, filename), self.project_dir)\n                        dst = os.path.join(self.project_dir, filename)\n                        if os.path.islink(dst):\n                            os.unlink(dst)\n                        os.symlink(src, dst)\n\n        logger.debug('Done')\n\n    def update_project(self):\n        logger.debug('Starting')\n        if not os.path.exists(self.project_dir + '/.templateconf'):\n            tmplconf = open(self.project_dir + '/.templateconf', 'w')\n            tmplconf.write('# Project template settings\\n')\n            tmplconf.write('TEMPLATECONF=${TEMPLATECONF:-$OEROOT/config}\\n')\n            tmplconf.close()\n\n        self.copySample(self.install_dir + '/data/samples/README.sample', self.project_dir + '/README')\n        self.copySample(self.install_dir + '/data/samples/bblayers.conf.sample', self.project_dir + '/config/bblayers.conf.sample')\n        self.copySample(self.install_dir + '/data/samples/conf-notes.sample', self.project_dir + '/config/conf-notes.txt')\n        self.copySample(self.install_dir + '/data/samples/local.conf.sample', self.project_dir + '/config/local.conf.sample')\n\n        with open(self.project_dir + '/config/local.conf.sample', 'a') as f:\n            inc = '\\n# Add known layers to whitelist'\n            inc += '\\nrequire conf/wrlinux-whitelist.inc\\n'\n            f.write(inc)\n\n        if os.path.exists(self.install_dir + '/data/samples/site.conf.sample'):\n            self.copySample(self.install_dir + '/data/samples/site.conf.sample', self.project_dir + '/config/site.conf.sample')\n        with open(self.saved_base_branch, 'w') as f:\n            f.write('%s\\n' % self.base_branch)\n\n    def update_mirror(self):\n        self.copySample(self.install_dir + '/data/samples/README-MIRROR.sample', self.project_dir + '/README')\n\n    def __prep_replacements(self):\n        self.replacement['layers'] = []\n        self.replacement['machines'] = {}\n        self.replacement['distros'] = {}\n\n        def addLayer(lindex, layerBranch):\n            branchid = self.index.getBranchId(lindex, self.get_branch(lindex=lindex))\n\n            paths = []\n            for layer in self.index.find_layer(lindex, id=layerBranch['layer']):\n                vcs_url = layer['vcs_url']\n\n                path = 'layers/' + \"\".join(vcs_url.split('/')[-1:])\n                if layerBranch['vcs_subdir']:\n                    path += '/' + layerBranch['vcs_subdir']\n\n                paths.append(path)\n\n            return paths\n\n        # Add layers to 'LAYERS'\n        for (lindex, layerBranch) in self.requiredlayers + self.recommendedlayers:\n            self.replacement['layers'] = self.replacement['layers'] + addLayer(lindex, layerBranch)\n\n        # Add machines to 'MACHINES'\n        for (lindex, layerBranch) in self.requiredlayers + self.recommendedlayers:\n            for machine in lindex['machines']:\n                if machine['layerbranch'] == layerBranch['id']:\n                    desc = machine['description'] or machine['name']\n                    self.replacement['machines'][machine['name']] = desc\n\n        # Add distro to 'DISTROS'\n        for (lindex, layerBranch) in self.requiredlayers + self.recommendedlayers:\n            for distro in lindex['distros']:\n                if distro['layerbranch'] == layerBranch['id']:\n                    desc = distro['description'] or distro['name']\n                    self.replacement['distros'][distro['name']] = desc\n\n\n\n    def copySample(self, src, dst):\n        src = open(src, 'r')\n        dst = open(dst, 'w')\n\n        for line in src:\n            if '####LAYERS####' in line:\n                for l in self.replacement['layers']:\n                    dst.write(line.replace('####LAYERS####', '##OEROOT##/%s' % (l)))\n                for rl in self.remote_layers:\n                    dst.write(line.replace('####LAYERS####', '##OEROOT##/%s' % (rl.get('path'))))\n                for ll in self.local_layers:\n                    dst.write(line.replace('####LAYERS####', '%s' % (ll)))\n                continue\n            if '####SETUP_ARGS####' in line:\n                dst.write(line.replace('####SETUP_ARGS####', self.setup_args))\n                continue\n            if '####MACHINES####' in line:\n                for (name, desc) in sorted(self.replacement['machines'].items(), key=lambda t: t[0]):\n                    dst.write('# %s\\n' % desc.strip())\n                    dst.write(line.replace('####MACHINES####', name))\n                continue\n            if '####DEFAULTMACHINE####' in line:\n                name = self.machines[0]\n                if ':' in name:\n                    name = ':'.join(name.split(':')[1:])\n                dst.write(line.replace('####DEFAULTMACHINE####', name))\n                continue\n            if '####DISTROS####' in line:\n                for (name, desc) in sorted(self.replacement['distros'].items(), key=lambda t: t[0]):\n                    dst.write('# %s\\n' % desc.strip())\n                    dst.write(line.replace('####DISTROS####', name))\n                continue\n            if '####DEFAULTDISTRO####' in line:\n                name = self.distros[0]\n                if ':' in name:\n                    name = ':'.join(name.split(':')[1:])\n                dst.write(line.replace('####DEFAULTDISTRO####', name))\n                continue\n            if '####DEFAULTWRTEMPLATE####' in line:\n                dst.write(line.replace('####DEFAULTWRTEMPLATE####', ' '.join(self.wrtemplates)))\n                continue\n            dst.write(line)\n\n        src.close()\n        dst.close()\n\n    def update_mirror_index(self):\n        logger.debug('Starting')\n        path = os.path.join(self.project_dir, 'mirror-index')\n\n        logger.plain('Exporting mirror-index %s...' % (path))\n        if not os.path.exists(path):\n            cmd = [self.tools['git'], 'init', path]\n            utils_setup.run_cmd(cmd, log=2, environment=self.env, cwd=self.project_dir)\n\n        try:\n            cmd = [self.tools['git'], 'checkout', '-b', self.base_branch]\n            utils_setup.run_cmd(cmd, log=2, environment=self.env, cwd=path)\n        except:\n            # if we failed, then simply try to switch branches\n            cmd = [self.tools['git'], 'checkout', self.base_branch]\n            utils_setup.run_cmd(cmd, log=2, environment=self.env, cwd=path)\n\n        # Make sure the directory is empty, use -f to ignore failures\n        for (dirpath, dirnames, filenames) in os.walk(path):\n            if dirpath.endswith('/.git') or path + '/.git' in dirpath:\n                continue\n            for filename in filenames:\n                os.remove(os.path.join(dirpath, filename))\n\n        # Construct a list of all layers we've downloaded, by url, including sublayers not activated\n        url_cache = {}\n        for (lindex, layerBranch) in self.requiredlayers + self.recommendedlayers:\n            for layer in self.index.find_layer(lindex, id=layerBranch['layer']):\n                vcs_url = layer['vcs_url']\n                if not vcs_url in url_cache:\n                    url_cache[vcs_url] = []\n                url_cache[vcs_url].append((lindex, layerBranch['branch']))\n\n        # Serialize the information for each of the layers (and their sublayers)\n        for vcs_url in url_cache:\n            for (lindex, branchid) in url_cache[vcs_url]:\n                for layer in lindex['layerItems']:\n                    if layer['vcs_url'] in url_cache:\n                        for lb in self.index.getLayerBranch(lindex, branchid=branchid, layerItem=layer):\n                            self.index.serialize_index(lindex, os.path.join(path, lindex['CFG']['DESCRIPTION']), split=True, layerBranches=[lb], IncludeCFG=True, mirror=True, base_url=self.base_url)\n                        name = layer['name']\n                        destdir = os.path.join(path, 'xml')\n                        srcfile = os.path.join(self.xml_dir, '%s.inc' % (name))\n                        if os.path.exists(srcfile):\n                            os.makedirs(destdir, exist_ok=True)\n                            shutil.copy(srcfile, destdir)\n                        srcfile = os.path.join(self.xml_dir, '%s.xml' % (name))\n                        if os.path.exists(srcfile):\n                            os.makedirs(destdir, exist_ok=True)\n                            shutil.copy(srcfile, destdir)\n\n                        # Special processing for the openembedded-core layer\n                        if name == 'openembedded-core':\n                            srcfile = os.path.join(self.xml_dir, 'bitbake.inc')\n                            if os.path.exists(srcfile):\n                                os.makedirs(destdir, exist_ok=True)\n                                shutil.copy(srcfile, destdir)\n                            srcfile = os.path.join(self.xml_dir, 'bitbake.xml')\n                            if os.path.exists(srcfile):\n                                os.makedirs(destdir, exist_ok=True)\n                                shutil.copy(srcfile, destdir)\n\n        # git add file.\n        cmd = [self.tools['git'], 'add', '-A', '.']\n        utils_setup.run_cmd(cmd, environment=self.env, cwd=path)\n\n        try:\n            cmd = [self.tools['git'], 'diff-index', '--quiet', 'HEAD', '--']\n            utils_setup.run_cmd(cmd, log=2, environment=self.env, cwd=path, stderr=subprocess.DEVNULL, stdout=subprocess.DEVNULL)\n        except:\n            logger.debug('Updating mirror-index')\n            cmd = [self.tools['git'], 'commit', '-m', 'Updated index - %s' % (self.setup_args)]\n            utils_setup.run_cmd(cmd, environment=self.env, cwd=path)\n        logger.debug('Done')\n\n\n    def update_manifest(self):\n        logger.debug('Starting')\n\n        fxml = open(os.path.join(self.project_dir, self.default_xml), 'w')\n        fxml.write('<manifest>\\n')\n\n        remote = 'base'\n        fxml.write('    <remote  name=\"%s\" fetch=\"%s\"/>\\n' % (remote, self.remotes[remote]))\n        fxml.write('    <default revision=\"%s\" remote=\"%s\" sync-j=\"%s\"/>\\n' % (self.base_branch, remote, self.jobs))\n\n        for remote in sorted(self.remotes):\n            if remote == 'base':\n                continue\n            fxml.write('    <remote  name=\"%s\" fetch=\"%s\"/>\\n' % (remote, self.remotes[remote]))\n\n        def open_xml_tag(name, url, remote, path, revision):\n            fxml.write('    <project name=\"%s\" remote=\"%s\" path=\"%s\" revision=\"%s\">\\n' % (url, remote, path, revision))\n\n        def inc_xml(name, url, remote, path, revision):\n            # incfile is included inline and has to work as elements of the 'project'\n            incfile = os.path.join(self.xml_dir, '%s.inc' % (name))\n            logger.debug('Looking for %s' % (incfile))\n            if os.path.exists(incfile):\n                fbase = open(incfile, 'r')\n                for line in fbase:\n                    fxml.write(line)\n                fbase.close()\n\n        def close_xml_tag(name, url, remote, path, revision):\n            fxml.write('    </project>\\n')\n\n        def add_xml(name, url, remote, path, revision):\n            # xmlfile is included after the entry and is completely standalone\n            xmlfile = os.path.join(self.xml_dir, '%s.xml' % (name))\n            logger.debug('Looking for %s' % (xmlfile))\n            if os.path.exists(xmlfile):\n                fbase = open(xmlfile, 'r')\n                for line in fbase:\n                    fxml.write(line)\n                fbase.close()\n\n        def write_xml(name, url, remote, path, revision):\n            open_xml_tag(name, url, remote, path, revision)\n            inc_xml(name, url, remote, path, revision)\n            close_xml_tag(name, url, remote, path, revision)\n            add_xml(name, url, remote, path, revision)\n\n        if self.mirror == True and self.buildtools_branch:\n            if self.buildtools_remote:\n                write_xml('buildtools', self.buildtools_remote, 'base', self.buildtools_remote, self.buildtools_branch)\n            if self.another_buildtools_remote:\n                write_xml('buildtools', self.another_buildtools_remote, 'base', self.another_buildtools_remote, self.buildtools_branch)\n\n        def process_xml_layers(allLayers):\n            def process_xml_layer(lindex, layerBranch):\n                branchid = self.index.getBranchId(lindex, self.get_branch(lindex=lindex))\n\n                for layer in self.index.find_layer(lindex, id=layerBranch['layer']):\n                    revision = layerBranch['actual_branch'] or self.index.getBranch(lindex, branchid)['name']\n\n                    vcs_url = layer['vcs_url']\n\n                    for remote in self.remotes:\n                        if vcs_url.startswith(self.remotes[remote]):\n                            break\n\n                    url = vcs_url[len(self.remotes[remote]):]\n                    url = url.strip('/')\n\n                    path = 'layers/' + \"\".join(url.split('/')[-1:])\n\n                    entry = {\n                           'name' : layer['name'],\n                           'remote' : remote,\n                           'path' : path,\n                           'revision' : revision,\n                        }\n\n                    if url not in cache:\n                        cache[url] = []\n\n                    if entry['name'] == 'openembedded-core':\n                        bitbakeurl = '/'.join(url.split('/')[:-1] + [ settings.BITBAKE ])\n                        bitbakeBranch = self.index.getBranch(lindex, layerBranch['branch'])['bitbake_branch']\n                        bitbake_entry = {\n                                'name' : 'bitbake',\n                                'remote' : remote,\n                                'path' : path + '/bitbake',\n                                'revision' : bitbakeBranch,\n                            }\n                        if bitbakeurl not in cache:\n                            cache[bitbakeurl] = []\n                        cache[bitbakeurl].append(bitbake_entry)\n\n                    cache[url].append(entry)\n\n            # We need to construct a list of layers with same urls...\n            cache = {}\n\n            for (lindex, layerBranch) in allLayers:\n                process_xml_layer(lindex, layerBranch)\n\n            from collections import OrderedDict\n\n            for url in OrderedDict(sorted(cache.items(), key=lambda t: t[0])):\n                name = cache[url][0]['name']\n                remote = cache[url][0]['remote']\n                path = cache[url][0]['path']\n                revision = cache[url][0]['revision']\n\n                open_xml_tag(name, url, remote, path, revision)\n\n                for entry in cache[url]:\n                    inc_xml(entry['name'], url, remote, path, revision)\n\n                close_xml_tag(name, url, remote, path, revision)\n\n                for entry in cache[url]:\n                    add_xml(entry['name'], url, remote, path, revision)\n\n        process_xml_layers(self.requiredlayers + self.recommendedlayers)\n\n        # process the remote layers\n        for remote_layer in self.remote_layers:\n            vcs_url = remote_layer.get('url')\n            for remote in self.remotes:\n                if vcs_url.startswith(self.remotes[remote]):\n                    break\n\n            url = vcs_url[len(self.remotes[remote]):]\n            url = url.strip('/')\n            name = \"\".join(url.split('/')[-1:])\n            path = remote_layer.get('path')\n            revision = remote_layer.get('branch')\n\n            open_xml_tag(name, url, remote, path, revision)\n            close_xml_tag(name, url, remote, path, revision)\n\n        fxml.write('</manifest>\\n')\n        fxml.close()\n\n        logger.debug('Done')\n\n    def check_default_xml(self):\n        \"\"\"\n        * Check for duplicated basename in default.xml, e.g.:\n          - path=\"/foo1/bar\"\n          - path=\"/foo2/bar\"\n          This doesn't work for flatten mirrors.\n\n        * Check whether 'name' is endded with '.git'\n        \"\"\"\n\n        logger.debug('Starting checking duplicated path in xml')\n        default_xml_dict = {}\n        tree = ET.parse(self.default_xml)\n        root = tree.getroot()\n        for project in root.iter('project'):\n            path = project.attrib['path']\n            if path:\n                basename = os.path.basename(path)\n                if basename in default_xml_dict:\n                    default_xml_dict[basename].append(path)\n                else:\n                    default_xml_dict[basename] = [path]\n\n            # The 'name' cannot be ended with '.git'\n            name = project.attrib['name']\n            if name and name.endswith('.git'):\n                name_no_git = name[:-4]\n                logger.warning(\"%s cannot be ended with '.git', suggest %s\" %(name, name_no_git))\n\n        for basename, paths in default_xml_dict.items():\n            if len(paths) > 1:\n                logger.warning(\"Found duplicated basename in %s's attribute 'path':\" % self.default_xml)\n                for path in paths:\n                    logger.warning(path)\n\n        logger.debug('Done')\n\n    def get_git_premirrors_from_mirror_index(self, url, protocol):\n        \"\"\"\n        Generate PREMIRRORS conf for git from mirror-index.\n        \"\"\"\n        premirrors_conf_git = []\n        for xml in os.listdir(self.xml_dir):\n            xml_file = os.path.join(self.xml_dir, xml)\n            if not (xml.endswith('.xml') and '-dl' in xml):\n                logger.debug('Skipping %s' % xml_file)\n                continue\n\n            # Parse xml file and save the name, these xml files are just xml\n            # sections, not integrated xml, so can't use ET to parse them.\n            logger.debug('Parsing %s' % xml_file)\n            with open(xml_file) as x:\n                for line in x.readlines():\n                    if not 'name=' in line:\n                        continue\n                    # Part of the parsing errors may not matter since we only\n                    # need their parent dirs.\n                    try:\n                        name = line.split('name=')[1].split()[0].strip('\"')\n                    except Exception as esc:\n                        logger.warning('Failed to get name from %s:%s' % (xml_file, line))\n                    if name:\n                        conf = \"    git://.*/.* git://%s%s/%s/MIRRORNAME;protocol=%s \\\\n \\\\\" % \\\n                                (url.netloc, url.path, os.path.dirname(name), protocol)\n                    if not conf in premirrors_conf_git:\n                        premirrors_conf_git.append(conf)\n                        premirrors_conf_git.append(conf.replace('git://', 'gitsm://'))\n\n        # Make the subdirs in front to have a higher priority in PREMIRRORS, e.g.:\n        # external/yocto\n        # external/qt5\n        # [snip]\n        # external\n        if not premirrors_conf_git:\n            logger.warning('Failed get figure out dirs from %s' % self.xml_dir)\n        else:\n            premirrors_conf_git.reverse()\n\n        return premirrors_conf_git\n\n    def make_mirror_as_premirrors(self):\n        \"\"\"\n        * dl*/downlaods: Use \"git clone --local --branch <revision>\" to clone dl layers into\n                         premirrors-dl, and copy (link) dl*/downloads/* into premirrors-dl/downloads,\n                         the premirrors-dl/downloads will be used as PREMIRRORS by client.\n\n        * git repo sources: No action is needed since they are already bare repos.\n        \"\"\"\n\n        logger.info('Making project mirror as PREMIRRORS...')\n        premirrors_dict = {}\n        tree = ET.parse(self.default_xml)\n        root = tree.getroot()\n        for project in root.iter('project'):\n            # Only need the dl layers\n            if 'bare' in project.attrib and project.attrib['bare'] == \"True\":\n                continue\n            name = project.attrib['name']\n            if name and (name.endswith('-dl') or '-dl-' in name):\n                try:\n                    path = project.attrib['path']\n                    if path and path.startswith('layers/'):\n                        revision = project.attrib['revision'].replace('refs/tags/', '')\n                        premirrors_dict[name] = revision\n                except Exception as esc:\n                    logger.warning('%s: Failed to find revision or path: %s' % (name, esc))\n\n        if premirrors_dict:\n             if not os.path.exists(self.premirrors_dl):\n                os.mkdir(self.premirrors_dl)\n        else:\n            logger.warning(\"mirror-as-premirrors: No dl layers found!\")\n            return\n\n        for name, revision in premirrors_dict.items():\n            src = os.path.join(self.project_dir, name)\n            dst = os.path.join(self.premirrors_dl, os.path.basename(name))\n            # Run the git reset and pull in the existed repo\n            dst_git = os.path.join(dst, '.git')\n            need_clone = True\n            if os.path.exists(dst_git):\n                logger.debug('Making %s as a PREMIRROR' % src)\n                try:\n                    for cmd in ([self.tools['git'], 'fetch', '-q', 'origin', revision], \\\n                                    [self.tools['git'], 'checkout', '-q', 'FETCH_HEAD']):\n                        utils_setup.run_cmd(cmd, environment=self.env, cwd=dst)\n                    need_clone = False\n                except Exception as esc:\n                    logger.warning('%s: Failed to update it: %s' % (dst, esc))\n                    logger.warning('%s: Removing it...' % dst)\n                    shutil.rmtree(dst)\n            if need_clone:\n                # There are a lot of messages when run \"git clone --branch <tag>\"\n                # which rush the screen, so use \"git clone -nq\" to make it\n                # quiet, and \"git checkout <branch/tag>\" to checkout the files.\n                cmd = [self.tools['git'], 'clone', '--local', '-nq', src, dst]\n                utils_setup.run_cmd(cmd, environment=self.env)\n                cmd = [self.tools['git'], 'checkout', '-q', revision]\n                utils_setup.run_cmd(cmd, environment=self.env, cwd=dst)\n        # Create a clean premirrors-dl/downloads as PREMIRRORS\n        if os.path.exists(self.premirrors_dl_downloads):\n            shutil.rmtree(self.premirrors_dl_downloads)\n        os.mkdir(self.premirrors_dl_downloads)\n        cmd = 'cp -alf %s/*-dl*/downloads/* %s' % (self.premirrors_dl, self.premirrors_dl_downloads)\n        subprocess.run(cmd, shell=True)\n        logger.info('The PREMIRROR files are prepared in %s' % self.premirrors_dl_downloads)\n\n    def use_mirror_as_premirrors(self):\n        \"\"\"\n        Use mirror as PREMIRRORS if the project is cloned from a mirror\n        \"\"\"\n\n        logger.info('Using mirror as PREMIRRORS...')\n\n        if not self.mirror_index_path:\n            logger.warning(\"This project isn't setup from a project mirror, skipping mirror-as-premirrors\")\n            return\n\n        premirrors_output = os.path.join(self.conf_dir, 'mirror-as-premirrors.conf')\n\n        enable_network = False\n        url = urlparse(self.base_url)\n        if url.scheme and url.scheme != 'file':\n            protocol = url.scheme\n            enable_network = True\n        else:\n            protocol = 'file'\n\n        premirrors_conf_git = self.get_git_premirrors_from_mirror_index(url, protocol)\n\n        premirrors_conf_downloads = []\n        downloads_via_git = \"\"\n        if protocol == 'git':\n            downloads_via_git = \"The protocol git:// is invalid for premirrors-dl/downloads\"\n            logger.warning('mirror-as-mirrorrs: %s' % downloads_via_git)\n        else:\n            premirrors_conf_downloads.append(\"    .*://.*/.* %s://%s%s/premirrors-dl/downloads/ \\\\n \\\\\" % \\\n                (protocol, url.netloc, url.path))\n\n        with open(premirrors_output, 'w') as f:\n            f.write('# Use project mirror as PREMIRRORS for the build\\n')\n            if premirrors_conf_git:\n                f.write('PREMIRRORS:append = \" \\\\\\n')\n                f.write('%s\\n\"\\n' % '\\n'.join(premirrors_conf_git))\n            if premirrors_conf_downloads:\n                f.write('PREMIRRORS:append = \" \\\\\\n')\n                f.write('%s\\n\"\\n' % '\\n'.join(premirrors_conf_downloads))\n            if enable_network:\n                # The network is for PREMIRRORS only\n                f.write('\\n# The network is for PREMIRRORS only\\n')\n                f.write('BB_NO_NETWORK = \"0\"\\n')\n                f.write('BB_FETCH_PREMIRRORONLY = \"1\"\\n')\n\n        local_conf_sample = os.path.join(self.project_dir, 'config/local.conf.sample')\n        with open(local_conf_sample, 'a+') as f:\n            f.seek(0)\n            line = 'require ##OEROOT##/config/mirror-as-premirrors.conf\\n'\n            if not line in f.readlines():\n                f.write('\\n# Use project mirror as PREMIRRORS for the build\\n')\n                f.write(line)\n\n    def update_gitignore(self):\n        logger.debug('Starting')\n\n        ign_list = [\n                    '.repo*',\n                    '*.pyc',\n                    '*.pyo',\n                    '*.swp',\n                    '*.orig',\n                    '*.rej',\n                    '*~',\n                    '/bin',\n                    '/environment-setup-*',\n                    '/layers/*',\n                    '!layers/local',\n                    os.path.basename(self.install_dir),\n                    ]\n\n        tree = ET.parse(os.path.join(self.project_dir, 'default.xml'))\n        root = tree.getroot()\n        for linkfile in root.iter('linkfile'):\n            dest = linkfile.attrib['dest']\n            if not '/' in dest:\n                ign_list.append(dest)\n\n        with open(os.path.join(self.project_dir, '.gitignore'), 'a+') as f:\n            f.seek(0)\n            existed = f.readlines()\n            for l in ign_list:\n                item = '%s\\n' % l\n                if item not in existed:\n                    f.write(item)\n\n        logger.debug('Done')\n\n    def commit_files(self):\n        logger.debug('Starting')\n\n        # List of all files that may change due to config\n        filelist = [\n            'README',\n            'default.xml',\n            '.gitignore',\n            '.gitconfig',\n            'config/index-cache',\n            ]\n\n        # If we are mirroring, skip all of these...\n        if self.mirror != True:\n            filelist.append('layers/local')\n            filelist.append('.templateconf')\n            filelist.append('config/bblayers.conf.sample')\n            filelist.append('config/conf-notes.txt')\n            filelist.append('config/local.conf.sample')\n            filelist.append('config/saved_base_branch')\n\n            if os.path.exists('config/site.conf.sample'):\n                filelist.append('config/site.conf.sample')\n\n        # Add log dir if it contains files\n        if os.listdir('config/log'):\n            filelist.append('config/log')\n\n        # git init\n        if not os.path.exists(self.project_dir + '/.git'):\n            cmd = [self.tools['git'], 'init', self.project_dir]\n            if self.quiet == self.default_repo_quiet:\n                cmd.append(self.quiet)\n            utils_setup.run_cmd(cmd, environment=self.env, cwd=self.conf_dir)\n\n        # git add manifest. (Since these files are new, always try to add them)\n        cmd = [self.tools['git'], 'add', '--'] + filelist\n        utils_setup.run_cmd(cmd, environment=self.env, cwd=self.project_dir)\n\n        try:\n            cmd = [self.tools['git'], 'diff-index', '--quiet', 'HEAD', '--'] + filelist\n            utils_setup.run_cmd(cmd, log=2, environment=self.env, cwd=self.project_dir, stderr=subprocess.DEVNULL, stdout=subprocess.DEVNULL)\n        except:\n            logger.plain('Updated project configuration')\n            # Command failed -- so self.default_xml changed...\n            cmd = [self.tools['git'], 'commit', '-q', '-m', 'Configuration change - %s' % (self.setup_args), '--'] + filelist\n            utils_setup.run_cmd(cmd, environment=self.env, cwd=self.project_dir)\n\n        logger.debug('Done')\n\n    def repo_sync(self):\n        if self.repo_no_fetch:\n            logger.info('Skipping repo sync')\n            return\n\n        logger.debug('Starting')\n\n        def checkout_to_repo_branch():\n            # Checkout to specific branch\n            if self.repo_rev:\n                cmd = [self.tools['git'], 'checkout', '-B', self.repo_rev, 'origin/%s' % self.repo_rev]\n                utils_setup.run_cmd(cmd, environment=self.env, cwd=os.path.dirname(self.repo_dir))\n\n        self.repo_dir = os.path.join(self.project_dir, self.check_repo_install_dir)\n        if os.path.exists(self.repo_dir):\n            checkout_to_repo_branch()\n            cmd = ['-j', self.jobs]\n            self.call_repo_sync(cmd)\n        else:\n            # repo init\n            cmd = ['-m', self.default_xml, '-u',  self.project_dir]\n            if self.mirror == True:\n                cmd.append('--mirror')\n\n            cmd.append('--no-repo-verify')\n            self.call_repo_init(cmd)\n\n            checkout_to_repo_branch()\n\n            # repo sync\n            cmd = ['-j', self.jobs]\n            self.call_initial_repo_sync(cmd)\n\n        logger.debug('Done')\n\n    def __check_and_update_layerseries_compat(self, project_local_layer_path, data_local_layer_path):\n        project_layer_conf = os.path.join(project_local_layer_path, 'conf/layer.conf')\n        data_layer_conf = os.path.join(data_local_layer_path, 'conf/layer.conf')\n        project_layerseries_compat_line = \"\"\n        data_layerseries_compat_line = \"\"\n        update_local_conf = False\n        with open(data_layer_conf, 'r') as f:\n            for line in f.readlines():\n                if 'LAYERSERIES_COMPAT_local' in line:\n                    data_layerseries_compat_line = line\n                    break\n\n        with open(project_layer_conf, 'r') as f:\n            lines = f.readlines()\n            newlines = []\n            for line in lines:\n                if 'LAYERSERIES_COMPAT_local' in line:\n                    project_layerseries_compat_line = line\n                    if project_layerseries_compat_line != data_layerseries_compat_line:\n                        newlines.append(data_layerseries_compat_line)\n                        update_local_conf = True\n                    else:\n                        newlines.append(project_layerseries_compat_line)\n                else:\n                    newlines.append(line)\n\n        if update_local_conf:\n            logger.info(\"Update LAYERSERIES_COMPAT_local for local layer\")\n            with open(project_layer_conf, 'w') as f:\n                for line in newlines:\n                    f.write(line)\n\n    def __set_pnwhitelist_layers(self):\n        \"\"\"Set PNWHITELIST_LAYERS in wrlinux-whitelist.inc of layer local\"\"\"\n        logger.debug('Checking PNWHITELIST_LAYERS in local layer')\n\n        local_layer_conf = os.path.join(self.project_dir, 'layers/local', 'conf/wrlinux-whitelist.inc')\n        index_layers = self.index.get_index_layers(self.base_branch)\n        collections = []\n        for _, layers in index_layers.items():\n            for layer in layers:\n                col = layer['collection']\n                if col:\n                    collections.append(layer['collection'])\n                else:\n                    logger.warning('%s: BBFILE_COLLECTIONS is None' % layer['name'])\n\n        existed = False\n        lines = []\n        if os.path.isfile(local_layer_conf):\n            with open(local_layer_conf, 'r') as f:\n                for line in f:\n                    if re.match(r'PNWHITELIST_LAYERS\\s*=', line):\n                        lines.append(\"PNWHITELIST_LAYERS = '%s'\" % ' '.join(sorted(collections)))\n                        existed = True\n                    else:\n                        lines.append(line)\n        else:\n            lines.append('# DO NOT EDIT THIS FILE!')\n            lines.append('\\n# This file is automatically generated by setup.py\\n')\n\n        if not existed:\n            lines.append('\\n# Set PNWHITELIST_LAYERS with all known layers')\n            lines.append(\"\\nPNWHITELIST_LAYERS = '%s'\" % ' '.join(sorted(collections)))\n\n        with open(local_layer_conf, 'w') as f:\n            f.writelines(lines)\n\n    def __setup_local_layer(self):\n        \"\"\"Setup the local layer in /layers/local - if required.\"\"\"\n        logger.debug('Checking local layer')\n\n        if self.mirror is True:\n            return\n\n        project_local_layer_path = os.path.join(self.project_dir,'layers/local')\n        data_local_layer_path = os.path.join(self.install_dir, 'data/local_layer')\n        if os.path.exists(project_local_layer_path):\n            # update LAYERSERIES_COMPAT_local if necessary\n            self.__check_and_update_layerseries_compat(project_local_layer_path, data_local_layer_path)\n            self.__set_pnwhitelist_layers()\n            return\n\n        logger.debug('Starting local layer')\n\n        if not os.path.exists(os.path.join(self.project_dir, 'layers')):\n            os.makedirs(os.path.join(self.project_dir, 'layers'))\n\n        if not os.path.exists(os.path.join(self.project_dir, 'layers/local')):\n            shutil.copytree(os.path.join(self.install_dir, 'data/local_layer'), os.path.join(self.project_dir, 'layers/local'))\n            # make sure the local layer is writeable\n            try:\n                cmd = ['chmod', '-R', '+w', '%s' % (project_local_layer_path)]\n                utils_setup.run_cmd(cmd, environment=self.env)\n            except Exception as e:\n                raise\n\n        self.__set_pnwhitelist_layers()\n\n        logger.debug('Done')\n\n    def setup_env(self):\n        self.set_ssl_cert()\n        self.set_repo_git_env()\n        self.add_bin_path()\n\n    def add_bin_path(self):\n        self.env[\"PATH\"] = self.install_dir + \"/bin:\" + self.env[\"PATH\"]\n\n    def set_repo_git_env(self):\n        # Set HOME to install_dir to use install_dir/.gitconfig settings.  Otherwise the user will\n        # be prompted for information.\n        self.env[\"HOME\"] = self.project_dir\n\n    def set_ssl_cert(self):\n        fn = self.project_dir + self.BINTOOLS_SSL_CERT\n        dn = self.project_dir + self.BINTOOLS_SSL_DIR\n        if os.path.exists(fn) and os.path.exists(dn):\n            self.env[\"GIT_SSL_CAINFO\"] = fn\n            self.env[\"CURL_CA_BUNDLE\"] = fn\n            self.env[\"SSL_CERT_FILE\"] = fn\n            self.env[\"SSL_CERT_DIR\"] = dn\n            os.environ[\"SSL_CERT_FILE\"] = fn\n            os.environ[\"SSL_CERT_DIR\"] = dn\n\n    def call_repo_init(self, args):\n        logger.debug('Starting')\n        repo = self.tools['repo']\n        directory = os.path.join(self.project_dir, self.check_repo_install_dir)\n        if os.path.exists(directory):\n            logger.info('Done: detected repo init already run since %s exists' % directory)\n            return\n        cmd = [repo, 'init', '--no-clone-bundle']\n        if self.depth:\n            cmd.append(self.depth)\n        if self.repo_url:\n            cmd.extend(['--repo-url', self.repo_url])\n        if self.repo_rev:\n            cmd.extend(['--repo-branch', self.repo_rev])\n        log_it = 1\n        if self.repo_verbose is not True and self.quiet == self.default_repo_quiet:\n            cmd.append(self.quiet)\n            log_it = 0\n        cmd.extend(args)\n        logger.debug(\"cmd: %s\" % cmd)\n        try:\n            utils_setup.run_cmd(cmd, environment=self.env, log=log_it)\n        except Exception as e:\n            raise\n        logger.debug('Done')\n\n    # This only exists to check if we have fully sync'ed the project\n    # Updating should use call_repo_sync\n    def call_initial_repo_sync(self, args):\n        logger.debug('Starting')\n        sync_file= os.path.join(self.project_dir, self.check_repo_sync_file)\n        local_only = 0\n        orig_args = list(args)\n        if os.path.exists(sync_file):\n            logger.info('Detected repo sync already run since %s exists' % sync_file)\n            logger.info('Only running local update.')\n            args.append('--local-only')\n            local_only = 1\n        try:\n            self.call_repo_sync(args)\n        except Exception as e:\n            if not local_only:\n                raise\n            else:\n                logger.info('Using --local-only failed.  Trying full sync.')\n                try:\n                    self.call_repo_sync(orig_args)\n                except Exception as e2:\n                    raise\n\n        logger.debug('Done')\n\n    def call_repo_sync(self, args):\n        logger.debug('Starting')\n        repo = self.tools['repo']\n        cmd = [repo, 'sync', '--prune']\n        # disable use of /clone.bundle on HTTP/HTTPS\n        cmd.append('--no-clone-bundle')\n        if self.force_sync:\n            cmd.append(self.force_sync)\n        log_it = 1\n        if self.repo_verbose is not True and self.quiet == self.default_repo_quiet:\n            cmd.append(self.quiet)\n            log_it = 0\n        cmd.extend(args)\n        utils_setup.run_cmd(cmd, environment=self.env, log=log_it)\n        logger.debug('Done')\n\n    def get_branch(self, lindex=None):\n        if lindex:\n            return self.index.getIndexBranch(default=self.base_branch, lindex=lindex)\n        return self.base_branch\n\n    def get_path(self, tool):\n        cmd = self.which(tool)\n        if (not cmd):\n            logger.critical('Cannot find %s in path!' % tool)\n            logger.critical('Path was: %s' % os.environ['PATH'])\n        return cmd\n\n    # Helpers: Set_*, which..\n    def set_repo_verbose(self, verbose):\n        self.repo_verbose = verbose\n\n    def set_jobs(self, jobs):\n        logger.debug('Setting jobs to %s' % jobs)\n        self.jobs = jobs\n\n    def set_depth(self, depth):\n        if int(depth) <= 1:\n            logger.info('repo depth %s is invalid, setting to 2' % depth)\n            depth = '2'\n        logger.debug('Setting depth to %s' % depth)\n        self.depth = '--depth=%s' % depth\n\n    def set_force_sync(self, sync):\n        logger.debug('Setting force-sync to %s' % sync)\n        if sync is True:\n            self.force_sync = '--force-sync'\n\n    def set_repo_url(self, url):\n        logger.debug('Setting repo-url to %s' % url)\n        self.repo_url = url\n\n    def set_repo_rev(self, rev):\n        logger.debug('Setting repo-rev to %s' % rev)\n        self.repo_rev = rev\n\n    def set_debug(self):\n        self.debug_lvl += 1\n        self.set_debug_env()\n        self.quiet = None\n        logger.setLevel(logging.DEBUG)\n        logger.debug('logging level set to DEBUG')\n\n    def set_base_url(self, url):\n        logger.debug('Setting base-url to %s' % url)\n        self.base_url = url\n\n    def set_base_branch(self, branch):\n        logger.debug('Setting base-branch to %s' % branch)\n        self.base_branch = branch\n\n    def set_debug_env(self):\n        self.env[\"REPO_CURL_VERBOSE\"] = '1'\n\n\n    def touch(self, fn):\n        logger.debug(\"Creating %s\" % fn)\n        open(fn, 'a').close()\n\n    ''' When this is python3.3, use built in version'''\n    def which(self, program):\n        path=self.env[\"PATH\"]\n        for path in path.split(os.path.pathsep):\n            fullpath=os.path.join(path, program)\n            if os.path.exists(fullpath) and os.access(fullpath,os.X_OK):\n                return fullpath\n        return None\n\nif __name__ == '__main__':\n    try:\n        x = Setup()\n        x.main(sys.argv)\n    except KeyboardInterrupt:\n        logger.warning(\"Aborted by user, will terminate this setup.\")\n        sys.exit(1)\n"
  },
  {
    "path": "bin/test-network.py",
    "content": "#!/usr/bin/env python3\n\n# Copyright (C) 2016-2017 Wind River Systems, Inc.\n#\n# This program is free software; you can redistribute it and/or modify\n# it under the terms of the GNU General Public License version 2 as\n# published by the Free Software Foundation.\n#\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n# See the GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program; if not, write to the Free Software\n# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n\n# Please keep these sorted.\nimport logging\nimport os\nimport sys\nimport argparse\n\nimport logger_setup\n\nlogger = logger_setup.setup_logging()\nlogger.setLevel(logging.DEBUG)\n\n# Redirect stdout and stderr to the custom logger.  This allows us to use\n# python modules that may output only via stdout/stderr.\nsys.stdout = logger_setup.LoggerOut(logger.info)\nsys.stderr = logger_setup.LoggerOut(logger.error)\n\ndef parse_args():\n    parser = argparse.ArgumentParser(description='test-network.py: Application to check network connection ability.')\n\n    # Define arguments\n    parser.add_argument(\"repoURL\", help=\"The repoURL provided by Windshare.\")\n\n    parser.parse_args()\n    return parser.parse_args()\n\ndef dump_proxies():\n    logger.info(\"Checking if proxies are enabled in the environment...\")\n\n    if 'http_proxy' in os.environ:\n        logger.debug(\"http_proxy = %s\" % (os.environ['http_proxy']))\n    else:\n        logger.debug(\"No http_proxy defined.\")\n\n    if 'https_proxy' in os.environ:\n        logger.debug(\"https_proxy = %s\" % (os.environ['https_proxy']))\n    else:\n        logger.debug(\"No https_proxy defined.\")\n\ndef test_windshare(repoUrl):\n    logger.info(\"Running Windshare test based on repoURL: %s\" % repoUrl)\n\n    from windshare import Windshare\n    ws = Windshare(debug=1)\n    ws.interactive = 1\n\n    from urllib.parse import urlsplit, urlunsplit\n\n    (uscheme, uloc, upath, uquery, ufragid) = urlsplit(repoUrl)\n\n    base_folder = os.path.basename(upath)\n\n    if not base_folder or base_folder == \"\":\n        logger.error(\"Invalid URL, unable to determine base_folder\")\n        return\n\n    # Folder root is one directory higher\n    upath = os.path.dirname(upath)\n    base_url = urlunsplit((uscheme, uloc, upath, uquery, ufragid))\n\n    logger.debug(\"BASE URL = %s\" % base_url)\n\n    # Determine if this is a windshare install\n    (ws_base_url, _, ws_entitlement_url) = ws.get_windshare_urls(base_url)\n\n    if ws_base_url and ws_base_url != \"\" and ws.load_folders(ws_entitlement_url):\n        logger.info('Detected Windshare configuration.  Processing entitlements and indexes.')\n    else:\n        logger.info('Unable to detect Windshare configuration!  No entitlements available.')\n\n    return ws\n\nif __name__ == \"__main__\":\n    args = parse_args()\n\n    logger.info(\"------------- Environment Information --------------\")\n    logger.info(sys.version)\n    logger.plain(\"\")\n\n    logger.info(\"---------------- Proxy Information -----------------\")\n    dump_proxies()\n    logger.plain(\"\")\n\n    if args.repoURL:\n        logger.info(\"-------------- Windshare Information ---------------\")\n        windshare = test_windshare(args.repoURL)\n        logger.plain(\"\")\n\n        logger.info(\"------------- Available Entitlements ---------------\")\n        for folder in windshare.folders or [ 'none (Unable to load Windshare data)' ]:\n            logger.info('    %s' % folder)\n        logger.plain(\"\")\n"
  },
  {
    "path": "bin/texttable.py",
    "content": "# texttable - module for creating simple ASCII tables\n# Copyright (C) 2003-2018 Gerome Fournier <jef(at)foutaise.org>\n\n\"\"\"module for creating simple ASCII tables\n\n\nExample:\n\n    table = Texttable()\n    table.set_cols_align([\"l\", \"r\", \"c\"])\n    table.set_cols_valign([\"t\", \"m\", \"b\"])\n    table.add_rows([[\"Name\", \"Age\", \"Nickname\"],\n                    [\"Mr\\\\nXavier\\\\nHuon\", 32, \"Xav'\"],\n                    [\"Mr\\\\nBaptiste\\\\nClement\", 1, \"Baby\"],\n                    [\"Mme\\\\nLouise\\\\nBourgeau\", 28, \"Lou\\\\n\\\\nLoue\"]])\n    print table.draw() + \"\\\\n\"\n\n    table = Texttable()\n    table.set_deco(Texttable.HEADER)\n    table.set_cols_dtype(['t',  # text\n                          'f',  # float (decimal)\n                          'e',  # float (exponent)\n                          'i',  # integer\n                          'a']) # automatic\n    table.set_cols_align([\"l\", \"r\", \"r\", \"r\", \"l\"])\n    table.add_rows([[\"text\",    \"float\", \"exp\", \"int\", \"auto\"],\n                    [\"abcd\",    \"67\",    654,   89,    128.001],\n                    [\"efghijk\", 67.5434, .654,  89.6,  12800000000000000000000.00023],\n                    [\"lmn\",     5e-78,   5e-78, 89.4,  .000000000000128],\n                    [\"opqrstu\", .023,    5e+78, 92.,   12800000000000000000000]])\n    print table.draw()\n\nResult:\n\n    +----------+-----+----------+\n    |   Name   | Age | Nickname |\n    +==========+=====+==========+\n    | Mr       |     |          |\n    | Xavier   |  32 |          |\n    | Huon     |     |   Xav'   |\n    +----------+-----+----------+\n    | Mr       |     |          |\n    | Baptiste |   1 |          |\n    | Clement  |     |   Baby   |\n    +----------+-----+----------+\n    | Mme      |     |   Lou    |\n    | Louise   |  28 |          |\n    | Bourgeau |     |   Loue   |\n    +----------+-----+----------+\n\n    text   float       exp      int     auto\n    ===========================================\n    abcd   67.000   6.540e+02   89    128.001\n    efgh   67.543   6.540e-01   90    1.280e+22\n    ijkl   0.000    5.000e-78   89    0.000\n    mnop   0.023    5.000e+78   92    1.280e+22\n\"\"\"\n\nfrom __future__ import division\n\n__all__ = [\"Texttable\", \"ArraySizeError\"]\n\n__author__ = 'Gerome Fournier <jef(at)foutaise.org>'\n__license__ = 'MIT'\n__version__ = '1.6.1'\n__credits__ = \"\"\"\\\nJeff Kowalczyk:\n    - textwrap improved import\n    - comment concerning header output\n\nAnonymous:\n    - add_rows method, for adding rows in one go\n\nSergey Simonenko:\n    - redefined len() function to deal with non-ASCII characters\n\nRoger Lew:\n    - columns datatype specifications\n\nBrian Peterson:\n    - better handling of unicode errors\n\nFrank Sachsenheim:\n    - add Python 2/3-compatibility\n\nMaximilian Hils:\n    - fix minor bug for Python 3 compatibility\n\nfrinkelpi:\n    - preserve empty lines\n\"\"\"\n\nimport sys\nimport unicodedata\n\n# define a text wrapping function to wrap some text\n# to a specific width:\n# - use cjkwrap if available (better CJK support)\n# - fallback to textwrap otherwise\ntry:\n    import cjkwrap\n    def textwrapper(txt, width):\n        return cjkwrap.wrap(txt, width)\nexcept ImportError:\n    try:\n        import textwrap\n        def textwrapper(txt, width):\n            return textwrap.wrap(txt, width)\n    except ImportError:\n        sys.stderr.write(\"Can't import textwrap module!\\n\")\n        raise\n\n# define a function to calculate the rendering width of a unicode character\n# - use wcwidth if available\n# - fallback to unicodedata information otherwise\ntry:\n    import wcwidth\n    def uchar_width(c):\n        \"\"\"Return the rendering width of a unicode character\n        \"\"\"\n        return max(0, wcwidth.wcwidth(c))\nexcept ImportError:\n    def uchar_width(c):\n        \"\"\"Return the rendering width of a unicode character\n        \"\"\"\n        if unicodedata.east_asian_width(c) in 'WF':\n            return 2\n        elif unicodedata.combining(c):\n            return 0\n        else:\n            return 1\n\nfrom functools import reduce\n\nif sys.version_info >= (3, 0):\n    unicode_type = str\n    bytes_type = bytes\nelse:\n    unicode_type = unicode\n    bytes_type = str\n\n\ndef obj2unicode(obj):\n    \"\"\"Return a unicode representation of a python object\n    \"\"\"\n    if isinstance(obj, unicode_type):\n        return obj\n    elif isinstance(obj, bytes_type):\n        try:\n            return unicode_type(obj, 'utf-8')\n        except UnicodeDecodeError as strerror:\n            sys.stderr.write(\"UnicodeDecodeError exception for string '%s': %s\\n\" % (obj, strerror))\n            return unicode_type(obj, 'utf-8', 'replace')\n    else:\n        return unicode_type(obj)\n\n\ndef len(iterable):\n    \"\"\"Redefining len here so it will be able to work with non-ASCII characters\n    \"\"\"\n    if isinstance(iterable, bytes_type) or isinstance(iterable, unicode_type):\n        return sum([uchar_width(c) for c in obj2unicode(iterable)])\n    else:\n        return iterable.__len__()\n\n\nclass ArraySizeError(Exception):\n    \"\"\"Exception raised when specified rows don't fit the required size\n    \"\"\"\n\n    def __init__(self, msg):\n        self.msg = msg\n        Exception.__init__(self, msg, '')\n\n    def __str__(self):\n        return self.msg\n\n\nclass FallbackToText(Exception):\n    \"\"\"Used for failed conversion to float\"\"\"\n    pass\n\n\nclass Texttable:\n\n    BORDER = 1\n    HEADER = 1 << 1\n    HLINES = 1 << 2\n    VLINES = 1 << 3\n\n    def __init__(self, max_width=80):\n        \"\"\"Constructor\n\n        - max_width is an integer, specifying the maximum width of the table\n        - if set to 0, size is unlimited, therefore cells won't be wrapped\n        \"\"\"\n\n        self.set_max_width(max_width)\n        self._precision = 3\n\n        self._deco = Texttable.VLINES | Texttable.HLINES | Texttable.BORDER | \\\n            Texttable.HEADER\n        self.set_chars(['-', '|', '+', '='])\n        self.reset()\n\n    def reset(self):\n        \"\"\"Reset the instance\n\n        - reset rows and header\n        \"\"\"\n\n        self._hline_string = None\n        self._row_size = None\n        self._header = []\n        self._rows = []\n        return self\n\n    def set_max_width(self, max_width):\n        \"\"\"Set the maximum width of the table\n\n        - max_width is an integer, specifying the maximum width of the table\n        - if set to 0, size is unlimited, therefore cells won't be wrapped\n        \"\"\"\n        self._max_width = max_width if max_width > 0 else False\n        return self\n\n    def set_chars(self, array):\n        \"\"\"Set the characters used to draw lines between rows and columns\n\n        - the array should contain 4 fields:\n\n            [horizontal, vertical, corner, header]\n\n        - default is set to:\n\n            ['-', '|', '+', '=']\n        \"\"\"\n\n        if len(array) != 4:\n            raise ArraySizeError(\"array should contain 4 characters\")\n        array = [ x[:1] for x in [ str(s) for s in array ] ]\n        (self._char_horiz, self._char_vert,\n            self._char_corner, self._char_header) = array\n        return self\n\n    def set_deco(self, deco):\n        \"\"\"Set the table decoration\n\n        - 'deco' can be a combinaison of:\n\n            Texttable.BORDER: Border around the table\n            Texttable.HEADER: Horizontal line below the header\n            Texttable.HLINES: Horizontal lines between rows\n            Texttable.VLINES: Vertical lines between columns\n\n           All of them are enabled by default\n\n        - example:\n\n            Texttable.BORDER | Texttable.HEADER\n        \"\"\"\n\n        self._deco = deco\n        return self\n\n    def set_header_align(self, array):\n        \"\"\"Set the desired header alignment\n\n        - the elements of the array should be either \"l\", \"c\" or \"r\":\n\n            * \"l\": column flushed left\n            * \"c\": column centered\n            * \"r\": column flushed right\n        \"\"\"\n\n        self._check_row_size(array)\n        self._header_align = array\n        return self\n\n    def set_cols_align(self, array):\n        \"\"\"Set the desired columns alignment\n\n        - the elements of the array should be either \"l\", \"c\" or \"r\":\n\n            * \"l\": column flushed left\n            * \"c\": column centered\n            * \"r\": column flushed right\n        \"\"\"\n\n        self._check_row_size(array)\n        self._align = array\n        return self\n\n    def set_cols_valign(self, array):\n        \"\"\"Set the desired columns vertical alignment\n\n        - the elements of the array should be either \"t\", \"m\" or \"b\":\n\n            * \"t\": column aligned on the top of the cell\n            * \"m\": column aligned on the middle of the cell\n            * \"b\": column aligned on the bottom of the cell\n        \"\"\"\n\n        self._check_row_size(array)\n        self._valign = array\n        return self\n\n    def set_cols_dtype(self, array):\n        \"\"\"Set the desired columns datatype for the cols.\n\n        - the elements of the array should be either a callable or any of\n          \"a\", \"t\", \"f\", \"e\" or \"i\":\n\n            * \"a\": automatic (try to use the most appropriate datatype)\n            * \"t\": treat as text\n            * \"f\": treat as float in decimal format\n            * \"e\": treat as float in exponential format\n            * \"i\": treat as int\n            * a callable: should return formatted string for any value given\n\n        - by default, automatic datatyping is used for each column\n        \"\"\"\n\n        self._check_row_size(array)\n        self._dtype = array\n        return self\n\n    def set_cols_width(self, array):\n        \"\"\"Set the desired columns width\n\n        - the elements of the array should be integers, specifying the\n          width of each column. For example:\n\n                [10, 20, 5]\n        \"\"\"\n\n        self._check_row_size(array)\n        try:\n            array = list(map(int, array))\n            if reduce(min, array) <= 0:\n                raise ValueError\n        except ValueError:\n            sys.stderr.write(\"Wrong argument in column width specification\\n\")\n            raise\n        self._width = array\n        return self\n\n    def set_precision(self, width):\n        \"\"\"Set the desired precision for float/exponential formats\n\n        - width must be an integer >= 0\n\n        - default value is set to 3\n        \"\"\"\n\n        if not type(width) is int or width < 0:\n            raise ValueError('width must be an integer greater then 0')\n        self._precision = width\n        return self\n\n    def header(self, array):\n        \"\"\"Specify the header of the table\n        \"\"\"\n\n        self._check_row_size(array)\n        self._header = list(map(obj2unicode, array))\n        return self\n\n    def add_row(self, array):\n        \"\"\"Add a row in the rows stack\n\n        - cells can contain newlines and tabs\n        \"\"\"\n\n        self._check_row_size(array)\n\n        if not hasattr(self, \"_dtype\"):\n            self._dtype = [\"a\"] * self._row_size\n\n        cells = []\n        for i, x in enumerate(array):\n            cells.append(self._str(i, x))\n        self._rows.append(cells)\n        return self\n\n    def add_rows(self, rows, header=True):\n        \"\"\"Add several rows in the rows stack\n\n        - The 'rows' argument can be either an iterator returning arrays,\n          or a by-dimensional array\n        - 'header' specifies if the first row should be used as the header\n          of the table\n        \"\"\"\n\n        # nb: don't use 'iter' on by-dimensional arrays, to get a\n        #     usable code for python 2.1\n        if header:\n            if hasattr(rows, '__iter__') and hasattr(rows, 'next'):\n                self.header(rows.next())\n            else:\n                self.header(rows[0])\n                rows = rows[1:]\n        for row in rows:\n            self.add_row(row)\n        return self\n\n    def draw(self):\n        \"\"\"Draw the table\n\n        - the table is returned as a whole string\n        \"\"\"\n\n        if not self._header and not self._rows:\n            return\n        self._compute_cols_width()\n        self._check_align()\n        out = \"\"\n        if self._has_border():\n            out += self._hline()\n        if self._header:\n            out += self._draw_line(self._header, isheader=True)\n            if self._has_header():\n                out += self._hline_header()\n        length = 0\n        for row in self._rows:\n            length += 1\n            out += self._draw_line(row)\n            if self._has_hlines() and length < len(self._rows):\n                out += self._hline()\n        if self._has_border():\n            out += self._hline()\n        return out[:-1]\n\n    @classmethod\n    def _to_float(cls, x):\n        if x is None:\n            raise FallbackToText()\n        try:\n            return float(x)\n        except (TypeError, ValueError):\n            raise FallbackToText()\n\n    @classmethod\n    def _fmt_int(cls, x, **kw):\n        \"\"\"Integer formatting class-method.\n\n        - x will be float-converted and then used.\n        \"\"\"\n        return str(int(round(cls._to_float(x))))\n\n    @classmethod\n    def _fmt_float(cls, x, **kw):\n        \"\"\"Float formatting class-method.\n\n        - x parameter is ignored. Instead kw-argument f being x float-converted\n          will be used.\n\n        - precision will be taken from `n` kw-argument.\n        \"\"\"\n        n = kw.get('n')\n        return '%.*f' % (n, cls._to_float(x))\n\n    @classmethod\n    def _fmt_exp(cls, x, **kw):\n        \"\"\"Exponential formatting class-method.\n\n        - x parameter is ignored. Instead kw-argument f being x float-converted\n          will be used.\n\n        - precision will be taken from `n` kw-argument.\n        \"\"\"\n        n = kw.get('n')\n        return '%.*e' % (n, cls._to_float(x))\n\n    @classmethod\n    def _fmt_text(cls, x, **kw):\n        \"\"\"String formatting class-method.\"\"\"\n        return obj2unicode(x)\n\n    @classmethod\n    def _fmt_auto(cls, x, **kw):\n        \"\"\"auto formatting class-method.\"\"\"\n        f = cls._to_float(x)\n        if abs(f) > 1e8:\n            fn = cls._fmt_exp\n        else:\n            if f - round(f) == 0:\n                fn = cls._fmt_int\n            else:\n                fn = cls._fmt_float\n        return fn(x, **kw)\n\n    def _str(self, i, x):\n        \"\"\"Handles string formatting of cell data\n\n            i - index of the cell datatype in self._dtype\n            x - cell data to format\n        \"\"\"\n        FMT = {\n            'a':self._fmt_auto,\n            'i':self._fmt_int,\n            'f':self._fmt_float,\n            'e':self._fmt_exp,\n            't':self._fmt_text,\n            }\n\n        n = self._precision\n        dtype = self._dtype[i]\n        try:\n            if callable(dtype):\n                return dtype(x)\n            else:\n                return FMT[dtype](x, n=n)\n        except FallbackToText:\n            return self._fmt_text(x)\n\n    def _check_row_size(self, array):\n        \"\"\"Check that the specified array fits the previous rows size\n        \"\"\"\n\n        if not self._row_size:\n            self._row_size = len(array)\n        elif self._row_size != len(array):\n            raise ArraySizeError(\"array should contain %d elements\" \\\n                % self._row_size)\n\n    def _has_vlines(self):\n        \"\"\"Return a boolean, if vlines are required or not\n        \"\"\"\n\n        return self._deco & Texttable.VLINES > 0\n\n    def _has_hlines(self):\n        \"\"\"Return a boolean, if hlines are required or not\n        \"\"\"\n\n        return self._deco & Texttable.HLINES > 0\n\n    def _has_border(self):\n        \"\"\"Return a boolean, if border is required or not\n        \"\"\"\n\n        return self._deco & Texttable.BORDER > 0\n\n    def _has_header(self):\n        \"\"\"Return a boolean, if header line is required or not\n        \"\"\"\n\n        return self._deco & Texttable.HEADER > 0\n\n    def _hline_header(self):\n        \"\"\"Print header's horizontal line\n        \"\"\"\n\n        return self._build_hline(True)\n\n    def _hline(self):\n        \"\"\"Print an horizontal line\n        \"\"\"\n\n        if not self._hline_string:\n            self._hline_string = self._build_hline()\n        return self._hline_string\n\n    def _build_hline(self, is_header=False):\n        \"\"\"Return a string used to separated rows or separate header from\n        rows\n        \"\"\"\n        horiz = self._char_horiz\n        if (is_header):\n            horiz = self._char_header\n        # compute cell separator\n        s = \"%s%s%s\" % (horiz, [horiz, self._char_corner][self._has_vlines()],\n            horiz)\n        # build the line\n        l = s.join([horiz * n for n in self._width])\n        # add border if needed\n        if self._has_border():\n            l = \"%s%s%s%s%s\\n\" % (self._char_corner, horiz, l, horiz,\n                self._char_corner)\n        else:\n            l += \"\\n\"\n        return l\n\n    def _len_cell(self, cell):\n        \"\"\"Return the width of the cell\n\n        Special characters are taken into account to return the width of the\n        cell, such like newlines and tabs\n        \"\"\"\n\n        cell_lines = cell.split('\\n')\n        maxi = 0\n        for line in cell_lines:\n            length = 0\n            parts = line.split('\\t')\n            for part, i in zip(parts, list(range(1, len(parts) + 1))):\n                length = length + len(part)\n                if i < len(parts):\n                    length = (length//8 + 1) * 8\n            maxi = max(maxi, length)\n        return maxi\n\n    def _compute_cols_width(self):\n        \"\"\"Return an array with the width of each column\n\n        If a specific width has been specified, exit. If the total of the\n        columns width exceed the table desired width, another width will be\n        computed to fit, and cells will be wrapped.\n        \"\"\"\n\n        if hasattr(self, \"_width\"):\n            return\n        maxi = []\n        if self._header:\n            maxi = [ self._len_cell(x) for x in self._header ]\n        for row in self._rows:\n            for cell,i in zip(row, list(range(len(row)))):\n                try:\n                    maxi[i] = max(maxi[i], self._len_cell(cell))\n                except (TypeError, IndexError):\n                    maxi.append(self._len_cell(cell))\n\n        ncols = len(maxi)\n        content_width = sum(maxi)\n        deco_width = 3*(ncols-1) + [0,4][self._has_border()]\n        if self._max_width and (content_width + deco_width) > self._max_width:\n            \"\"\" content too wide to fit the expected max_width\n            let's recompute maximum cell width for each cell\n            \"\"\"\n            if self._max_width < (ncols + deco_width):\n                raise ValueError('max_width too low to render data')\n            available_width = self._max_width - deco_width\n            newmaxi = [0] * ncols\n            i = 0\n            while available_width > 0:\n                if newmaxi[i] < maxi[i]:\n                    newmaxi[i] += 1\n                    available_width -= 1\n                i = (i + 1) % ncols\n            maxi = newmaxi\n        self._width = maxi\n\n    def _check_align(self):\n        \"\"\"Check if alignment has been specified, set default one if not\n        \"\"\"\n\n        if not hasattr(self, \"_header_align\"):\n            self._header_align = [\"c\"] * self._row_size\n        if not hasattr(self, \"_align\"):\n            self._align = [\"l\"] * self._row_size\n        if not hasattr(self, \"_valign\"):\n            self._valign = [\"t\"] * self._row_size\n\n    def _draw_line(self, line, isheader=False):\n        \"\"\"Draw a line\n\n        Loop over a single cell length, over all the cells\n        \"\"\"\n\n        line = self._splitit(line, isheader)\n        space = \" \"\n        out = \"\"\n        for i in range(len(line[0])):\n            if self._has_border():\n                out += \"%s \" % self._char_vert\n            length = 0\n            for cell, width, align in zip(line, self._width, self._align):\n                length += 1\n                cell_line = cell[i]\n                fill = width - len(cell_line)\n                if isheader:\n                    align = self._header_align[length - 1]\n                if align == \"r\":\n                    out += fill * space + cell_line\n                elif align == \"c\":\n                    out += (int(fill/2) * space + cell_line \\\n                            + int(fill/2 + fill%2) * space)\n                else:\n                    out += cell_line + fill * space\n                if length < len(line):\n                    out += \" %s \" % [space, self._char_vert][self._has_vlines()]\n            out += \"%s\\n\" % ['', space + self._char_vert][self._has_border()]\n        return out\n\n    def _splitit(self, line, isheader):\n        \"\"\"Split each element of line to fit the column width\n\n        Each element is turned into a list, result of the wrapping of the\n        string to the desired width\n        \"\"\"\n\n        line_wrapped = []\n        for cell, width in zip(line, self._width):\n            array = []\n            for c in cell.split('\\n'):\n                if c.strip() == \"\":\n                    array.append(\"\")\n                else:\n                    array.extend(textwrapper(c, width))\n            line_wrapped.append(array)\n        max_cell_lines = reduce(max, list(map(len, line_wrapped)))\n        for cell, valign in zip(line_wrapped, self._valign):\n            if isheader:\n                valign = \"t\"\n            if valign == \"m\":\n                missing = max_cell_lines - len(cell)\n                cell[:0] = [\"\"] * int(missing / 2)\n                cell.extend([\"\"] * int(missing / 2 + missing % 2))\n            elif valign == \"b\":\n                cell[:0] = [\"\"] * (max_cell_lines - len(cell))\n            else:\n                cell.extend([\"\"] * (max_cell_lines - len(cell)))\n        return line_wrapped\n\n\nif __name__ == '__main__':\n    table = Texttable()\n    table.set_cols_align([\"l\", \"r\", \"c\"])\n    table.set_cols_valign([\"t\", \"m\", \"b\"])\n    table.add_rows([[\"Name\", \"Age\", \"Nickname\"],\n                    [\"Mr\\nXavier\\nHuon\", 32, \"Xav'\"],\n                    [\"Mr\\nBaptiste\\nClement\", 1, \"Baby\"],\n                    [\"Mme\\nLouise\\nBourgeau\", 28, \"Lou\\n \\nLoue\"]])\n    print(table.draw() + \"\\n\")\n\n    table = Texttable()\n    table.set_deco(Texttable.HEADER)\n    table.set_cols_dtype(['t',  # text\n                          'f',  # float (decimal)\n                          'e',  # float (exponent)\n                          'i',  # integer\n                          'a']) # automatic\n    table.set_cols_align([\"l\", \"r\", \"r\", \"r\", \"l\"])\n    table.add_rows([[\"text\",    \"float\", \"exp\", \"int\", \"auto\"],\n                    [\"abcd\",    \"67\",    654,   89,    128.001],\n                    [\"efghijk\", 67.5434, .654,  89.6,  12800000000000000000000.00023],\n                    [\"lmn\",     5e-78,   5e-78, 89.4,  .000000000000128],\n                    [\"opqrstu\", .023,    5e+78, 92.,   12800000000000000000000]])\n    print(table.draw())\n"
  },
  {
    "path": "bin/toaster_fixture.py",
    "content": "#!/usr/bin/env python3\n\n# Copyright (C) 2017 Wind River Systems, Inc.\n#\n# This program is free software; you can redistribute it and/or modify\n# it under the terms of the GNU General Public License version 2 as\n# published by the Free Software Foundation.\n#\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n# See the GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program; if not, write to the Free Software\n# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n\nimport argparse\nimport json\nimport os\nimport sys\nimport xml.etree.ElementTree as ET\nfrom xml.dom import minidom\nimport re\n\n#\n# TODO\n# - Multiple Indexes\n# - Multiple bitbakes\n# - Multiple remotes\n#\n\n# Get the 'setup.py' default settings (BASE_LAYERS, DEFAULT_DISTRO, ...)\nimport settings\n\n# Global variables\ntop_layers=[]   # list of top layers\nlist_layers=[]  # list of top and dependent layers\njson_dct={}     # layer index json cache\nxmltree=None    # default.xml object\n\n# Add 'layer index' type layer_branch records\nTYPE_LAYERINDEX = 1\n\n# Insert custom settings starting at 100\nCUSTOM_SETTINGS_BASE=100\n\n# Toaster fixture file's relative path from install directory\nFIXTURE_FILE='layers/oe-core/bitbake/lib/toaster/orm/fixtures/custom.xml'\n\n# Do not include optional layers in default layer list\nINCLUDE_DEFAULT_LAYERS=False\n\n############################################\n### formatted output\n\ndef add_field(obj,attr_list,value):\n    field = ET.SubElement(obj, \"field\")\n    for attr in attr_list:\n        field.set(attr[0], attr[1])\n    field.text = value\n\ndef write_prolog():\n    global root\n    root = ET.Element(\"django-objects\")\n    root.set('version', '1.0')\n\ndef append_setting(name,value,pk):\n    global root\n    obj = ET.SubElement(root, \"object\")\n    obj.set('model', 'orm.toastersetting')\n    obj.set('pk', str(pk))\n    add_field(obj,[('type','CharField'),('name', 'name')],name)\n    add_field(obj,[('type','CharField'),('name', 'value')],value)\n    return pk+1\n\ndef append_bitbake(name,giturl,branch,pk):\n    global root\n    obj = ET.SubElement(root, \"object\")\n    obj.set('model', 'orm.bitbakeversion')\n    obj.set('pk', str(pk))\n    add_field(obj,[('type','CharField'),('name', 'name')],name)\n    add_field(obj,[('type','CharField'),('name', 'giturl')],giturl)\n    add_field(obj,[('type','CharField'),('name', 'branch')],branch)\n    add_field(obj,[('type','CharField'),('name', 'dirpath')],'')\n    return pk+1\n\ndef append_releases(name,desc,bitbake_version,branch,help):\n    global root\n    obj = ET.SubElement(root, \"object\")\n    obj.set('model', 'orm.release')\n    obj.set('pk', '1')\n    add_field(obj,[('type','CharField'),('name', 'name')],name)\n    add_field(obj,[('type','CharField'),('name', 'description')],desc)\n    add_field(obj,[('rel','ManyToOneRel'),('to','orm.bitbakeversion'),('name', 'bitbake_version')],str(bitbake_version))\n    add_field(obj,[('type','CharField'),('name', 'branch_name')],branch)\n    add_field(obj,[('type','TextField'),('name', 'helptext')],help)\n\ndef write_default_layer_release(release,pk):\n    global root\n    for layer in list_layers:\n        obj = ET.SubElement(root, \"object\")\n        obj.set('model', 'orm.releasedefaultlayer')\n        obj.set('pk', str(pk))\n        add_field(obj,[('rel','ManyToOneRel'),('to','orm.release'),('name', 'release')],str(release))\n        add_field(obj,[('type','CharField'),('name', 'layer_name')],layer)\n        pk += 1\n    return pk\n\ndef write_layer_release(layer_pk,layer_version_pk,layer_source):\n    global root\n    layers = json_dct[\"layerItems\"]\n    for layer_name in list_layers:\n        for layer in layers:\n            if layer_name == layer[\"name\"]:\n                break\n        else:\n            print(\"ERROR: Layer Name '%s' in not found\" % layer_name)\n            return\n        obj = ET.SubElement(root, \"object\")\n        obj.set('model', 'orm.layer')\n        obj.set('pk', str(layer_pk))\n        add_field(obj,[('type','CharField'),('name', 'name')],layer['name'])\n        add_field(obj,[('type','CharField'),('name', 'layer_index_url')],'')\n        add_field(obj,[('type','CharField'),('name', 'vcs_url')],layer['vcs_url'])\n\n        # for release in releases:\n        layer_id=layer[\"id\"]\n        for release in range(1, 2):\n            layerBranches = json_dct[\"layerBranches\"]\n            for layer_branch in layerBranches:\n                if layer_id == layer_branch[\"layer\"]:\n                    break\n            else:\n                print(\"ERROR: LayerId '%d' in layerBranches not found\" % layer_id)\n                return\n            obj = ET.SubElement(root, \"object\")\n            obj.set('model', 'orm.layer_version')\n            obj.set('pk', str(layer_version_pk))\n            add_field(obj,[('rel','ManyToOneRel'),('to','orm.layer'),('name', 'layer')],str(layer_pk))\n            add_field(obj,[('type','IntegerField'),('name', 'layer_source')],str(layer_source))\n            add_field(obj,[('rel','ManyToOneRel'),('to','orm.release'),('name', 'release')],str(release))\n            add_field(obj,[('type','CharField'),('name', 'branch')],layer_branch['actual_branch'])\n            add_field(obj,[('type','CharField'),('name', 'dirpath')],layer_branch['vcs_subdir'])\n            layer_version_pk+=1\n        layer_pk+=1\n    return layer_pk,layer_version_pk\n\ndef write_epilog():\n    parsed = minidom.parseString(ET.tostring(root, 'utf-8'))\n    print(parsed.toprettyxml(indent=\"  \"),file=output_fd)\n\n############################################\n### worker functions\n\ndef read_default_xml(xml_file):\n    xmltree = ET.parse(xml_file)\n    xmlroot = xmltree.getroot()\n    remote_base=None\n    remote_base_revision=None\n    bitbake_branch=None\n    bitbake_path=None\n    for child in xmlroot:\n        if 'remote' == child.tag and 'base' == child.attrib['name']:\n            remote_base_fetch = child.attrib['fetch']\n        if 'default' == child.tag and 'base' == child.attrib['remote']:\n            remote_base_revision = child.attrib['revision']\n        if 'default' == child.tag and 'base' == child.attrib['remote']:\n            remote_base_revision = child.attrib['revision']\n        if 'project' == child.tag and child.attrib['name'].endswith('bitbake'):\n            bitbake_branch = child.attrib['revision']\n            bitbake_path=child.attrib['name']\n    return remote_base_fetch,remote_base_revision,bitbake_branch,bitbake_path\n\ndef read_layer_index_cache(json_cache):\n    global json_dct\n    with open(json_cache,\"r\") as json_data:\n        json_dct = json.load(json_data)\n\ndef find_layer2id(layer_name):\n    layers = json_dct[\"layerItems\"]\n    for layer in layers:\n        if layer_name == layer[\"name\"]:\n            return layer[\"id\"]\n    return None\n\ndef find_id2layer(layer_id):\n    layers = json_dct[\"layerItems\"]\n    for layer in layers:\n        if layer_id == layer[\"id\"]:\n            return layer[\"name\"]\n    return None\n\ndef find_layerBranch2layer(layerBranch_id):\n    layers = json_dct[\"layerItems\"]\n    layerBranches = json_dct[\"layerBranches\"]\n    for layerBranch in layerBranches:\n        if layerBranch_id == layerBranch[\"id\"]:\n            layer_id=layerBranch[\"layer\"]\n            for layer in layers:\n                if layer_id == layer[\"id\"]:\n                    return layer[\"name\"]\n    return None\n\ndef find_layer2layerBranch(layer):\n    layerBranches = json_dct[\"layerBranches\"]\n    layer_id=find_layer2id(layer)\n    if None == layer_id:\n        print(\"ERROR: Index for layer '%s' not found\" % add_layer)\n        return None\n    for layerBranch in layerBranches:\n        if layer_id == layerBranch[\"layer\"]:\n            layer_branch_id=layerBranch[\"id\"]\n            break\n    else:\n        print(\"ERROR: layerbranch layer '%d' not found\" % layer_id)\n        return None\n    return layer_id,layer_branch_id\n\ndef add_machine_layers(add_machine):\n    global top_layers\n    machines = json_dct[\"machines\"]\n    for machine in machines:\n        if add_machine == machine[\"name\"]:\n            layerBranch_id = machine[\"layerbranch\"]\n            layer = find_layerBranch2layer(layerBranch_id)\n            if None == layer:\n                print(\"ERROR: Layer '%s' for machine '%s' not found\" % (layer,add_machine))\n            else:\n                top_layers.append(layer)\n\ndef add_distro_layers(add_distro):\n    global top_layers\n    distros = json_dct[\"distros\"]\n    for distro in distros:\n        if add_distro == distro[\"name\"]:\n            layerBranch_id = distro[\"layerbranch\"]\n            layer = find_layerBranch2layer(layerBranch_id)\n            if None == layer:\n                print(\"ERROR: Layer '%s' for distro '%s' not found\" % (layer,add_distro))\n            else:\n                top_layers.append(layer)\n\ndef add_dependent_layers(add_layer,include_optional):\n    global list_layers\n    layers = json_dct[\"layerItems\"]\n    layerBranches = json_dct[\"layerBranches\"]\n    layerDependencies = json_dct[\"layerDependencies\"]\n\n    # do we already have this layer?\n    if add_layer in list_layers:\n        return\n\n    # find layer ID\n    layer_id,layer_branch_id = find_layer2layerBranch(add_layer)\n    # find dependent layers\n    for dep in layerDependencies:\n        if not include_optional and not dep['required']:\n            continue\n        if layer_branch_id == dep['layerbranch']:\n            dep_layer=find_id2layer(dep[\"dependency\"])\n            if None == dep_layer:\n                print(\"ERROR: Index to dep layer '%d' not found\" % dep_id)\n            else:\n                add_dependent_layers(dep_layer,include_optional)\n\n    # add layers depth first, top last\n    list_layers.append(add_layer)\n\n############################################\n### main()\n\ndef main(argv):\n    global top_layers\n    global list_layers\n    global output_fd\n    global root\n\n    parser = argparse.ArgumentParser(description='toaster_fixture.py: create Toaster fixture file from setup output')\n    parser.add_argument('--project-dir', dest='project_dir',help='Project Directory')\n    parser.add_argument('--verbose', '-v', action='store_true', dest='verbose',help='Verbose mode')\n    args = parser.parse_args()\n\n    # Core paths\n    script_dir=os.path.dirname(os.path.abspath(argv[0]))\n    wrlinux_dir=os.path.dirname(script_dir)\n    if args.project_dir:\n        install_dir = args.project_dir\n    else:\n        install_dir = os.getcwd()\n\n    # Read setup default.xml data\n    default_xml_file=os.path.join(install_dir,'default.xml')\n    if not os.path.exists(default_xml_file):\n        print(\"ERROR: 'default.xml' does not exist. You need to run the 'setup' program.\")\n        exit(-1)\n    else:\n        remote_base_fetch,remote_base_revision,bitbake_branch,bitbake_path=read_default_xml(default_xml_file)\n        bitbake_url=os.path.join(remote_base_fetch,bitbake_path)\n\n    # Load layer index cache\n    json_cache=os.path.join(install_dir,settings.INDEXES[0]['CACHE']+'.json')\n    read_layer_index_cache(json_cache)\n\n    # Discover the XML directory\n    xml_dir=os.path.join(wrlinux_dir,'data/xml')\n    if os.path.exists(os.path.join(install_dir,'config','mirror-index','xml')):\n        xml_dir=os.path.join(install_dir,'config','mirror-index','xml')\n\n    # Prepare the output file\n    output_fd=open(os.path.join(install_dir,FIXTURE_FILE), 'w')\n    write_prolog()\n\n    # Write Toaster environment hints\n    #   1. Point Toaster to the wrlinux-x directory\n    root.append(ET.Comment(' HINT:WRLINUX_DIR=\"%s\" ' % wrlinux_dir))\n\n    # Write default setting overrides\n    root.append(ET.Comment(' Set the project default values '))\n\n    append_setting('DEFCONF_DISTRO',settings.DEFAULT_DISTRO,1)\n    append_setting('DEFAULT_RELEASE',remote_base_revision,2)\n    append_setting('DEFCONF_MACHINE',settings.DEFAULT_MACHINE,4)\n    # append custom settings\n    setting_pk=CUSTOM_SETTINGS_BASE\n    setting_pk=append_setting('DEFCONF_LINUX_KERNEL_TYPE','standard',setting_pk)\n    setting_pk=append_setting('DEFAULT_KTYPE_LIST','standard preempt-rt tiny',setting_pk)\n    setting_pk=append_setting('CUSTOM_LAYERINDEX_SERVER','file://'+json_cache,setting_pk)\n    setting_pk=append_setting('SETUP_XMLDIR',xml_dir,setting_pk)\n    setting_pk=append_setting('SETUP_GITURL',remote_base_fetch,setting_pk)\n    setting_pk=append_setting('SETUP_PATH_FILTER','s|layers/[a-zA-Z0-9_\\\\-.]*||',setting_pk)\n\n    # Write bitbake version\n    root.append(ET.Comment(' Bitbake versions which correspond to the metadata release '))\n    bitbake_pk=1\n    bitbake_pk=append_bitbake(remote_base_revision,bitbake_url,bitbake_branch,bitbake_pk)\n\n    # Write releases\n    root.append(ET.Comment(' Releases available '))\n    append_releases(remote_base_revision,\"Wind River Linux \" + remote_base_revision,1,remote_base_revision,\n        \"Toaster will run your builds using the tip of the Wind River Linux '%s' branch.\" % remote_base_revision)\n\n    # Write base default layers\n    for layer in settings.BASE_LAYERS.split():\n        top_layers.append(layer)\n\n    # Write DEFAULT_MACHINE layer\n    add_machine_layers(settings.DEFAULT_MACHINE)\n\n    # Write DEFAULT_DISTRO layer\n    add_distro_layers(settings.DEFAULT_DISTRO)\n\n    # Resolve dependent layers, exclude optional layers\n    for layer in top_layers:\n        add_dependent_layers(layer,INCLUDE_DEFAULT_LAYERS)\n\n    # Write default layer list per release\n    root.append(ET.Comment(' Default project layers for each release '))\n    default_layers_pk=1\n    default_layers_pk=write_default_layer_release(1,default_layers_pk)\n\n    # Write layer list\n    root.append(ET.Comment(' Default layers from wrlinux defaults '))\n    layer_pk,layer_version_pk = write_layer_release(1,1,TYPE_LAYERINDEX)\n\n    write_epilog()\n    output_fd.close()\n\n    if args.verbose:\n        print(\"Done:\")\n        print(\"  Layers=%d, LayerRelease=%d, LayerVersions=%d, Custom Settings=%d\" % (len(list_layers),layer_pk,layer_version_pk,setting_pk-CUSTOM_SETTINGS_BASE))\n        print(\"  Default Layers=%s\" % list_layers)\n\n\nif __name__ == '__main__':\n    main(sys.argv)\n"
  },
  {
    "path": "bin/transform_index.py",
    "content": "#!/usr/bin/env python3\n\n# Copyright (C) 2016 Wind River Systems, Inc.\n#\n# This program is free software; you can redistribute it and/or modify\n# it under the terms of the GNU General Public License version 2 as\n# published by the Free Software Foundation.\n#\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n# See the GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program; if not, write to the Free Software\n# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n\n# This program allows you to transform layer index data from one source\n# to a specific output format.  The output format can be in either restapi\n# or django format.  It can be a single file, or split by layerbranch.\n#\n# You will need to adjust the items below to control the input/output\n#\n# OUTPUT - output directory to write file\n#\n# OUTPUT_FMT - restapi or django -- use Django for dataloads\n#\n# INDEXES - where to pull the data from\n#\n# REPLACES - what replacements to make on the -url- parts\n#\n# SPLIT - True or False, if True split the output\n\n\n# The following will let us load a layer index from one source, and make\n# it so we can load it into another for a stand-a-lone layerindex-Web\n# session.\n#\n# Set OUTPUT_FMT to 'django'\n# Set SPLIT to False\n#\n# Once configured, run the program then follow the steps below...\n#\n# To setup a new layerindex-Web session:\n#\n# git clone git://git.wrs.com/tools/layerindex-web\n# cd layerindex-web\n# virtualenv -p python3 venv\n# . ./venv/bin/activate\n# pip3 install -r requirements.txt\n#\n# (configure settings.py -- see README)\n#   I recommend (adjust paths as necessary):\n#\n#      USE_TZ = True\n#\n#      DEBUG = True\n#\n#      DATABASES = {\n#          'default': {\n#              'ENGINE': 'django.db.backends.sqlite3',\n#              'NAME': '/home/mhatle/git/layerIndex/wr9-db',\n#              'USER': '',\n#              'PASSWORD': '',\n#              'HOST': '',\n#              'PORT': '',\n#          }\n#      }\n#\n#      SECRET_KEY = \"<put something here>\"\n#\n#      LAYER_FETCH_DIR = \"/home/mhatle/git/layerIndex/wr9-layers\"\n#\n#      BITBAKE_REPO_URL = \"git://git.wrs.com/bitbake\"\n#\n#\n# python3 manage.py syncdb\n#   # Answer yes to creating an admin user\n# python3 manage.py migrate\n#\n# cp <OUTPUT>.json layerindex/fixtures/.\n# python3 manage.py loaddata <name>.json\n#\n# To start webserver\n# python3 manage.py runserver\n\n# This can also be used to take a database dump, either from the django DB\n# or from the RestAPI and split the pieces for individual entitlement\n# indexes.\n#\n# To get the input file, in your layerIndex run:\n#   python3 manage.py dumpdata > /tmp/input.json\n#\n# By default the output will be organized by layerbranch in /tmp/output\n#\n# Split the results by base/bsp/addon\n#\n# example:\n#   (cd /tmp/transform ; cp `grep layer_type * | grep -v \\\"B\\\" | cut -f 1 -d :` /home/mhatle/git/lpd/wrlinux-x/data/index/base/.)\n#   (cd /tmp/transform ; cp `grep layer_type * | grep \\\"B\\\" | cut -f 1 -d :` /home/mhatle/git/lpd/wrlinux-x/data/index/bsps/.)\n#\n\n# We load from git.wrs.com and transform to msp-git.wrs.com\n# Adjusting both the git URL and the webgit URL\nREPLACE = [\n            ( 'git://git.wrs.com/', '#BASE_URL#' ),\n            ( 'http://git.wrs.com/cgit/', '#BASE_WEB#' ),\n            ( '#BASE_URL#', 'git://msp-git.wrs.com/' ),\n            ( '#BASE_WEB#', 'http://msp-git.wrs.com/cgi-bin/cgit.cgi/' ),\n          ]\n\n# Note the branch can be hard coded.  This is required only when you want\n# to limit the branch from a restapi-web import.  (This does not do anything\n# on other input formats.)\nINDEXES = [\n    {\n        'DESCRIPTION' : 'Wind River Developer Layer Index',\n        'TYPE' : 'restapi-web',\n        'URL' : 'http://layers.wrs.com/layerindex/api/',\n        'CACHE' : None,\n        'BRANCH' : 'master-wr',\n    },\n]\n\nOUTPUT = '/tmp/transform'\nOUTPUT_FMT = 'django'\n#OUTPUT_FMT = 'restapi'\nSPLIT = False\n\nimport os\nimport sys\n\nfrom layer_index import Layer_Index\n\nindex = Layer_Index(INDEXES, base_branch=None, replace=REPLACE)\n\nfor lindex in index.index:\n    print('Dump %s as %s (split=%s)...' % (lindex['CFG']['DESCRIPTION'], OUTPUT_FMT, SPLIT))\n    os.makedirs(OUTPUT, exist_ok=True)\n    if OUTPUT_FMT == 'django':\n        index.serialize_django_export(lindex, OUTPUT + '/' + lindex['CFG']['DESCRIPTION'], split=SPLIT)\n    elif OUTPUT_FMT == 'restapi':\n        index.serialize_index(lindex, OUTPUT + '/' + lindex['CFG']['DESCRIPTION'], split=SPLIT)\n    else:\n        print('Unknown output format!')\n\n"
  },
  {
    "path": "bin/utils_setup.py",
    "content": "#!/usr/bin/env python3\n\n# Copyright (C) 2016 Wind River Systems, Inc.\n#\n# This program is free software; you can redistribute it and/or modify\n# it under the terms of the GNU General Public License version 2 as\n# published by the Free Software Foundation.\n#\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n# See the GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program; if not, write to the Free Software\n# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n\nimport os\nimport sys\nimport subprocess\n\n# Setup-specific modules\nimport logger_setup\n\nlogger = logger_setup.setup_logging()\n\ndef run_cmd(cmd, environment=None, cwd=None, log=1, expected_ret=0, err=b'GitError', err2=b'error', err3=b'fatal', stderr=None, stdout=None):\n    err_msg = []\n\n    logger.debug('Running cmd: \"%s\"' % repr(cmd))\n    if cwd:\n        logger.debug('From %s' % cwd)\n\n    # log 0 - output goes to stdout/stderr, not logged\n    # log 1 - send output to plain\n    # log 2 - send output to debug\n    if log == 1 or log == 2:\n        if stderr is None:\n            stderr = subprocess.STDOUT\n\n        ret = subprocess.Popen(cmd, env=environment, cwd=cwd, stderr=stderr, stdout=subprocess.PIPE)\n        while True:\n            output = ret.stdout.readline()\n            if not output and ret.poll() is not None:\n                break\n            if output:\n                output = output.strip()\n                if len(err_msg) > 0 or output.startswith(err) or output.startswith(err2) or output.startswith(err3):\n                    err_msg.append(\"%s\" % output.decode('utf-8'))\n                if log == 1:\n                    logger.plain(\"%s\" % output.decode('utf-8'))\n                elif log == 2:\n                    logger.debug(\"%s\" % output.decode('utf-8'))\n    else:\n        logger.debug('output not logged for this command (%s) without verbose flag (-v).' % (cmd))\n        ret = subprocess.Popen(cmd, env=environment, cwd=cwd, close_fds=True, stderr=stderr, stdout=stdout)\n\n    ret.wait()\n    if ret.returncode != expected_ret:\n        if stderr != subprocess.DEVNULL:\n            if environment:\n                for key in environment.keys():\n                    logger.to_file('%20s = %s' % (key, repr(environment[key])))\n            if log != 2:\n                logger.critical('cmd \"%s\" returned %d' % (cmd, ret.returncode))\n            else:\n                logger.debug('cmd \"%s\" returned %d' % (cmd, ret.returncode))\n\n        msg = ''\n        if log:\n            if cwd:\n                msg += cwd + ': '\n            msg += \" \".join(cmd) + '\\n'\n            msg += '\\n'.join(err_msg)\n            msg += '\\n'\n        raise Exception(msg)\n    logger.debug('Finished running cmd: \"%s\"' % repr(cmd))\n\ndef query_input(question, interactive):\n    client = os.environ.get('GIT_ASKPASS', None)\n    if not client:\n        client = os.environ.get('SSH_ASKPASS', None)\n    if not client:\n        if interactive:\n            client = \"[internal]\"\n        else:\n            raise Exception('Unable to get authentication via ASKPASS.')\n\n    cmd = [ client, question ]\n    logger.debug(\"cmd: %s \" % (cmd))\n\n    if cmd[0] == \"[internal]\":\n        import getpass\n        retval = getpass.getpass(cmd[1])\n    else:\n        environ = os.environ.copy()\n\n        # We do NOT want to inherit python home from the environment\n        # See Issue: LIN1018-2934\n        #   python3 wrapper from the buildtools sets this, which causes host\n        #   python tools to fail\n        if 'PYTHONHOME' in environ:\n            del environ['PYTHONHOME']\n\n        ret = subprocess.Popen(cmd, env=environ, close_fds=True, stdout=subprocess.PIPE)\n        retval = \"\"\n        while True:\n            lin = ret.stdout.readline()\n            if not lin and ret.poll() is not None:\n                break\n            retval += lin.decode('utf-8')\n        ret.wait()\n        if ret.returncode != 0:\n            raise Exception('return code != 0 from %s.' % cmd)\n        retval = retval.rstrip('\\n')\n\n    return retval\n\n\ndef fetch_url(url=None, auth=False, debuglevel=0, interactive=0):\n    assert url is not None\n\n    import urllib\n    from urllib.request import urlopen, Request\n    from urllib.parse import urlparse\n\n    if auth:\n        logger.debug(\"Configuring authentication for %s...\" % url)\n\n        up = urlparse(url)\n\n        uname = query_input(\"Username for '%s://%s': \" % (up.scheme, up.netloc), interactive)\n        passwd = query_input(\"Password for '%s://%s@%s': \" % (up.scheme, uname, up.netloc), interactive)\n\n        # This is a security leak, as the username/password could be logged.\n        # Only enable this during development.\n        #logger.debug(\"%s: u:'%s' p:'%s'\" % ( url, uname, passwd ))\n\n        password_mgr = urllib.request.HTTPPasswordMgrWithDefaultRealm()\n        password_mgr.add_password(None, \"%s://%s\" % (up.scheme, up.netloc), uname, passwd)\n        handler = urllib.request.HTTPBasicAuthHandler(password_mgr)\n        opener = urllib.request.build_opener(handler, urllib.request.HTTPSHandler(debuglevel=debuglevel))\n    else:\n        opener = urllib.request.build_opener(urllib.request.HTTPSHandler(debuglevel=debuglevel))\n\n    urllib.request.install_opener(opener)\n\n    logger.debug(\"Fetching %s (%s)...\" % (url, [\"without authentication\", \"with authentication\"][auth]))\n\n    try:\n        res = urlopen(Request(url, headers={'User-Agent': 'Mozilla/5.0 (Wind River Linux/setup.sh)'}, unverifiable=True))\n    except urllib.error.HTTPError as e:\n        logger.debug(\"HTTP Error: %s: %s\" % (e.code, e.reason))\n        logger.debug(\" Requested: %s\" % (url))\n        logger.debug(\" Actual:    %s\" % (e.geturl()))\n        if auth:\n            logger.debug(\" Authentication enabled.  Using username '%s'.\" % uname)\n        if not auth and e.code == 401:\n            logger.debug(\"Retrying with authentication...\")\n            res = fetch_url(url, auth=True, debuglevel=debuglevel, interactive=interactive)\n            logger.debug(\"...retrying with authentication successful, continuing.\")\n        elif e.code == 404:\n            logger.debug(\"Request not found.\")\n            raise e\n        else:\n            logger.debug(\"Headers:\\n%s\" % (e.headers))\n            raise e\n    except OSError as e:\n        error = 0\n        reason = \"\"\n\n        # Process base OSError first...\n        if hasattr(e, 'errno'):\n            error = e.errno\n            reason = e.strerror\n\n        # Process gaierror (socket error) subclass if available.\n        if hasattr(e, 'reason') and hasattr(e.reason, 'errno') and hasattr(e.reason, 'strerror'):\n            error = e.reason.errno\n            reason = e.reason.strerror\n            if error == -2:\n                raise e\n\n        if error and error != 0:\n            logger.critical(\"Unable to fetch %s due to exception: [Error %s] %s\" % (url, error, reason))\n        else:\n            logger.critical(\"Unable to fetch %s due to OSError exception: %s\" % (url, e))\n        sys.exit(1)\n    except Exception as e:\n        logger.critical('Unable to fetch entitlement: %s (%s)' % (type(e), e))\n        sys.exit(1)\n    finally:\n        logger.debug(\"...fetching %s (%s), done.\" % (url, [\"without authentication\", \"with authentication\"][auth]))\n\n    return res\n"
  },
  {
    "path": "bin/windshare.py",
    "content": "# Copyright (C) 2016 Wind River Systems, Inc.\n#\n# This program is free software; you can redistribute it and/or modify\n# it under the terms of the GNU General Public License version 2 as\n# published by the Free Software Foundation.\n#\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n# See the GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program; if not, write to the Free Software\n# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n\n# The windshare distribution mechanism has unique requirements for dividing\n# the components into specific entitled sections.  We need to take these\n# 'folders' and reconstruct the related items (mirror-index, xml files, etc)\n# into a flat view that works like a regular mirror would.\n\nimport json\nimport xml.etree.ElementTree as ET\n\nimport os\nimport sys\n\nimport logger_setup\n\nimport utils_setup\n\nlogger = logger_setup.setup_logging()\nclass Windshare():\n    def __init__(self, debug=0):\n        self.folders = None\n        self.indexes = {}\n        self.xmls = {}\n        self.debug = debug\n\n        # This is only used if we want to instruct the system to ask the user\n        # for credentials, if a better credential manager is not available.\n        self.interactive = 0\n\n    def get_windshare_urls(self, base_url):\n        from urllib.parse import urlsplit, urlunsplit\n\n        (uscheme, uloc, upath, uquery, ufragid) = urlsplit(base_url)\n\n        # What folder are we in?\n        ws_base_folder = os.path.basename(upath)\n\n        logger.debug('Product base folder = %s' % ws_base_folder)\n\n        if not ws_base_folder or ws_base_folder == \"\":\n            # Invalid URL\n            logger.debug('Invalid base folder, not Windshare.')\n            return (None, None, None)\n\n        # Folder root is one directory higher then the base_url\n        upath = os.path.dirname(upath)\n        ws_base_url = urlunsplit((uscheme, uloc, upath, uquery, ufragid))\n\n        if uscheme and (uscheme != \"http\" and uscheme != \"https\"):\n            logger.debug('Scheme (%s) not valid for Windshare.' % uscheme)\n            return (None, None, None)\n\n        # Magic URL to the entitlement file\n        ws_entitlement_url = ws_base_url + '/wrlinux-lts.21.json'\n\n        logger.debug('Entitlement url %s' % ws_entitlement_url)\n\n        # If no uscheme, this is file access, check here if an entitlement\n        # file exists.  If not, we know we're not windshare.\n        if not uscheme and not os.path.exists(ws_entitlement_url):\n            logger.debug('Local file path, file does not exist.  Not a Windshare install.')\n            return (None, None, None)\n\n        return (ws_base_url, ws_base_folder, ws_entitlement_url)\n\n    def load_folders(self, url=None):\n        assert url is not None\n\n        def _get_json_response(wsurl=None, retry=True):\n            assert wsurl is not None\n\n            from urllib.parse import urlparse\n\n            up = urlparse(wsurl)\n            if not up.scheme:\n                # Check for it on the disk...\n                if os.path.exists(wsurl):\n                    parsed = json.load(open(wsurl, 'rt', encoding='utf-8'))\n                else:\n                    return None\n            else:\n                # Go out to the network...\n                from urllib.request import URLError\n                try:\n                    res = utils_setup.fetch_url(wsurl, debuglevel=self.debug, interactive=self.interactive)\n                except URLError as e:\n                    if 'windshare' in up.netloc:\n                        # Authentication failure, we need to stop now.\n                        if hasattr(e, 'code') and e.code == 401:\n                            logger.critical('Unable to authenticate: %s' % wsurl)\n                        else:\n                            logger.critical('Unable to contact Wind Share: %s: %s' % (wsurl, e.reason))\n\n                        logger.critical(\"Check your credentials, network and proxy settings.\")\n                        sys.exit(1)\n                    raise e\n\n                try:\n                    result = res.read().decode('utf-8')\n                except ConnectionResetError:\n                    if retry:\n                        logger.debug(\"%s: Connection reset by peer.  Retrying...\" % wsurl)\n                        result = _get_json_response(wsurl=wsurl, retry=False)\n                        logger.debug(\"%s: retry successful.\" % wsurl)\n                    else:\n                        logger.critical(\"%s: Connection reset by peer.\" % wsurl)\n                        logger.critical(\"Is there a firewall blocking your connection?\")\n                        sys.exit(1)\n\n                logger.debug('Result:\\n%s' % result)\n                parsed = json.loads(result)\n\n            return parsed\n\n        try:\n            entitlement = _get_json_response(url)\n\n            if entitlement and 'dataFolderTrueFolders' in entitlement:\n                self.folders = entitlement['dataFolderTrueFolders']\n            else:\n                return False\n        except Exception as e:\n            logger.debug('Unable to fetch entitlement: %s (%s)' % (type(e), e))\n            return False\n\n        return True\n\n    # Note base_url is _NOT_ setup.base_url, it is the root of the folders dir\n    def load_mirror_index(self, setup, base_url, folder):\n        mirror_index_path = setup.load_mirror_index(base_url + '/' + folder + '/mirror-index', folder=folder + \"_\")\n        if not mirror_index_path:\n            raise Exception(\"Unable to load mirror index %s.\" % (base_url + '/' + folder + '/mirror-index'))\n\n        # Mirror index returns with the fetched item checked out...\n        #cmd = [setup.tools['git'], 'checkout', folder + \"_\" + setup.base_branch ]\n        #utils_setup.run_cmd(cmd, environment=setup.env, cwd=mirror_index_path)\n\n        for (dirpath, _, filenames) in os.walk(mirror_index_path):\n            if dirpath.endswith('/.git') or '/.git/' in dirpath:\n                continue\n            for filename in filenames:\n                if filename == 'README':\n                    continue\n                if filename.endswith('.json'):\n                    try:\n                        (_, _, jlayer) = filename[:-5].split('__')\n                    except:\n                        raise Exception('Unable to parse windshare json file %s (%s).' % (filename, folder + \"_\" + setup.base_branch))\n\n                    path = os.path.join(dirpath, filename)\n                    pindex = json.load(open(path, 'rt', encoding='utf-8'))\n\n                    if 'layerItems' in pindex:\n                        newItems = []\n                        for entry in pindex['layerItems']:\n                            # Verify this is the jlayer, otherwise remove it as it won't be in this folder!\n                            if entry['name'] != jlayer:\n                                continue\n                            entry['vcs_url'] = entry['vcs_url'].replace('#BASE_URL#', '#BASE_URL#' + '/' + folder)\n                            newItems.append(entry)\n                        pindex['layerItems'] = newItems\n\n                    self.indexes[filename] = pindex\n\n                elif filename.endswith('.xml') or filename.endswith('.inc'):\n                    self.xmls[filename] = []\n                    path = os.path.join(dirpath, filename)\n\n                    # Prefix the <project name= entries with the folder/\n                    with open(path, 'rt') as fin:\n                        for _line in fin:\n                            _line = _line.rstrip()\n                            try:\n                                _root = ET.fromstring(_line)\n                            except Exception:\n                                logger.warning('Unable to parse XML %s: %s' % (filename, _line))\n                                self.xmls[filename].append(_line)\n                                continue\n\n                            if _root.tag != 'project':\n                                self.xmls[filename].append(_line)\n                                continue\n\n                            for attrib in _root.attrib:\n                                if attrib == 'name':\n                                    _root.attrib['name'] = folder + '/' + _root.attrib['name']\n\n                            for _child in _root:\n                                for attrib in _child.attrib:\n                                    if attrib == 'name':\n                                        _child.attrib['name'] = folder + '/' + _child.attrib['name']\n\n                            self.xmls[filename].append(ET.tostring(_root, encoding='unicode'))\n                else:\n                    logger.warning('When processing Windshare mirror index, Unexpected file %s...' % filename)\n\n        return mirror_index_path\n\n    def write_local_mirror_index(self, setup, mirror_index_path):\n        import subprocess\n\n        # We need access to the sortRestApi function...\n        from layer_index import Layer_Index\n        li = Layer_Index()\n\n        # We want to move to a generic named branch, now that we've done the fixups.\n        try:\n            cmd = [setup.tools['git'], 'checkout', '--orphan', setup.base_branch ]\n            utils_setup.run_cmd(cmd, environment=setup.env, cwd=mirror_index_path, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)\n        except Exception:\n            cmd = [setup.tools['git'], 'checkout', setup.base_branch ]\n            utils_setup.run_cmd(cmd, log=2, environment=setup.env, cwd=mirror_index_path)\n            cmd = [setup.tools['git'], 'reset', '--hard' ]\n            utils_setup.run_cmd(cmd, log=2, environment=setup.env, cwd=mirror_index_path)\n\n        # Remove obsolete entries only\n        for (dirpath, _, filenames) in os.walk(mirror_index_path):\n            if dirpath.endswith('/.git') or '/.git/' in dirpath:\n                continue\n            for filename in filenames:\n                if filename not in self.indexes and filename not in self.xmls:\n                    logger.debug('ws mirror-index remove obsolete %s' % os.path.join(dirpath, filename))\n                    os.remove(os.path.join(dirpath, filename))\n\n        for entry in self.indexes:\n            logger.debug('Writing windshare index %s...' % entry)\n            fpath = os.path.join(mirror_index_path, entry)\n            json.dump(li.sortRestApi(self.indexes[entry]), open(fpath, 'wt'), indent=4)\n\n        for entry in self.xmls:\n            logger.debug('Writing windshare xml %s...' % entry)\n            os.makedirs(os.path.join(mirror_index_path, 'xml'), exist_ok=True)\n            fpath = os.path.join(mirror_index_path, 'xml', entry)\n            with open(fpath, 'wt') as fout:\n                for _line in self.xmls[entry]:\n                    fout.write(_line + '\\n')\n\n        cmd = [setup.tools['git'], 'add', '-A', '.']\n        utils_setup.run_cmd(cmd, log=2, environment=setup.env, cwd=mirror_index_path)\n\n        try:\n            cmd = [setup.tools['git'], 'diff-index', '--quiet', 'HEAD', '--']\n            utils_setup.run_cmd(cmd, environment=setup.env, cwd=mirror_index_path, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)\n        except Exception:\n            # We expect to fail to this code\n            logger.debug('Updating windshare mirror-index')\n            cmd = [setup.tools['git'], 'commit', '-m', 'Updated index - %s' % (setup.setup_args)]\n            utils_setup.run_cmd(cmd, log=2, environment=setup.env, cwd=mirror_index_path)\n\n"
  },
  {
    "path": "data/environment.d/00_check_repo.sh",
    "content": "# Copyright (C) 2017 Wind River Systems, Inc.\n#\n# This program is free software; you can redistribute it and/or modify\n# it under the terms of the GNU General Public License version 2 as\n# published by the Free Software Foundation.\n#\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n# See the GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program; if not, write to the Free Software\n# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n\n# Verify that we don't have a .repo directory in a parent dir\n# since repo does not permit this\n\nsetup_add_func check_repo\n\ncheck_repo() {\n\t# Cleanup the path if necessary\n\tpath=$(cd $PWD ; pwd)\n\n\twhile\n\t        path=$(dirname $path)\n\t\t[ -n \"$path\" -a \"$path\" != \"/\" ]\n\tdo\n\t\tif [ -e $path/.repo ]; then\n\t\t\techo \"ERROR: A parent path has a .repo subdirectory: $path\" >&2\n\t\t\techo \"git-repo, which is used by the setup program, does not permit a nested\" >&2\n\t\t\techo \"repository structure.  You must run setup in a different location or\" >&2\n\t\t\techo \"remove the directory $path/.repo\" >&2\n\t\t\texit 1\n\t\tfi\n\tdone\n}\n"
  },
  {
    "path": "data/environment.d/00_wrl_eula.sh",
    "content": "# Copyright (C) 2016 - 2020 Wind River Systems, Inc.\n#\n# This program is free software; you can redistribute it and/or modify\n# it under the terms of the GNU General Public License version 2 as\n# published by the Free Software Foundation.\n#\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n# See the GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program; if not, write to the Free Software\n# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n\n# Verify EULA acceptance\n\n# We don't 'keep' this command & argument as acceptance is stored\nsetup_add_arg --accept-eula ACCEPT_EULA\n\nsetup_add_func eula_setup\n\neula_askuser() {\n\taccept=${ACCEPT_EULA}\n\t# Check whether it is set or not.\n\tif [ -n \"${ACCEPT_EULA+x}\" ]; then\n\t\tif [ \"${accept}\" != \"yes\" -a \"${accept}\" != \"no\" ]; then\n\t\t\techo \"error: argument --accept-eula: invalid choice: '${accept}' \\\n(choose from 'yes', 'no')\" >&2\n\t\t\texit 1\n\t\tfi\n\t\tif [ \"${accept}\" = \"no\" ]; then\n\t\t\techo \"You must agree to the EULA to continue.\" >&2\n\t\t\texit 1\n\t\tfi\n\tfi\n\twhile [ \"${accept}\" != \"yes\" ] ; do\n\t\techo\n\t\techo \"The End User License Agreement is available at:\"\n\t\techo \"\t${BASEDIR}/EULA\"\n\t\techo\n\t\tread -p \"I have read the EULA and accept it - yes/no/read \" accept\n\t\tcase ${accept} in\n\t\t\t[yY][eE][sS])\n\t\t\t\taccept=\"yes\"\n\t\t\t\t;;\n\t\t\t[nN][oO])\n\t\t\t\techo \"You must agree to the EULA to continue.\" >&2\n\t\t\t\texit 1\n\t\t\t\t;;\n\t\t\t[rR] | [rR][eE][aA][dD])\n\t\t\t\t# Prefer 'less' if we have it, otherwise fall back to more\n\t\t\t\tif which less >/dev/null 2>&1 ; then\n\t\t\t\t\tcat ${BASEDIR}/EULA | less -P\"Type 'q' when done.\"\n\t\t\t\telse\n\t\t\t\t\tcat ${BASEDIR}/EULA | more\n\t\t\t\tfi\n\t\t\t\t;;\n\t\t\t*)\n\t\t\t\techo \"Only yes, no and read are accepted.\" >&2\n\t\t\t\t;;\n\t\tesac\n\tdone\n\n\techo\n\n\tmkdir -p config\n\t# Log the EULA acceptance if there is any question in the future...\n\t{\n\t\techo \"#End User License Agreement Accepted\"\n\t\techo \"EULA_DATE=\\\"$(date)\\\"\"\n\t\techo \"EULA_USER=\\\"$(whoami)@$(hostname)\\\"\"\n\t\techo \"EULA_VERSION=\\\"$(tail -n 1 ${BASEDIR}/EULA)\\\"\"\n\t\techo \"EULA_SHA=\\\"$(shasum ${BASEDIR}/EULA | cut -d ' ' -f 1)\\\"\"\n\t\techo\n\t} >> config/eula_accepted\n}\n\neula_setup() {\n\tif [ -e config/eula_accepted ]; then\n\t\t. ./config/eula_accepted\n\tfi\n\tNEW_SHA=$(shasum ${BASEDIR}/EULA | cut -d ' ' -f 1)\n\tif [ -n \"${EULA_SHA}\" -a \"${NEW_SHA}\" != \"${EULA_SHA}\" ]; then\n\t\techo \"The End User User License has changed since you last agreed to it.\"\n\t\tEULA_SHA=\"\"\n\tfi\n\tif [ -z \"${EULA_SHA}\" -o -z \"${EULA_VERSION}\" -o -z \"${EULA_DATE}\" -o -n \"${ACCEPT_EULA+x}\" ]; then\n\t\teula_askuser\n\telse\n\t\techo \"End User License Agreement '${EULA_VERSION}' agreed to by ${EULA_USER} on ${EULA_DATE}.\"\n\tfi\n}\n"
  },
  {
    "path": "data/environment.d/01_wrl_buildtools.sh",
    "content": "# Copyright (C) 2016, 2020 Wind River Systems, Inc.\n#\n# This program is free software; you can redistribute it and/or modify\n# it under the terms of the GNU General Public License version 2 as\n# published by the Free Software Foundation.\n#\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n# See the GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program; if not, write to the Free Software\n# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n\n# Check if the buildtools are available, if so load it early...\n\nBUILDTOOLS=\"${BUILDTOOLS:-bin/buildtools}\"\n\nsetup_add_func buildtools_pre_setup\n\nunset -v BUILDTOOLS_LOADED\n\nbuildtools_pre_setup() {\n\tENVIRON=$(find -L ${BUILDTOOLS} -name \"environment-setup-${SDKARCH}-*-linux\" 2>/dev/null | head -n1)\n\tif [ -z \"${ENVIRON}\" ]; then\n\t\t# Nothing there yet...\n\t\treturn 0\n\tfi\n\t. \"${ENVIRON}\"\n\tif [ $? -ne 0 ]; then\n\t\t# Something went wrong.. ignore it\n\t\treturn 0\n\tfi\n\tBUILDTOOLS_LOADED=1\n\treturn 0\n}\n"
  },
  {
    "path": "data/environment.d/02_wrl_anspass.sh",
    "content": "# Copyright (C) 2016 Wind River Systems, Inc.\n#\n# This program is free software; you can redistribute it and/or modify\n# it under the terms of the GNU General Public License version 2 as\n# published by the Free Software Foundation.\n#\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n# See the GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program; if not, write to the Free Software\n# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n\n# Check if we have access to anspassd, if so try to setup anspass.\n\n# Quick walk through args to look for --no-anspass \n#  We do it here because we need to decide right now if the anspass\n#  needs to be started/stopped\n\nargs=\"$@\"\n\n# Skip anspass if --no-anspass OR the BASEURL starts with ssh://\n# for ssh:// we don't want to store these values in anspass, as it can not\n# understand the format of the question\nif [ \"${args/--no-anspass//}\" != \"${args}\" -o \"${BASEURL##ssh://}\" != \"${BASEURL}\" ] ; then\n\texport NO_ANSPASS=1\nfi\n\nif [ \"$NO_ANSPASS\" = \"\" ] ; then\nsetup_add_func anspass_setup\n\nsetup_shutdown_func anspass_early_shutdown\n\n. ${BASEDIR}/data/environment.d/setup_anspass\nfi\n\n# anspass_setup defined in setup_anspass\n\n# This isn't really a shutdown, but a transfer.  Before we stop 'askpass', we\n# need to transfer any credential into anspass.  By this point anspass\n# should be ready for a transfer.\n#\n# If anspass isn't running yet, we have to start it, so we can transfer the\n# credentials.  But it should be shutdown right after.\n#\n# anspass_start defined in setup_anspass\nanspass_early_shutdown() {\n\t# Before shutting down, try to transfer askpass items to anspass\n\tif [ -n \"${WRL_ASKPASS_SOCKET}\" ]; then\n\t\tif [ -z \"$(${BASEDIR}/data/environment.d/setup_askpass --dump)\" ]; then\n\t\t\treturn 0\n\t\tfi\n\t\t# If anspass is not running, we start it so we can transfer\n\t\t# credentials for storage\n\t\tif [ -z \"${ANSPASS_PATH}\" -o -z \"${ANSPASS_TOKEN}\" ]; then\n\t\t\tanspass_start\n\t\tfi\n\t\techo \"Storing credentials into anspass.\"\n\t\t${BASEDIR}/data/environment.d/setup_askpass --dump | anspass_transfer\n\t\tanspass_stop\n\tfi\n\treturn 0\n}\n"
  },
  {
    "path": "data/environment.d/03_wrl_askpass.sh",
    "content": "# Copyright (C) 2016 Wind River Systems, Inc.\n#\n# This program is free software; you can redistribute it and/or modify\n# it under the terms of the GNU General Public License version 2 as\n# published by the Free Software Foundation.\n#\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n# See the GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program; if not, write to the Free Software\n# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n\n# This needs to be run BEFORE we run any password checks...\n\nsetup_add_arg --user WINDSHARE_USER\nsetup_add_arg --password WINDSHARE_PASS\n\nsetup_add_func askpass_setup\n\nsetup_shutdown_func askpass_shutdown\n\naskpass_setup() {\n\t# These values may also be used by anspass\n\tWINDSHARE_SCHEME=$(echo ${BASEURL} | sed 's,\\([^:/]*\\).*,\\1,')\n\tif [ ${WINDSHARE_SCHEME} ]; then\n\t\tWINDSHARE_HOST=$(echo ${BASEURL} | sed 's,\\([^:/]*\\)://\\([^/]*\\).*,\\2,')\n\tfi\n\n\t# If anspass is already enabled, use it instead!\n\tif [ -n \"${ANSPASS_TOKEN}\" ]; then\n\t\treturn 0\n\tfi\n\n\tif [ \"$WINDSHARE_SCHEME\" = \"http\" ] || [ \"$WINDSHARE_SCHEME\" = \"https\" ]; then\n\t\tif [ -n \"$GIT_ASKPASS\" ]; then\n\t\t\techo \"INFO: Detected GIT_ASKPASS configuration. Disabling built-in askpass functionality.\"\n\t\t\treturn 0\n\t\tfi\n\tfi\n\n\texport WRL_ASKPASS_SOCKET=${PWD}/bin/.setup_askpass\n\n\t# Cleanup any old instances\n\t${BASEDIR}/data/environment.d/setup_askpass --quit >/dev/null 2>&1\n\trm -f ${WRL_ASKPASS_SOCKET}\n\n\tmkdir -p $(dirname ${WRL_ASKPASS_SOCKET})\n\t${BASEDIR}/data/environment.d/setup_askpass --server &\n\taskpass_pid=$!\n\taskpass_jid=%%\n\n\twhile [ ! -e ${WRL_ASKPASS_SOCKET} ]; do\n\t\tif ! jobs $askpass_jid >/dev/null 2>&1 ; then\n\t\t\techo \"Unable to start the askpass server.\" >&2\n\t\t\treturn 1\n\t\tfi\n\t\t# We have to give it time to start...\n\t\tsleep 1\n\tdone\n\n\t# We need to tell it what tty to use for questions...\n\techo $(tty) | ${BASEDIR}/data/environment.d/setup_askpass --set \"tty\" > /dev/null 2> /dev/null\n\n\t# If user/pass passed in (can't do this for a file path)\n\tif [ -n \"${WINDSHARE_HOST}\" ]; then\n\t\tif [ -n \"${WINDSHARE_USER}\" ]; then\n\t\t\techo \"${WINDSHARE_USER}\" | ${BASEDIR}/data/environment.d/setup_askpass --set \"Username for '${WINDSHARE_SCHEME}://${WINDSHARE_HOST}': \" > /dev/null\n\t\t\techo \"${WINDSHARE_PASS}\" | ${BASEDIR}/data/environment.d/setup_askpass --set \"Password for '${WINDSHARE_SCHEME}://${WINDSHARE_USER}@${WINDSHARE_HOST}': \" \"${WINDSHARE_PASS}\" > /dev/null\n\t\tfi\n\n\t\tif [ ${WINDSHARE_SCHEME} = \"ssh\" -a -n \"${WINDSHARE_PASS}\" ]; then\n\t\t\techo \"${WINDSHARE_PASS}\" | ${BASEDIR}/data/environment.d/setup_askpass --set \"${WINDSHARE_HOST}'s password: \" > /dev/null\n\t\tfi\n\tfi\n\n\texport GIT_SSH=${BASEDIR}/data/environment.d/setup_ssh\n\texport GIT_ASKPASS=${BASEDIR}/data/environment.d/setup_askpass\n\texport SSH_ASKPASS=${BASEDIR}/data/environment.d/setup_askpass\n\treturn 0\n}\n\naskpass_shutdown() {\n\tif [ -n \"${WRL_ASKPASS_SOCKET}\" ]; then\n\t\t${BASEDIR}/data/environment.d/setup_askpass --quit\n\t\trm -f ${WRL_ASKPASS_SOCKET}\n\t\tunset WRL_ASKPASS_SOCKET\n\tfi\n}\n"
  },
  {
    "path": "data/environment.d/04_wrl_buildtools.sh",
    "content": "# Copyright (C) 2016-2021 Wind River Systems, Inc.\n#\n# This program is free software; you can redistribute it and/or modify\n# it under the terms of the GNU General Public License version 2 as\n# published by the Free Software Foundation.\n#\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n# See the GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program; if not, write to the Free Software\n# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n\n# Download, install and load the buildtools tarball (as needed)\n\nBUILDTOOLS_VERSION=${BUILDTOOLS_VERSION:-10.21.20.4}\nBUILDTOOLS_EXT_VERSION=${BUILDTOOLS_EXT_VERSION:-10.21.01b.0}\n\n# Special windshare folders to search\nBUILDTOOLS_FOLDERS=\"WRLinux-lts-21-Core WRLinux-lts-21-Base\"\n\n\n# Where to install the build tools\nBUILDTOOLS=\"${BUILDTOOLS:-bin/buildtools}\"\n\n# Arch of the SDK to load\nSDKARCH=${SDKARCH:-$(uname -m)}\n\nsetup_add_arg --buildtools-branch BUILDTOOLSBRANCH keep\n\nsetup_add_arg --buildtools-type BUILDTOOLS_TYPE keep\n\nsetup_add_func buildtools_setup\n\nsetup_export_func buildtools_export\n\n. ${BASEDIR}/data/environment.d/setup_utils\n\nbuildtools_setup() {\n\tif [ -z \"${BUILDTOOLSBRANCH}\" ]; then\n\t\tBUILDTOOLSBRANCH=\"${BASEBRANCH}\"\n\tfi\n\n\t# According to https://gcc.gnu.org/projects/cxx-status.html#cxx14\n\t# gcc 6.0.0 is the minimal version fully support c++14\n\tgcc_cur_ver=$(gcc -dumpfullversion -dumpversion 2>/dev/null)\n\trequired_ver=6.0.0\n\n\t# check whether host gcc version less than $required_ver\n\tif [ ! \"$(printf '%s\\n' \"$required_ver\" \"$gcc_cur_ver\" | sort -V | head -n1)\" = \"$required_ver\" ]; then\n\t\tif [ basic = \"${BUILDTOOLS_TYPE}\" ]; then\n\t\t\techo -e \"\\nWarning: The version of host gcc is too low to support c++14 standard. It may cause some packages such as doxygen-native fail to build with basic buildtools.\\n\"\n\t\tfi\n\n\t\tif [ -z \"${BUILDTOOLS_TYPE}\" ]; then\n\t\t\tBUILDTOOLS_TYPE=extended\n\t\tfi\n\tfi\n\n\tif [ -z \"${BUILDTOOLS_TYPE}\" ]; then\n\t\tBUILDTOOLS_TYPE=basic\n\tfi\n\n\tif [ basic != \"${BUILDTOOLS_TYPE}\" ] && [ extended != \"${BUILDTOOLS_TYPE}\" ]; then\n\t\techo \"Wrong argument \\\"${BUILDTOOLS_TYPE}\\\" for option --buildtools-type. Supported arguments: basic, extended.\" >&2\n\t\treturn 1\n\tfi\n\n\tif [ basic = \"${BUILDTOOLS_TYPE}\" ]; then\n\t\tbuildtools=buildtools\n\t\tbuildtools_version=$BUILDTOOLS_VERSION\n\telse\n\t\tbuildtools=buildtools-extended\n\t\tbuildtools_version=$BUILDTOOLS_EXT_VERSION\n\tfi\n\n\t# Buildtools location can change -- this is the path on top of the BASEURL\n\tBUILDTOOLS_REMOTE=\"${BUILDTOOLS_REMOTE:-${buildtools}-standalone-${buildtools_version}}\"\n\n\t# Where to cache the git fetch\n\tBUILDTOOLS_GIT=\"${BUILDTOOLS_GIT:-bin/${buildtools}.git}\"\n\n\tFETCH_BUILDTOOLS=0\n\n\t# Install them into the project directory\n\tEXTRACT_BUILDTOOLS=0\n\n\tBUILDTOOLS_REF=$(echo ${BUILDTOOLS_REMOTE} | sed -e 's,.*/buildtools-standalone-,,')\n\n\tif [ ! -d \"${BUILDTOOLS_GIT}\" ]; then\n\t\tFETCH_BUILDTOOLS=1\n\n\t\t(mkdir -p ${BUILDTOOLS_GIT} && git init ${BUILDTOOLS_GIT})\n\t\tif [ $? -ne 0 ]; then\n\t\t\techo \"Unable to create ${BUILDTOOLS_GIT} directory.\" >&2\n\t\t\treturn 1\n\t\tfi\n\telse\n\t\t# Did the buildtools URL change?\n\t\tLASTREF=$(git config -f ${BUILDTOOLS_GIT}/.git/config local.last.ref)\n\t\tif [ \"${LASTREF}\" != \"${BUILDTOOLS_REF}\" ]; then\n\t\t\tFETCH_BUILDTOOLS=1\n\t\tfi\n\tfi\n\n\tif [ ${FETCH_BUILDTOOLS} -ne 1 ]; then\n\t\t# We need this in order to have the right path for subsequent mirror operations\n\t\tBUILDTOOLS_REMOTE=$(git config -f ${BUILDTOOLS_GIT}/.git/config local.${BUILDTOOLS_REF}.path)\n\telse\n\t\techo \"Searching for ${BUILDTOOLS_REMOTE}...\"\n\n\t\tretries=0\n\t\tduration=5\n\t\tfor i in {1..5} ; do\n\t\t\tif ! setup_check_url \"${BASEURL}/${BUILDTOOLS_REMOTE}\" ; then\n\t\t\t\tORIG_BT_REMOTE=${BUILDTOOLS_REMOTE}\n\t\t\t\t# Additional places to search...\n\t\t\t\tfor folder in ${BUILDTOOLS_FOLDERS} layers/buildtools; do\n\t\t\t\t\tNEW_REMOTE=${folder}/${BUILDTOOLS_REMOTE}\n\t\t\t\t\tif setup_check_url \"${BASEURL}/${NEW_REMOTE}\" ; then\n\t\t\t\t\t\tBUILDTOOLS_REMOTE=${NEW_REMOTE}\n\t\t\t\t\tfi\n\t\t\t\tdone\n\t\t\t\tif [ \"${BUILDTOOLS_REMOTE}\" = \"${ORIG_BT_REMOTE}\" ]; then\n\t\t\t\t\tretries=$(($retries+1))\n\t\t\t\t\techo \"Retrying $1 after $duration seconds -- $retries time(s) (max: 5)\"\n\t\t\t\t\tsleep $duration\n\t\t\t\t\tduration=$(($duration+$(random 1 5)))\n\t\t\t\tfi\n\t\t\telse\n\t\t\t\tbreak\n\t\t\tfi\n\t\tdone\n\n\t\tif [ $retries -eq 5 ]; then\n\t\t\techo \"Unable to find ${BUILDTOOLS_REMOTE}.  Search path:\">&2\n\t\t\tfor folder in ${BUILDTOOLS_FOLDERS} layers/buildtools; do\n\t\t\t\techo \" ${BASEURL}/${folder}/${BUILDTOOLS_REMOTE}\" >&2\n\t\t\tdone\n\t\t\treturn 1\n\t\tfi\n\n\t\techo \"Fetching buildtools..\"\n\t\t# Check if it's a tag\n\t\tif [ \"$BASEBRANCH\" != \"${BASEBRANCH##refs/tags/}\" ]; then\n\t\t\tlocal_name=\"${BUILDTOOLSBRANCH}:tags/${BUILDTOOLS_REF}\"\n\t\telse\n\t\t\tlocal_name=\"${BUILDTOOLSBRANCH}:${BUILDTOOLS_REF}\"\n\t\tfi\n\t\ttrap : INT\n\t\tretries=0\n\t\tduration=5\n\t\tret=0\n\t\tfor i in {1..5} ; do\n\t\t\techo \"${BASEURL}/${BUILDTOOLS_REMOTE}\"\n\t\t\t(cd ${BUILDTOOLS_GIT} && git fetch -f -n -u \"${BASEURL}/${BUILDTOOLS_REMOTE}\" $local_name)\n\t\t\tret=$?\n\t\t\tif [ $ret -eq 0 ] || [ $ret -eq 130 ]; then\n\t\t\t\tbreak\n\t\t\telse\n\t\t\t\tretries=$(($retries+1))\n\t\t\t\techo \"Retrying $1 after $duration seconds -- $retries time(s) (max: 5)\"\n\t\t\t\tsleep $duration\n\t\t\t\tduration=$(($duration+$(random 1 5)))\n\t\t\tfi\n\t\tdone\n\n\t\tif [ $retries -eq 5 ] || [ $ret -eq 130 ]; then\n\t\t\techo \"Error fetching buildtools repository ${BASEURL}/${BUILDTOOLS_REMOTE}\" >&2\n\t\t\treturn 1\n\t\tfi\n\t\ttrap - INT\n\t\t# Set a flag so we know where the fetch was from...\n\t\t(\n\t\t\tcd ${BUILDTOOLS_GIT}\n\t\t\tgit config \"local.${BUILDTOOLS_REF}.url\" \"${BASEURL}/${BUILDTOOLS_REMOTE}\"\n\t\t\tgit config \"local.${BUILDTOOLS_REF}.path\" \"${BUILDTOOLS_REMOTE}\"\n\t\t\tgit config local.last.ref \"${BUILDTOOLS_REF}\"\n\t\t\tgit checkout \"${BUILDTOOLS_REF}\"\n\t\t)\n\t\tif [ $? -ne 0 ]; then\n\t\t\techo \"Unable to checkout branch ${BUILDTOOLS_REF}.\" >&2\n\t\t\treturn 1\n\t\tfi\n\t\techo \"Done\"\n\n\t\tEXTRACT_BUILDTOOLS=1\n\tfi\n\n\tif [ ! -d \"${BUILDTOOLS}.${BUILDTOOLS_REF}\" ]; then\n\t\tEXTRACT_BUILDTOOLS=1\n\tfi\n\n\tif [ ${EXTRACT_BUILDTOOLS} -ne 1 ]; then\n\t\tENVIRON=$(find -L ${BUILDTOOLS} -name \"environment-setup-${SDKARCH}-*-linux\" | head -n1)\n\t\tif [ -z \"${ENVIRON}\" ]; then\n\t\t\t# Something is wrong, try to fix it!\n\t\t\tEXTRACT_BUILDTOOLS=1\n\t\tfi\n\tfi\n\n\tif [ ${EXTRACT_BUILDTOOLS} -eq 1 ]; then\n\t\t# Needs python.\n\t\tbuildtoolssdk=$(find \"${BUILDTOOLS_GIT}\" -name \"${SDKARCH}-${buildtools}-nativesdk-standalone-*.sh\" 2>/dev/null | sort | head -n1)\n\t\tbuildtoolssdk_list=$(find \"${BUILDTOOLS_GIT}\" -name \"${SDKARCH}-${buildtools}-nativesdk-standalone-*.list\" 2>/dev/null | sort | head -n1)\n\t\tif [ -z \"${buildtoolssdk_list}\" ]; then\n\t\t\tif [ -z \"${buildtoolssdk}\" ]; then\n\t\t\t\techo \"Unable to find buildtools-nativesdk-standalone archive for ${SDKARCH}.\" >&2\n\t\t\t\techo >&2\n\t\t\t\techo \"SDKARCH values found:\" >&2\n\t\t\t\techo $(find \"${BUILDTOOLS_GIT}\" -name \"*-${buildtools}-nativesdk-standalone-*.sh\" | xargs -n 1 basename | cut -d '-' -f 1) >&2\n\t\t\t\techo >&2\n\t\t\t\techo \"If one of these is compatible, set SDKARCH in your environment.\" >&2\n\t\t\t\techo >&2\n\t\t\t\treturn 1\n\t\t\tfi\n\t\telse\n\t\t\tbuildtoolssdk=${buildtoolssdk_list/%.list/.sh}\n\t\t\trm -f ${buildtoolssdk}\n\t\t\tfor part in $(cat ${buildtoolssdk_list}); do\n\t\t\t\tcat ${BUILDTOOLS_GIT}/${part} >>${buildtoolssdk}\n\t\t\tdone\n\t\t\tchmod +x ${buildtoolssdk}\n\t\tfi\n\n\t\techo \"Installing buildtools..\"\n\t\tif [ -d \"${BUILDTOOLS}.${BUILDTOOLS_REF}\" ]; then\n\t\t\trm -rf \"${BUILDTOOLS}.${BUILDTOOLS_REF}\"\n\t\tfi\n\t\ttrap : INT\n\t\t${buildtoolssdk} -d \"${BUILDTOOLS}.${BUILDTOOLS_REF}\" -y\n\t\tif [ $? -ne 0 ]; then\n\t\t\techo >&2\n\t\t\techo \"Error installing the buildtools-nativesdk-standalone archive: ${buildtoolssdk}\" >&2\n\t\t\t# We try to cleanup, but an over zealous (sigint) user can stop the rm as well.\n\t\t\trm -rf ${BUILDTOOLS}.${BUILDTOOLS_REF}\n\t\t\treturn 1\n\t\tfi\n\t\ttrap - INT\n\t\techo \"Done\"\n\tfi\n\n\t# force to re-create the link that buildtools type may change\n\trm -f ${BUILDTOOLS}\n\tln -s $(basename ${BUILDTOOLS}).${BUILDTOOLS_REF} ${BUILDTOOLS}\n\n\tunset FETCH_BUILDTOOLS EXTRACT_BUILDTOOLS\n\n\tENVIRON=$(find -L ${BUILDTOOLS} -name \"environment-setup-${SDKARCH}-*-linux\" | head -n1)\n\tif [ -z \"${ENVIRON}\" ]; then\n\t\techo \"Error unable to load buildtools environment-setup file.\" >&2\n\t\treturn 1\n\tfi\n\t. \"${ENVIRON}\"\n\tif [ $? -ne 0 ]; then\n\t\techo \"Unable to load the buildtools environment setup file.\" >&2\n\t\treturn 1\n\tfi\n\tBUILDTOOLS_LOADED=1\n\treturn 0\n}\n\n\nbuildtools_export() {\n\tif [ -z \"${BUILDTOOLSBRANCH}\" ]; then\n\t\tBUILDTOOLSBRANCH=\"${BASEBRANCH}\"\n\tfi\n\n\texport OE_BUILDTOOLS_BRANCH=${BUILDTOOLSBRANCH}\n\texport OE_BUILDTOOLS_REMOTE=${BUILDTOOLS_REMOTE}\n\tif [ basic = \"${BUILDTOOLS_TYPE}\" ]; then\n\t\texport OE_ANOTHER_BUILDTOOLS_REMOTE=`echo ${BUILDTOOLS_REMOTE} | sed -e \"s,buildtools-standalone-,buildtools-extended-standalone-,\" \\\n\t\t\t| sed -e \"s,${BUILDTOOLS_VERSION},${BUILDTOOLS_EXT_VERSION},\"`\n\telse\n\t\texport OE_ANOTHER_BUILDTOOLS_REMOTE=`echo ${BUILDTOOLS_REMOTE} | sed -e \"s,buildtools-extended-standalone-,buildtools-standalone-,\" \\\n\t\t\t| sed -e \"s,${BUILDTOOLS_EXT_VERSION},${BUILDTOOLS_VERSION},\"`\n\tfi\n\treturn 0\n}\n"
  },
  {
    "path": "data/environment.d/05_wrl_anspass.sh",
    "content": "# Copyright (C) 2016 Wind River Systems, Inc.\n#\n# This program is free software; you can redistribute it and/or modify\n# it under the terms of the GNU General Public License version 2 as\n# published by the Free Software Foundation.\n#\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n# See the GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program; if not, write to the Free Software\n# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n\n# Check if we have access to anspassd, if so try to setup anspass.\n\nif [ \"$NO_ANSPASS\" = \"\" ] ; then\nsetup_add_func anspass_late_setup\n\nsetup_shutdown_func anspass_shutdown\n\n. ${BASEDIR}/data/environment.d/setup_anspass\nfi\n\n# anspass_setup defined in setup_anspass\nanspass_late_setup() {\n\t# If we've already started anspass, skip this\n\tif [ -n \"${ANSPASS_PATH}\" -a -n \"${ANSPASS_TOKEN}\" ]; then\n\t\treturn 0\n\tfi\n\n\t# We want to use askpass (if enabled), no reason to invoke\n\t# anspass yet.... unless the user passed in a user/pass\n\t# meaning they want an offline install, no Q's asked.\n\tif [ -n \"${WINDSHARE_USER}\" ]; then\n\t\tanspass_setup\n\t\treturn $?\n\tfi\n\n\treturn 0\n}\n\n# anspass_stop defined in setup_anspass\nanspass_shutdown() {\n\tanspass_stop\n}\n"
  },
  {
    "path": "data/environment.d/06_wrl_repo.sh",
    "content": "# Copyright (C) 2016 - 2021 Wind River Systems, Inc.\n#\n# This program is free software; you can redistribute it and/or modify\n# it under the terms of the GNU General Public License version 2 as\n# published by the Free Software Foundation.\n#\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n# See the GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program; if not, write to the Free Software\n# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n\n# Identify the right path for the Wind River version of git-repo\n# setup the REPO_URL to point there...\n\nsetup_add_arg --repo-url REPO_URL\nsetup_add_arg --repo-branch REPO_REV\n\nsetup_add_func wr_repo_setup\nsetup_add_func wr_repo_clone\n\n# Special windshare folders to search\nREPO_FOLDERS=\"WRLinux-lts-21-Core WRLinux-lts-21-Base\"\n\n. ${BASEDIR}/data/environment.d/setup_utils\n\nwr_repo_find() {\n\techo \"Searching for git-repo...\"\n\tREPO_URL=${BASEURL}/git-repo\n\n\tretries=0\n\tduration=5\n\tfor i in {1..5} ; do\n\t\tif ! setup_check_url \"${REPO_URL}\" ; then\n\t\t\t# Clear in case there are no REPO_FOLDERS\n\t\t\tREPO_URL=\"\"\n\t\t\tfor folder in ${REPO_FOLDERS} ; do\n\t\t\t\tREPO_URL=${BASEURL}/${folder}/git-repo\n\t\t\t\tif ! setup_check_url \"${REPO_URL}\" ; then\n\t\t\t\t\tREPO_URL=\"\"\n\t\t\t\t\tcontinue\n\t\t\t\tfi\n\t\t\t\tbreak\n\t\t\tdone\n\n\t\t\tif [ \"${REPO_URL}\" = \"\" ]; then\n\t\t\t\tretries=$(($retries+1))\n\t\t\t\techo \"Retrying $1 after $duration seconds -- $retries time(s) (max: 5)\"\n\t\t\t\tsleep $duration\n\t\t\t\tduration=$(($duration+$(random 1 5)))\n\t\t\tfi\n\t\telse\n\t\t\tbreak\n\t\tfi\n\tdone\n\n\tif [ $retries -eq 5 ]; then\n\t\techo \"Unable to find git-repo repository.  Search path:\" >&2\n\t\techo \"  ${BASEURL}/git-repo\" >&2\n\t\tfor folder in ${REPO_FOLDERS} ; do\n\t\t\techo \"  ${BASEURL}/${folder}/git-repo\" >&2\n\t\tdone\n\t\treturn 1\n\tfi\n\treturn 0\n}\n\nrepo_branch_fallback=\"WRLINUX_10_21_BASE\"\n\nwr_repo_setup() {\n\tlocal update_url\n\n\tupdate_url=true\n\n\t# If the user passed it in, we use it after we verify it!\n\tif [ -n \"$REPO_URL\" ]; then\n\t\tretries=0\n\t\tduration=5\n\t\tfor i in {1..5}; do\n\t\t\tif ! setup_check_url \"${REPO_URL}\" ; then\n\t\t\t\tretries=$(($retries+1))\n\t\t\t\techo \"Retrying $1 after $duration seconds -- $retries time(s) (max: 5)\"\n\t\t\t\tsleep $duration\n\t\t\t\tduration=$(($duration+$(random 1 5)))\n\t\t\tfi\n\t\tdone\n\n\t\tif [ $retries -eq 5 ]; then\n\t\t\techo \"Unable to find git-repo repository. ${REPO_URL}\" >&2\n\t\t\treturn 1\n\t\tfi\n\tfi\n\n\t# If we still don't know it, check the file...\n\tif [ -z \"$REPO_URL\" ]; then\n\t\tif [ -e bin/.git-repo ]; then\n\t\t\tREPO_URL=$(cat bin/.git-repo)\n\t\t\tupdate_url=false\n\t\t# If we still don't know it, go find it...\n\t\telif ! wr_repo_find ; then\n\t\t\treturn 1\n\t\tfi\n\tfi\n\n\t# Repo rev time...\n\t# User passed it in, verify it\n\tif [ -n \"$REPO_REV\" ]; then\n\t\tretries=0\n\t\tduration=5\n\n\t\tfor i in {1..5} ; do\n\t\t\toutput=$(setup_check_url_branch \"${REPO_URL}\" \"${REPO_REV}\")\n\t\t\tif [ \"$output\" != \"$REPO_REV\" -o $? -ne 0 ] ; then\n\t\t\t\tretries=$(($retries+1))\n\t\t\t\techo \"Retrying $1 after $duration seconds -- $retries time(s) (max: 5)\"\n\t\t\t\tsleep $duration\n\t\t\t\tduration=$(($duration+$(random 1 5)))\n\t\t\tfi\n\t\tdone\n\n\t\tif [ $retries -eq 5 ]; then\n\t\t\techo \"Unable to find branch ${REPO_REV} in git-repo repository (${REPO_URL})\" >&2\n\t\t\treturn 1\n\t\tfi\n\tfi\n\n\tif [ -z \"$REPO_REV\" ]; then\n\t\tBASEBRANCHES[0]=${BASEBRANCH}\n\t\t# Skip master-wr, we don't use this branch any longer in git-repo...\n\t\tif [ \"${BASEBRANCHES[0]}\" == \"master-wr\" ]; then\n\t\t\tBASEBRANCHES[0]=\"$repo_branch_fallback\"\n\t\tfi\n\t\tif [ \"${BASEBRANCHES[0]}\" != \"$repo_branch_fallback\" ]; then\n\t\t\tBASEBRANCHES[1]=\"$repo_branch_fallback\"\n\t\tfi\n\t\tretries=0\n\t\tduration=5\n\t\tfor i in {1..5} ; do\n\t\t\tREPO_REV=$(setup_check_url_branch \"${REPO_URL}\" \"${BASEBRANCHES[@]}\")\n\t\t\tif [ -z \"${REPO_REV}\" ]; then\n\t\t\t\tretries=$(($retries+1))\n\t\t\t\techo \"Retrying $1 after $duration seconds -- $retries time(s) (max: 5)\"\n\t\t\t\tsleep $duration\n\t\t\t\tduration=$(($duration+$(random 1 5)))\n\t\t\tfi\n\t\tdone\n\n\t\tif [ $retries -eq 5 ];then\n\t\t\techo \"Unable to find a usable branch (${BASEBRANCHES[@]}) in git-repo repository (${REPO_URL})\" >&2\n\t\t\treturn 1\n\t\tfi\n\tfi\n\n\t# Ensure subsequent 'repo' calls use the correct URL\n\tif $update_url ; then\n\t\techo ${REPO_URL} > bin/.git-repo\n\tfi\n\texport REPO_URL\n\n\texport REPO_REV\n\n\treturn 0\n}\n\nwr_repo_clone() {\n\t# git-repo is limited to working on it's own branches only.\n\t# In otherwords, we can't checkout a tag in git-repo and work with it,\n\t# otherwise we get numerous errors that things fail due to them not being\n\t# based on branches.\n\t#\n\t# Due to the design of git-repo, it is safe to use the latest version\n\t# on a branch associated with the tag.  For instance, if the tag\n\t# vWRLINUX_CI_10.19.29.0 is a tag based on WRLINUX_CI branch, we can just\n\t# use the branch for cloning.\n\t#\n\n\t# Since we can't check what branch the tag is from w/o a clone, we clone...\n\tif [ ! -d bin/git-repo ]; then\n\t\ttrap : INT\n\t\tgit clone \"${REPO_URL}\" bin/git-repo\n\t\tif [ $? -ne 0 ]; then\n\t\t\techo \"Unable to clone git-repo from ${REPO_URL}.\" >&2\n\t\t\treturn 1\n\t\tfi\n\t\ttrap - INT\n\telse\n\t\tif [ \"${REPO_URL}\" != \"$(git config -f bin/git-repo/.git/config remote.origin.url)\" ]; then\n\t\t\techo \"Updating git-repo remote url\"\n\t\t\tgit config -f bin/git-repo/.git/config remote.origin.url \"${REPO_URL}\"\n\t\tfi\n\n\t\t# We always clear local changes to make sure we're synced up!\n\t\t(cd bin/git-repo && git remote update origin && git reset --hard @{upstream})\n\t\tif [ $? -ne 0 ]; then\n\t\t\techo \"WARNING: Unable to reset the git-repo respository.\" >&2\n\t\tfi\n\tfi\n\n\t# Translate REPO_REV, if a tag to a branch\n\tif [ \"$REPO_REV\" != \"${REPO_REV##refs/tags/}\" ]; then\n\t\t# Find the first branch containing that commit..\n\t\tREPO_BRANCH=$(cd bin/git-repo && git branch -r --contains ${REPO_REV}^{commit} 2>/dev/null | grep -v '\\->' | head -n 1)\n\t\tif [ -z ${REPO_BRANCH} ]; then\n\t\t\techo \"ERROR: Unable to find branch containing $REPO_REV in git-repo repository.\"\n\t\t\texit 1\n\t\tfi\n\t\t# Strip spaces\n\t\tREPO_BRANCH=$(echo ${REPO_BRANCH})\n\t\t# Turn into a local branch\n\t\tREPO_BRANCH=${REPO_BRANCH##origin/}\n\t\techo \"Translated tag ${REPO_REV} to branch ${REPO_BRANCH}\"\n\n\t\tREPO_REV=$REPO_BRANCH\n\tfi\n\n\tif [ \"* ${REPO_REV}\" != \"$(cd bin/git-repo && git branch | grep '\\*')\" ]; then\n\t\t(cd bin/git-repo && git checkout ${REPO_REV})\n\t\tif [ $? -ne 0 ]; then\n\t\t\techo \"ERROR: Unable to checkout branch ${REPO_REV}\" >&2\n\t\t\treturn 1\n\t\tfi\n\tfi\n\n\tif [ -d .repo/repo/.git ]; then\n\t\techo \"Syncing git-repo to configured .repo/repo\"\n\t\trepo_resync=false\n\t\tbin_repo_url=$(git config -f bin/git-repo/.git/config remote.origin.url)\n\t\tgit_repo_url=$(git config -f .repo/repo/.git/config remote.origin.url)\n\t\tif [ \"${bin_repo_url}\" != \"${git_repo_url}\" ]; then\n\t\t\tgit config -f .repo/repo/.git/config remote.origin.url \"${bin_repo_url}\"\n\t\t\trepo_resync=true\n\t\tfi\n\t\tbin_repo_branch=$(git config -f bin/git-repo/.git/config branch.${REPO_REV}.merge)\n\t\tgit_repo_branch=$(git config -f .repo/repo/.git/config branch.default.merge)\n\t\tif [ \"${bin_repo_branch}\" != \"${git_repo_branch}\" ]; then\n\t\t\tgit config -f .repo/repo/.git/config branch.default.merge \"${bin_repo_branch}\"\n\t\t\trepo_resync=true\n\t\t\tgit_repo_branch=$(git config -f .repo/repo/.git/config branch.default.merge)\n\t\tfi\n\t\tif $repo_resync ; then\n\t\t\t(cd .repo/repo && git remote update origin) || exit 1\n\t\t\t(cd .repo/repo && git reset --hard @{upstream}) || exit 1\n\t\tfi\n\tfi\n\n\n\texport PATH=$(cd bin/git-repo && pwd):$PATH\n}\n"
  },
  {
    "path": "data/environment.d/07_toaster_update.sh",
    "content": "# Copyright (C) 2017 Wind River Systems, Inc.\n#\n# This program is free software; you can redistribute it and/or modify\n# it under the terms of the GNU General Public License version 2 as\n# published by the Free Software Foundation.\n#\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n# See the GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program; if not, write to the Free Software\n# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n\n# Regenerate the wrlinux-specific Toaster fixture file based on the \n# current 'layers_wrs_com.json' and 'default.xml'\n\nsetup_shutdown_func update_toaster_fixture_stop\n\nupdate_toaster_fixture_stop() {\n    if [ -f default.xml ] && [ -d bitbake ] ; then\n        # generate the wrlinux-specific Toaster fixture file\n        $BASEDIR/bin/toaster_fixture.py --project-dir $PWD\n    fi\n}\n\n"
  },
  {
    "path": "data/environment.d/check_update.sh",
    "content": "# Copyright (C) 2016 Wind River Systems, Inc.\n#\n# This program is free software; you can redistribute it and/or modify\n# it under the terms of the GNU General Public License version 2 as\n# published by the Free Software Foundation.\n#\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n# See the GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program; if not, write to the Free Software\n# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n\n# Check if this is an existing product, if the default.xml has beeen changed\n# warning the user they may need to update any build directories\n\nsetup_add_func check_update_start\nsetup_shutdown_func check_update_stop\n\ncheck_update_start() {\n\tif [ -e config/bblayers.conf.sample ]; then\n\t\tSHASUM_BBLAYERS=$(shasum config/bblayers.conf.sample | cut -d ' ' -f 1)\n\tfi\n\n\tif [ -e config/local.conf.sample ]; then\n\t\tSHASUM_LOCALCONF=$(shasum config/local.conf.sample | cut -d ' ' -f 1)\n\tfi\n}\n\ncheck_update_stop() {\n\tif [ -e config/bblayers.conf.sample -a -n \"${SHASUM_BBLAYERS}\" ]; then\n\t\tNEW_SHASUM=$(shasum config/bblayers.conf.sample | cut -d ' ' -f 1)\n\t\tif [ \"${NEW_SHASUM}\" != \"${SHASUM_BBLAYERS}\" ]; then\n\t\t\tcat << EOF\n\nNote: The project layers have been updated. You should inspect the\nconf/bblayers.conf file in all build directories and syncronize them to match\nthe updated conf/bblayers.conf.sample file, as necessary.\n\nEOF\n\t\tfi\n\tfi\n\n\tif [ -e config/local.conf.sample -a -n \"${SHASUM_LOCALCONF}\" ]; then\n\t\tNEW_SHASUM=$(shasum config/local.conf.sample | cut -d ' ' -f 1)\n\t\tif [ \"${NEW_SHASUM}\" != \"${SHASUM_LOCALCONF}\" ]; then\n\t\t\tcat << EOF\n\nNote: The project local.conf.sample has been updated.  You should inspect the\nconf/local.conf file in all build directories and syncronize them to match,\nas necessary.\n\nEOF\n\t\tfi\n\tfi\n}\n"
  },
  {
    "path": "data/environment.d/kernel_type.sh",
    "content": "# Copyright (C) 2017 Wind River Systems, Inc.\n#\n# This program is free software; you can redistribute it and/or modify\n# it under the terms of the GNU General Public License version 2 as\n# published by the Free Software Foundation.\n#\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n# See the GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program; if not, write to the Free Software\n# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n\n# For compatibility with the commercial version, we need to allow for the\n# accept-eula argument, even though it's a no-op\n\n# We don't 'keep' this command & argument as the option is not longer used.\nsetup_add_arg --kernel KTYPE\n\nsetup_add_func ktype_check\n\nktype_check() {\n\tif [ -n \"${KTYPE+x}\" ]; then\n\t\techo\n\t\techo \"WARNING: argument --kernel is no longer supported and will be ignored.\" >&2\n\t\techo \"         To adjust the LINUX_KERNEL_TYPE, edit the build conf/local.conf file.\" >&2\n\t\techo\n\tfi\n}\n"
  },
  {
    "path": "data/environment.d/setup_anspass",
    "content": "# Copyright (C) 2016 Wind River Systems, Inc.\n#\n# This program is free software; you can redistribute it and/or modify\n# it under the terms of the GNU General Public License version 2 as\n# published by the Free Software Foundation.\n#\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n# See the GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program; if not, write to the Free Software\n# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n\n# This needs to run after anspass is installed by the buildtools-tarball\n# Transfer askpass to anspass\nanspass_transfer() {\n\turls=\"\"\n\ttype=unknown\n\twhile read line; do\n\t\tcase \"$line\" in\n\t\t\tUsername*)\n\t\t\t\turl=$(echo $line | sed \"s,Username for '\\(.*\\)': *,\\1,\")\n\t\t\t\ttype=username\n\t\t\t\t;;\n\t\t\tPassword*)\n\t\t\t\turl=$(echo $line | sed \"s,Password for '\\(.*\\)': *,\\1,\")\n\t\t\t\turl=$(echo $url | sed \"s,\\([^:]*://\\)\\(.*\\)@\\([^@]*\\),\\1\\3,\")\n\t\t\t\ttype=password\n\t\t\t\t;;\n\t\t\t*)\n\t\t\t\tif [ $type == \"unknown\" -o -z \"$line\" ] ; then\n\t\t\t\t\tcontinue\n\t\t\t\tfi\n\t\t\t\tmurl=$(echo $url | sed 's,[-:/.@],_,g')\n\t\t\t\tif [ \"${urls}\" == \"${urls/$murl/}\" ]; then\n\t\t\t\t\turls=\"$urls $murl\"\n\t\t\t\tfi\n\t\t\t\teval url_${murl}=\"${url}\"\n\t\t\t\tcase $type in\n\t\t\t\t\tusername)\n\t\t\t\t\t\teval username_${murl}=\\${line}\n\t\t\t\t\t\t;;\n\t\t\t\t\tpassword)\n\t\t\t\t\t\teval password_${murl}=\\${line}\n\t\t\t\t\t\t;;\n\t\t\t\tesac\n\t\t\t\t;;\n\t\tesac\n\tdone\n\n\tfor murl in $urls ; do\n\t\tanspass_transfer_dump | eval anspass-ctrl --add \\${url_${murl}} > /dev/null 2>&1\n\tdone\n}\n\nanspass_transfer_dump() {\n\teval echo \\${username_${murl}}\n\teval echo \\${password_${murl}}\n\teval echo \\${password_${murl}}\n}\n\nanspass_check_credential() {\n\terr=$(LANG=C git ls-remote $REMOTEURL 2>&1 >/dev/null)\n\tret=$?\n\tif [ $ret -ne 0 ] && [ \"${err}\" != \"${err/Authentication/}\" ]; then\n\t\techo\n\t\techo \"${err}\"\n\t\twhile true ; do\n\t\t\techo\n\t\t\techo \"The saved user or password seems invalid, remove it and try again?\"\n\t\t\tread -p \"Remove the anspass db bin/.anspass? [Yes/No]\" accept\n\t\t\tcase ${accept} in\n\t\t\t\t[yY][eE][sS])\n\t\t\t\t\tanspass_stop\n\t\t\t\t\trm -rf ${PWD}/bin/.anspass\n\t\t\t\t\tbreak\n\t\t\t\t\t;;\n\t\t\t\t[nN][oO])\n\t\t\t\t\tbreak\n\t\t\t\t\t;;\n\t\t\t\t*)\n\t\t\t\t\techo \"Only yes and no are accepted.\" >&2\n\t\t\t\t\t;;\n\t\t\tesac\n\t\tdone\n\tfi\n}\n\nanspass_start() {\n\t# Do we have anspassd available yet?\n\tif ! which anspassd >/dev/null 2>&1 ; then\n\t\treturn 0\n\tfi\n\n\t# Have we already configured anspass?\n\tif [ -n \"${ANSPASS_PATH}\" -a -n \"${ANSPASS_TOKEN}\" ]; then\n\t\treturn 0\n\tfi\n\n\techo \"Starting anspass...\"\n\n\texport ANSPASS_PATH=${PWD}/bin/.anspass\n\tresult=$(anspassd < /dev/null 2>&1)\n\tif [ $? -ne 0 ]; then\n\t\techo \"anspassd failed to start:\"\n\t\techo \"${result}\"\n\t\treturn 1\n\tfi\n\texport ANSPASS_TOKEN=$(echo \"$result\" | grep \"Token:\" | head -n 1 | sed 's,Token: ,,')\n\t#echo \"Token: ${ANSPASS_TOKEN}\"\n\twrl_anspass_started=1\n\n\treturn 0\n}\n\n\nanspass_setup() {\n\t# Do we have anspassd available yet?\n\tif ! which anspassd >/dev/null 2>&1 ; then\n\t\treturn 0\n\tfi\n\n\t# Have we already configured anspass?\n\tif [ -n \"${ANSPASS_PATH}\" -a -n \"${ANSPASS_TOKEN}\" ]; then\n\t\treturn 0\n\tfi\n\n\tWINDSHARE_SCHEME=$(echo ${BASEURL} | sed 's,\\([^:/]*\\).*,\\1,')\n\tif [ -n \"${WINDSHARE_SCHEME}\" ]; then\n\t\tWINDSHARE_HOST=$(echo ${BASEURL} | sed 's,\\([^:/]*\\)://\\([^/]*\\).*,\\2,')\n\tfi\n\n\t# Has anspass been started before?\n\tif [ -d ${PWD}/bin/.anspass ]; then\n\t\tanspass_start\n\t\trc=$?\n\t\tif [ $rc != 0 ]; then\n\t\t\treturn $rc\n\t\tfi\n\telse\n\t\treturn 0\n\tfi\n\n\t# If user/pass passed in, default these first (can't do this for a file path)\n\tif [ -n \"${WINDSHARE_USER}\" -a -n \"${WINDSHARE_HOST}\" ]; then\n\t\t# If this has already been set, delete it so we can add the new one\n\t\techo \"${WINDSHARE_USER}\" | anspass-ctrl --delete ${WINDSHARE_SCHEME}://${WINDSHARE_HOST} > /dev/null 2>&1\n\t\tcat << EOF | anspass-ctrl --add ${WINDSHARE_SCHEME}://${WINDSHARE_HOST} > /dev/null 2>&1\n${WINDSHARE_USER}\n${WINDSHARE_PASS}\n${WINDSHARE_PASS}\nEOF\n\t\tif [ $? -ne 0 ]; then\n\t\t\techo \"Unable to set the credentials for ${WINDSHARE_SCHEME}://${WINDSHARE_HOST}\" >&2\n\t\t\tanspass-ctrl --quit > /dev/null 2>&1\n\t\t\treturn 1\n\t\tfi\n\tfi\n\texport GIT_ASKPASS=$(which anspass)\n\texport SSH_ASKPASS=$(which anspass)\n\n\t# check the old credentials works or not\n\tanspass_check_credential\n}\n\nanspass_stop() {\n\tif [ -n \"${ANSPASS_PATH}\" -a -n \"${ANSPASS_TOKEN}\" ]; then\n\t\techo \"Stopping anspass...\"\n\t\tanspass-ctrl --quit >/dev/null 2>&1\n\t\tunset ANSPASS_PATH\n\t\tunset ANSPASS_TOKEN\n\tfi\n}\n"
  },
  {
    "path": "data/environment.d/setup_askpass",
    "content": "#! /usr/bin/env python3\n\n# Copyright (C) 2016 Wind River Systems, Inc.\n#\n# This program is free software; you can redistribute it and/or modify\n# it under the terms of the GNU General Public License version 2 as\n# published by the Free Software Foundation.\n#\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n# See the GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program; if not, write to the Free Software\n# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n\nimport os\nimport sys\nimport socket\nimport subprocess\nimport termios\n\nif len(sys.argv) <= 1:\n    sys.exit(0)\n\nnamed_socket = os.getenv(\"WRL_ASKPASS_SOCKET\")\nif not named_socket or named_socket == \"\":\n    print('You must specify a named pipe in WRL_ASKPASS_SOCKET.')\n    sys.exit(1)\n\nsock_dir = os.path.dirname(named_socket)\nsock_name = os.path.basename(named_socket)\n\n# Make sure the socket directory exists\nif not os.path.exists(sock_dir):\n    os.makedirs(sock_dir)\nos.chdir(sock_dir)\n\nif sys.argv[1] == '--server':\n    q_cache = {}\n\n    try:\n        os.unlink(sock_name)\n    except:\n        pass\n\n    s = socket.socket(socket.AF_UNIX)\n    s.bind(sock_name)\n    s.listen(1)\n    quit = False\n    while not quit:\n        conn, addr = s.accept()\n        while 1:\n            data = conn.recv(1024).decode()\n            if not data:\n                break\n            if data[0] == 'q':\n                q = data[1:]\n                response = ''\n                if q in q_cache:\n                    response = q_cache[q]\n                #print('Q: \"%s\"' % q)\n                #print('R: \"%s\"' % response)\n                conn.send(response.encode())\n                break\n            if data[0] == 's':\n                res = data.split('\\n')\n                q = res[0][1:]\n                a = res[1]\n                q_cache[q] = a\n                #print('S: \"%s\" = \"%s\"' % (q, q_cache[q]))\n                break\n            if data[0] == 'd':\n                for q in q_cache:\n                    if q == 'tty':\n                        continue\n                    #print('D: \"%s\" = \"%s\"' % (q, q_cache[q]))\n                    conn.send((q + '\\n' + q_cache[q][1:] + '\\n').encode())\n                break\n            if data[0] == 'x':\n                #print('quit')\n                quit = True\n                break\n            #print(\"skip: \" + data)\n        conn.close()\n\n    sys.exit(0)\n\nif sys.argv[1] == '--quit':\n    s = socket.socket(socket.AF_UNIX)\n    s.connect(sock_name)\n    s.send('x'.encode())\n    s.close()\n    sys.exit(0)\n\nif sys.argv[1] == '--set':\n    result = sys.stdin.readline()\n\n    s = socket.socket(socket.AF_UNIX)\n    s.connect(sock_name)\n    s.send(('s' + sys.argv[2] + '\\n' + 'A' + result).encode())\n    s.close()\n    sys.exit(0)\n\nif sys.argv[1] == '--dump':\n    s = socket.socket(socket.AF_UNIX)\n    s.connect(sock_name)\n    s.send('d'.encode())\n    while 1:\n        result = s.recv(1024).decode()\n        if not result:\n            break\n        print(result)\n    s.close()\n    sys.exit(0)\n\ns = socket.socket(socket.AF_UNIX)\ns.connect(sock_name)\ns.send(('q' + sys.argv[1]).encode())\nresult = s.recv(1024).decode()\ns.close()\nif result:\n    print(result[1:])\n    sys.exit(0)\n\ns = socket.socket(socket.AF_UNIX)\ns.connect(sock_name)\ns.send('qtty'.encode())\ntty_file = s.recv(1024)[1:].decode()\ns.close()\n\nif not tty_file:\n    tty_file = \"/dev/tty\"\n\nwith open(tty_file, 'wb+', buffering=0) as tty_fd:\n    if not tty_fd.isatty():\n        # Only operate on a tty\n        sys.exit(1)\n\n    question = sys.argv[1]\n\n    if question.startswith('Password') or question.endswith('password: '):\n        fd = tty_fd.fileno()\n        old = termios.tcgetattr(fd)\n        new = termios.tcgetattr(fd)\n\n        try:\n            # Disable echoing and signals\n            # If we don't disable signals, readline can get confused and\n            # 'break' the terminal, this way the user MUST enter 'something'\n            new[3] &= ~termios.ECHO\n            new[3] &= ~termios.ISIG\n            termios.tcsetattr(fd, termios.TCSADRAIN, new)\n            if termios.tcgetattr(fd)[3] != new[3]:\n                tty_fd.write(\"WARNING: Password may echo to the screen!\\n\".encode())\n            tty_fd.write(question.encode())\n            result = tty_fd.readline().decode()\n            tty_fd.write('\\n'.encode())\n        finally:\n            termios.tcsetattr(fd, termios.TCSADRAIN, old)\n    else:\n        tty_fd.write(question.encode())\n        result = tty_fd.readline().decode()\n\ns = socket.socket(socket.AF_UNIX)\ns.connect(sock_name)\ns.send(('s' + question + '\\n' + 'A'+ result).encode())\ns.close()\n\ns = socket.socket(socket.AF_UNIX)\ns.connect(sock_name)\ns.send(('q' + sys.argv[1]).encode())\nresult = s.recv(1024).decode()\ns.close()\nif result:\n    print(result[1:])\n"
  },
  {
    "path": "data/environment.d/setup_ssh",
    "content": "#! /bin/sh\n#\n# Intercept the SSH calls during the installer to ensure that we have control\n# over the display and terminal.\n#\n# ssh will always prompt the user for their passphrase (password) if the tty\n# is setup.  This avoids using SSH_ASKPASS, which is needed for the setup\n# functionality.\n#\n# We use setsid to break the tty connection, and also ensure that DISPLAY is\n# cleared.  This combination forces SSH to use 'SSH_ASKPASS'.\n#\n# Note: storying SSH credentials can be a bit sketchy, so it is recommended\n# to use an authorized_key file instead.  But askpass/anspass do their best\n# to obfuscate the data.\n#\n# Use this file by setting GIT_SSH=setup_ssh\n\nDISPLAY= setsid ssh $@\n"
  },
  {
    "path": "data/environment.d/setup_utils",
    "content": "# Copyright (C) 2016 Wind River Systems, Inc.\n#\n# This program is free software; you can redistribute it and/or modify\n# it under the terms of the GNU General Public License version 2 as\n# published by the Free Software Foundation.\n#\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n# See the GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program; if not, write to the Free Software\n# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n\n# These are common utility functions multiple environment scripts\n# This unit may be loaded more then once\n\n# $1 is the url (or file path) to check if it's a git repository\n# Function returns:\n#   0 if git repository is available\n#   1 if it's a bad path\n#   2 if authentication failed (and prints a message)\n#   3 an unknown error occurs (and prints a message)\nsetup_check_url() {\n\terr=$(LANG=C git ls-remote \"$1\" 2>&1 >/dev/null)\n\tret=$?\n\n\t# Found!\n\tif [ $ret -eq 0 ]; then\n\t\treturn 0\n\tfi\n\n\t# Check for authentication error...\n\tif [ \"${err}\" != \"${err/Authentication/}\" ]; then\n\t\techo \"Authentication failed for $1\" >&2\n\t\treturn 2\n\tfi\n\n\t# Check if it's just a bad path\n\tif [ \"${err}\" != \"${err/not found/}\" ]; then\n\t\t# This is a normal, git repo not found error\n\t\treturn 1\n\tfi\n\n\tif [ \"${err}\" != \"${err/Could not read/}\" ]; then\n\t\t# This is just a bad path, git repo not found error\n\t\treturn 1\n\tfi\n\n\t# This error is unique to git servers\n\tif [ \"${err}\" != \"${err/access denied or repository not exported/}\" ]; then\n\t\t# This is just a bad path, git repo not found error\n\t\treturn 1\n\tfi\n\n\t# Unknown error\n\techo \"An unknown error occured looking for $1\" >&2\n\techo \"$err\" >&2\n\treturn 3\n}\n\n# $1 is the url (or file path) to check if it's a git repository\n# $2...$n is the branches to check if they exist\n# Function returns:\n#   0 if git repository is available\n#   1 if it's a bad path\n#   2 if authentication failed (and prints a message)\n#   3 an unknown error occurs (and prints a message)\n#\n# stdout will be the first branch that exists (rc 0)\nsetup_check_url_branch() {\n\tlocal repo\n\trepo=$1\n\n\tshift\n\n\tsetup_check_url \"$repo\"\n\tret=$?\n\n\tif [ $? -ne 0 ]; then\n\t\treturn $ret\n\tfi\n\n\tlocal branch\n\tfor branch in \"$@\"; do\n\t\toutput=$(LANG=C git ls-remote \"$repo\" \"$branch\")\n\n\t\tif [ -n \"$output\" ]; then\n\t\t\techo $branch\n\t\t\treturn 0\n\t\tfi\n\tdone\n}\n\n# function to generate a random number between min and max\nrandom(){\n       min=$1\n       max=$(($2-$min+1))\n       num=$(($RANDOM+1000000000))\n       echo $(($num%$max+$min))\n}\n"
  },
  {
    "path": "data/local_layer/README",
    "content": "local layer\n===========\n\nThis layer is intended to work as a scratch space in the default projects.\n\n\nDependencies\n------------\nNone.\n\n\nMaintenance\n-----------\nThis layer is maintained by the project owner.\n\n\nLicense\n-------\nCopyright (C) 2013-2016 Wind River Systems, Inc.\n\nSource code included in the tree for individual recipes is under the LICENSE\nstated in the associated recipe (.bb file) unless otherwise stated.\n\nThe metadata is under the following license unless otherwise stated.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n\n"
  },
  {
    "path": "data/local_layer/classes/.keepme",
    "content": ""
  },
  {
    "path": "data/local_layer/conf/layer.conf",
    "content": "# We have a conf and classes directory, add to BBPATH\nBBPATH =. \"${LAYERDIR}:\"\n\n# We have a recipe-* directory, add to BBFILES\nBBFILES += \"${LAYERDIR}/recipes-*/*/*.bb \\\n            ${LAYERDIR}/recipes-*/*/*.bbappend\"\n\nBBFILE_COLLECTIONS += \"local\"\nBBFILE_PATTERN_local = \"^${LAYERDIR}/\"\nBBFILE_PRIORITY_local = \"1000\"\n\n# Add scripts to PATH\nPATH .= \":${LAYERDIR}/scripts\"\n\n# Allow the developer to put pre-downloaded src into the downloads directory\n# Also allow the user to have bare clones of repositories in the git directory\nPREMIRRORS_append = \"\\\n     .*://.*/.* file://${LAYERDIR}/downloads/ \\n \\\n     git://.*/.* git://${LAYERDIR}/git/BASENAME;protocol=file \\n \\\n\"\n\n# Enable the local layer unconditionally if the whitelist in enabled\nPNWHITELIST_LAYERS_remove = \"local\"\n\n# We are compatiable with all the possibilities.\n#\nLAYERSERIES_COMPAT_local = \"${LAYERSERIES_CORENAMES}\"\n"
  },
  {
    "path": "data/local_layer/downloads/.keepme",
    "content": ""
  },
  {
    "path": "data/local_layer/git/.keepme",
    "content": ""
  },
  {
    "path": "data/local_layer/recipes-sample/hello/hello/hello.c",
    "content": "/*\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",
    "content": "DESCRIPTION = \"This package contains the simple Hello World program.\"\nLICENSE = \"windriver\"\nLICENSE_FLAGS = \"commercial_windriver\"\nLIC_FILES_CHKSUM = \"file://hello.c;beginline=1;endline=3;md5=3e8f741b049bec8146c81a2667ab4b45\"\n\nSECTION = \"sample\"\n\nPR = \"r1\"\n\nSRC_URI = \"file://hello.c\"\n\nS = \"${WORKDIR}\"\n\ndo_compile() {\n  ${CC} ${CFLAGS} ${LDFLAGS} -o hello hello.c\n}\n\ndo_install() {\n  install -d ${D}${bindir}\n  install -m 0755 hello ${D}${bindir}\n}\n"
  },
  {
    "path": "data/local_layer/scripts/.keepme",
    "content": ""
  },
  {
    "path": "data/samples/README-MIRROR.sample",
    "content": "This is a Wind River Linux Repository Mirror.  It was constructed by the setup\nprogram using the following arguments:\n\n####SETUP_ARGS####\n\n\nTo update your mirror\n----------------------\nThe preferred way of updating your repository mirror is to re-run the setup\nprogram.\n\nFirst you should update the wrlinux-x, for example:\n\n$ cd wrlinux-x\n$ git pull\n$ cd ..\n\nThen re-run the setup program with the original arguments.\n\n$ wrlinux-x/setup.sh ####SETUP_ARGS####\n\nYou can change the arguments to the setup program.  This will change the\nwhat is downloaded as part of your repository mirror.  If repositories have\nbeen removed, it may break users of this mirror.\n"
  },
  {
    "path": "data/samples/README.sample",
    "content": "This is a Wind River Linux build project.  It was constructed by the\nsetup.sh tool using the following arguments:\n\n####SETUP_ARGS####\n\n\nBuildtools\n----------\nWind River provides special host build-tools in order to supplement the\nbuild systems tools.  While this is not required, it can solve many\nproblems with missing or incompatible host tools.  These tools are installed\ninto bin/buildtools.\n\nWe recomend you always source this into your environment each time you\nopen a new shell session, and before issueing any build system commands.\nTo do this:\n\n$ . ./environment-setup-<host>-wrlinuxsdk-linux\n\n\nQuickstart Instructions\n-----------------------\nOnce you have sourced the environment file, as noted above...\n\nYou must first create a build directory:\n\n$ . ./oe-init-build-env <build>\n\nThe <build> is the directory to create, if not specified the system will\ndefault to the directory 'build'.\n\nOnce the build directory has been created, the system will change your\nworking directory to be inside of the build directory.  Each time you\nopen a new shell session you will need to source the oe-init-build-env\nscript as indicated above.\n\nOnce in the build directory edit the 'conf/local.conf' file.  Please\nrefer to the comments in the file for specific configuration instructions.\n\nAfter configuring your build directory, you may now run bitbake commands.\nNote that bitbake, actually python3, requires the LANG environment variable\nto be a utf-8 variant, e.g. en_US.UTF-8, or it will terminate with an error.\nBitbake commands are of the format: bitbake <recipe>\n\nFor example:\n\n$ export LANG=en_US.UTF-8      # if needed\n$ bitbake core-image-minimal\n\nor\n\n$ LANG=en_US.UTF-8 bitbake core-image-minimal\n\nOnce your have built an image, you can boot this using QEMU (for compatible\nMACHINE settings) using the 'runqemu' command, such as:\n\n$ runqemu qemux86-64\n\n\nTo update your project\n----------------------\nTo update your project, you must update the platform project git repository\nand re-run the setup.sh tool.\n\nFirst update wrlinux-x, for example:\n\n$ cd wrlinux-x\n$ git pull\n$ cd ..\n\nThen re-run the setup.sh tool with the original arguments.\n\n$ wrlinux-x/setup.sh ####SETUP_ARGS####\n\nNote: existing local.conf and bblayers.conf files are not modified by\nsetup.sh tool -- you will have to update them manually, or start a new build\ndirectory.\n\n\nLocal layer\n-----------\nA special 'local' layer has been added to your project automatically.\nThis layer is located at the path 'layers/local' in your project.\n\nThe purpose of the local layer is a staging location for your project\nwork, including any new recipes, classes or scripts.\n"
  },
  {
    "path": "data/samples/bblayers.conf.sample",
    "content": "# LAYER_CONF_VERSION is increased each time build/conf/bblayers.conf\n# changes incompatibly\nLCONF_VERSION = \"7\"\n\nBBPATH = \"${TOPDIR}\"\nBBFILES ?= \"\"\n\nBBLAYERS ?= \" \\\n  ####LAYERS#### \\\n  ##OEROOT##/layers/local \\\n  \"\n"
  },
  {
    "path": "data/samples/conf-notes.sample",
    "content": "This project was configured with the following options:\n    ####SETUP_ARGS####\n\nCommon Wind River images are:\n    wrlinux-image-small     (suggests distro: wrlinux and feature/busybox)\n    wrlinux-image-core      (suggests distro: wrlinux)\n    wrlinux-image-std       (suggests distro: wrlinux)\n    wrlinux-image-std-sato  (requires distro: wrlinux-graphics)\n\nCommon Yocto Project images, typically built with distro poky, are:\n    core-image-minimal\n    core-image-base\n    core-image-sato\n\nYou can also run generated qemu images with a command like 'runqemu qemux86-64'\n\nOther commonly useful commands are:\n - 'devtool' and 'recipetool' handle common recipe tasks\n - 'bitbake-layers' handles common layer tasks\n - 'oe-pkgdata-util' handles common target package tasks\n"
  },
  {
    "path": "data/samples/local.conf.sample",
    "content": "#\n# This file is your local configuration file and is where all local user settings\n# are placed. The comments in this file give some guide to the options a new user\n# to the system might want to change but pretty much any configuration option can\n# be set in this file. More adventurous users can look at local.conf.extended\n# which contains other examples of configuration which can be placed in this file\n# but new users likely won't need any of them initially.\n#\n# Lines starting with the '#' character are commented out and in some cases the\n# default values are provided as comments to show people example syntax. Enabling\n# the option is a question of removing the # character and making any change to the\n# variable as required.\n\n#\n# Network Control\n#\n# Disable bitbake from being able to access the network\nBB_NO_NETWORK ?= '1'\n\n# Only allow downloads from PREMIRRORs, not search the main SRC_URI or MIRRORS.\n# If you have enabled download (dl-layers), use this to restrict fetch to those\n# layers. This also has a side effect of telling the system to ensure the\n# fetched repositories from the local download layer (pre)mirrors are\n# up-to-date.\nBB_FETCH_PREMIRRORONLY ?= '${@d.getVar('BB_NO_NETWORK') or 0}'\n\n#\n# Wind River Linux Templates\n#\n# The following variables control the template inclusion mechanism.\n#\n# Specify templates you wish to use in a space separated list.\nWRTEMPLATE ?= \"####DEFAULTWRTEMPLATE####\"\n\n# If you want to disable one or more templates\n# Note: this matches the 'end' of any templates that were found.. so you can do\n# things like:\n#\n#  default (skip all default templates)\n#  feature/foobar (skip all layers feature/foobar)\n#  wr-base/feature/foobar (skip only feature/foobar in wr-base)\n#WRTEMPLATE_SKIP = \"feature/item3 feature/item4 ...\"\n\n# Selectively enable or disable the template 'image.inc' additions to a given\n# image recipe.\n# (the default value is 1)\n#WRTEMPLATE_IMAGE_pn-<recipe> = \"0\"\n\n# Disable or enable processing of the special 'bsp-pkgs.*' template pieces.\n# (the default value is 1)\n#WRTEMPLATE_BSP_PKGS = \"0\"\n\n#\n# Machine Selection\n#\n# You need to select a specific machine to target the build with.\n# Some machines are emulated, usually the name starts with qemu, these can boot\n# and run in the QEMU emulator:\n#\n#MACHINE ?= \"####MACHINES####\"\n#\n# This sets the default machine if no other machine has been selected:\nMACHINE ??= \"####DEFAULTMACHINE####\"\n\n#\n# Linux Kernel Type\n#\n# The kernel type is selected by the recipe that provides the kernel.\n# By default, this recipe is selected by the DISTRO.\n#\n# If you want to override the default kernel, you must select the desired\n# recipe via PREFERRED_PROVIDER_virtual/kernel.\n#\n# To select a specific kernel recipe, uncomment the line below\n# and set the value.\n#\n# Typical values include: linux-yocto, linux-yocto-rt, and linux-yocto-tiny\n#\n#PREFERRED_PROVIDER_virtual/kernel = \"linux-yocto\"\n\n#\n# Where to place downloads\n#\n# During a first build the system will download many different source code tarballs\n# from various upstream projects. This can take a while, particularly if your network\n# connection is slow. These are all stored in DL_DIR. When wiping and rebuilding you\n# can preserve this directory to speed up this part of subsequent builds. This directory\n# is safe to share between multiple builds on the same machine too.\n#\n# The default is a downloads directory under TOPDIR which is the build directory.\n#\n#DL_DIR ?= \"${TOPDIR}/downloads\"\n\n#\n# Where to place shared-state files\n#\n# BitBake has the capability to accelerate builds based on previously built output.\n# This is done using \"shared state\" files which can be thought of as cache objects\n# and this option determines where those files are placed.\n#\n# You can wipe out TMPDIR leaving this directory intact and the build would regenerate\n# from these files if no changes were made to the configuration. If changes were made\n# to the configuration, only shared state files where the state was still valid would\n# be used (done using checksums).\n#\n# The default is a sstate-cache directory under TOPDIR.\n#\n#SSTATE_DIR ?= \"${TOPDIR}/sstate-cache\"\n\n#\n# Where to place the build output\n#\n# This option specifies where the bulk of the building work should be done and\n# where BitBake should place its temporary files and output. Keep in mind that\n# this includes the extraction and compilation of many applications and the toolchain\n# which can use Gigabytes of hard disk space.\n#\n# The default is a tmp directory under TOPDIR.\n#\n#TMPDIR = \"${TOPDIR}/tmp\"\n\n#\n# Default policy config\n#\n# The distribution setting controls which policy settings are used as defaults.\n# The default value is fine for general Yocto project use, at least initially.\n# Ultimately when creating custom policy, people will likely end up subclassing \n# these defaults.\n#\n#DISTRO ?= \"####DISTROS####\"\n#\n# This sets the default distro if no other distro has been selected:\nDISTRO ??= \"####DEFAULTDISTRO####\"\n\n#\n# Package Management configuration\n#\n# This variable lists which packaging formats to enable. Multiple package backends\n# can be enabled at once and the first item listed in the variable will be used\n# to generate the root filesystems.\n# Options are:\n#  - 'package_deb' for debian style deb files\n#  - 'package_ipk' for ipk files are used by opkg (a debian style embedded package manager)\n#  - 'package_rpm' for rpm style packages\n# E.g.: PACKAGE_CLASSES ?= \"package_rpm package_deb package_ipk\"\n# We default to rpm:\nPACKAGE_CLASSES ?= \"package_rpm\"\n\n#\n# SDK target architecture\n#\n# This variable specifies the architecture to build SDK items for and means\n# you can build the SDK packages for architectures other than the machine you are\n# running the build on (i.e. building i686 packages on an x86_64 host).\n# Supported values are i686 and x86_64\n#SDKMACHINE ?= \"i686\"\n\n#\n# Extra image configuration defaults\n#\n# The EXTRA_IMAGE_FEATURES variable allows extra packages to be added to the generated\n# images. Some of these options are added to certain image types automatically. The\n# variable can contain the following options:\n#  \"dbg-pkgs\"       - add -dbg packages for all installed packages\n#                     (adds symbol information for debugging/profiling)\n#  \"src-pkgs\"       - add -src packages for all installed packages\n#                     (adds source code for debugging)\n#  \"dev-pkgs\"       - add -dev packages for all installed packages\n#                     (useful if you want to develop against libs in the image)\n#  \"ptest-pkgs\"     - add -ptest packages for all ptest-enabled packages\n#                     (useful if you want to run the package test suites)\n#  \"tools-sdk\"      - add development tools (gcc, make, pkgconfig etc.)\n#  \"tools-debug\"    - add debugging tools (gdb, strace)\n#  \"eclipse-debug\"  - add Eclipse remote debugging support\n#  \"tools-profile\"  - add profiling tools (oprofile, lttng, valgrind)\n#  \"tools-testapps\" - add useful testing tools (ts_print, aplay, arecord etc.)\n#  \"debug-tweaks\"   - make an image suitable for development\n#                     e.g. ssh root access has a blank password\n# There are other application targets that can be used here too, see\n# meta/classes/image.bbclass and meta/classes/core-image.bbclass for more details.\n# We default to enabling the debugging tweaks.\nEXTRA_IMAGE_FEATURES ?= \"debug-tweaks\"\n\n#\n# Additional image features\n#\n# The following is a list of additional classes to use when building images which\n# enable extra features. Some available options which can be included in this variable\n# are:\n#   - 'buildstats' collect build statistics\n#   - 'image-prelink' in order to prelink the filesystem image\nUSER_CLASSES ?= \"buildstats image-prelink\"\n\n#\n# Additional rootfs image types\n#\n# The following is a partial list of additional image filesystem types that\n# may be supported by the configured machine;\n#   - 'tar.gz' to create a gzip compressed tarball of the image\n#   - 'tar.bz2' to create a bz2 compressed tarball of the image\n#   - 'ext4' to create an ext4 image\n#\n# NOTE:\n# Due to the way the OpenEmbedded build system processes this variable,\n# you cannot update its contents by using _append or _prepend. You must use\n# the += operator to add one or more options to the IMAGE_FSTYPES variable.\nIMAGE_FSTYPES += \"tar.bz2\"\n\n# The following options will build a companion 'debug filesystem' in addition\n# to the normal deployable filesystem.  This companion system allows a\n# debugger to know the symbols and related sources.  It can be used to\n# debug a remote 'production' system without having to add the debug symbols\n# and sources to remote system.  If IMAGE_FSTYPES_DEBUGFS is not defined, it\n# defaults to IMAGE_FSTYPES.\n#IMAGE_GEN_DEBUGFS = \"1\"\n#IMAGE_FSTYPES_DEBUGFS = \"tar.bz2\"\n\n# The network based PR service host and port\n# Uncomment the following lines to enable PRservice.\n# Set PRSERV_HOST to 'localhost:0' to automatically\n# start local PRService.\n# Set to other values to use remote PRService.\n#PRSERV_HOST = \"localhost:0\"\n\n#\n# Runtime testing of images\n#\n# The build system can test booting virtual machine images under qemu (an emulator)\n# after any root filesystems are created and run tests against those images. It can also\n# run tests against any SDK that are built. To enable this uncomment these lines.\n# See classes/test{image,sdk}.bbclass for further details.\n#IMAGE_CLASSES += \"testimage testsdk\"\n#TESTIMAGE_AUTO_qemuall = \"1\"\n# Note: test image requires sshd and scp support on the target, this can be added by\n# adding one of the following two lines.\n#IMAGE_INSTALL_append = \" openssh-sshd openssh-scp\"\n#IMAGE_INSTALL_append = \" dropbear\"\n\n#\n# Interactive shell configuration\n#\n# Under certain circumstances the system may need input from you and to do this it\n# can launch an interactive shell. It needs to do this since the build is\n# multithreaded and needs to be able to handle the case where more than one parallel\n# process may require the user's attention. The default is iterate over the available\n# terminal types to find one that works.\n#\n# Examples of the occasions this may happen are when resolving patches which cannot\n# be applied, to use the devshell or the kernel menuconfig\n#\n# Supported values are auto, gnome, xfce, rxvt, screen, konsole (KDE 3.x only), none\n# Note: currently, Konsole support only works for KDE 3.x due to the way\n# newer Konsole versions behave\n#OE_TERMINAL = \"auto\"\n# By default disable interactive patch resolution (tasks will just fail instead):\nPATCHRESOLVE = \"noop\"\n\n#\n# Disk Space Monitoring during the build\n#\n# Monitor the disk space during the build. If there is less that 1GB of space or less\n# than 100K inodes in any key build location (TMPDIR, DL_DIR, SSTATE_DIR), gracefully\n# shutdown the build. If there is less that 100MB or 1K inodes, perform a hard abort\n# of the build. The reason for this is that running completely out of space can corrupt\n# files and damages the build in ways which may not be easily recoverable.\n# It's necesary to monitor /tmp, if there is no space left the build will fail\n# with very exotic errors.\nBB_DISKMON_DIRS ??= \"\\\n    STOPTASKS,${TMPDIR},1G,100K \\\n    STOPTASKS,${DL_DIR},1G,100K \\\n    STOPTASKS,${SSTATE_DIR},1G,100K \\\n    STOPTASKS,/tmp,100M,100K \\\n    ABORT,${TMPDIR},100M,1K \\\n    ABORT,${DL_DIR},100M,1K \\\n    ABORT,${SSTATE_DIR},100M,1K \\\n    ABORT,/tmp,10M,1K\"\n\n#\n# Shared-state files from other locations\n#\n# As mentioned above, shared state files are prebuilt cache data objects which can\n# used to accelerate build time. This variable can be used to configure the system\n# to search other mirror locations for these objects before it builds the data itself.\n#\n# This can be a filesystem directory, or a remote url such as http or ftp. These\n# would contain the sstate-cache results from previous builds (possibly from other\n# machines). This variable works like fetcher MIRRORS/PREMIRRORS and points to the\n# cache locations to check for the shared objects.\n# NOTE: if the mirror uses the same structure as SSTATE_DIR, you need to add PATH\n# at the end as shown in the examples below. This will be substituted with the\n# correct path within the directory structure.\n#SSTATE_MIRRORS ?= \"\\\n#file://.* http://someserver.tld/share/sstate/PATH;downloadfilename=PATH \\n \\\n#file://.* file:///some/local/dir/sstate/PATH\"\n#\n# Make sstate can be downloaded from network when BB_NO_NETWORK is set to 1\n#SSTATE_MIRROR_ALLOW_NETWORK ?= \"1\"\n\n# Select the default init manager\n# use systemd as the default init manager\nDISTRO_FEATURES_append = \" systemd\"\nDISTRO_FEATURES_BACKFILL_CONSIDERED += \"sysvinit\"\nVIRTUAL-RUNTIME_init_manager = \"systemd\"\nVIRTUAL-RUNTIME_initscripts = \"systemd-compat-units\"\nKERNEL_FEATURES_append = \" cfg/systemd.scc\"\n\n# use sysvinit as the default init manager\n#DISTRO_FEATURES_append = \" sysvinit\"\n#DISTRO_FEATURES_BACKFILL_CONSIDERED += \"systemd\"\n#VIRTUAL-RUNTIME_init_manager = \"sysvinit\"\n#VIRTUAL-RUNTIME_initscripts = \"initscripts\"\n\n#\n# Qemu configuration\n#\n# By default qemu will build with a builtin VNC server where graphical output can be\n# seen. The two lines below enable the SDL backend too. By default libsdl2-native will\n# be built, if you want to use your host's libSDL instead of the minimal libsdl built\n# by libsdl2-native then uncomment the ASSUME_PROVIDED line below.\nPACKAGECONFIG_append_pn-qemu-system-native = \" sdl\"\nPACKAGECONFIG_append_pn-nativesdk-qemu = \" sdl\"\n#ASSUME_PROVIDED += \"libsdl2-native\"\n\n# CONF_VERSION is increased each time build/conf/ changes incompatibly and is used to\n# track the version of this file when it was generated. This can safely be ignored if\n# this doesn't mean anything to you.\nCONF_VERSION = \"1\"\n\n# The overrides osv-wrlinux will enable wrlinux specific bbappend\nOVERRIDES_append = \":osv-wrlinux\"\n\n# Add WRLinux uninative support\nrequire wrlinux-distro/conf/distro/include/wrlinux-uninative.inc\n\n# Exclude buildtools dir from pseudo database to fix do_package failure\nPSEUDO_IGNORE_PATHS .= \",##OEROOT##/bin\"\n"
  },
  {
    "path": "data/samples/site.conf.sample",
    "content": "#\n# local.conf covers user settings, site.conf covers site specific information\n# such as proxy server addresses and optionally any shared download location\n#\n# SITE_CONF_VERSION is increased each time build/conf/site.conf\n# changes incompatibly\nSCONF_VERSION = \"1\"\n\n# Uncomment to cause CVS to use the proxy host specified\n#CVS_PROXY_HOST = \"proxy.example.com\"\n#CVS_PROXY_PORT = \"81\"\n\n# For svn, you need to create ~/.subversion/servers containing:\n#[global]\n#http-proxy-host = proxy.example.com\n#http-proxy-port = 81\n#\n\n# To use git with a proxy, you must use an external git proxy command, such as\n# the one provided by scripts/oe-git-proxy. To use this script, copy it to\n# your PATH and uncomment the following:\n#GIT_PROXY_COMMAND ?= \"oe-git-proxy\"\n#ALL_PROXY ?= \"socks://socks.example.com:1080\"\n#or\n#ALL_PROXY ?= \"https://proxy.example.com:8080\"\n# If you wish to use certain hosts without the proxy, specify them in NO_PROXY.\n# See the script for details on syntax. The script oe-git-proxy uses some tools\n# that may not be included on HOSTTOOLS, thus  add them manually through\n# HOSTTOOLS += \"getent\"\n\n# Uncomment this to use a shared download directory\n#DL_DIR = \"/some/shared/download/directory/\"\n\n"
  },
  {
    "path": "data/xml/axxiaarm-dl.xml",
    "content": "    <project name=\"external/yocto/github.com.lsigithub.lsi_axxia_uboot_public\" remote=\"base\" path=\"layers/axxiaarm-dl/git/github.com.lsigithub.lsi_axxia_uboot_public.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.axxia.axxia_atf\" remote=\"base\" path=\"layers/axxiaarm-dl/git/github.com.axxia.axxia_atf.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.axxia.axxia_u-boot\" remote=\"base\" path=\"layers/axxiaarm-dl/git/github.com.axxia.axxia_u-boot.git\" bare=\"True\"/>\n"
  },
  {
    "path": "data/xml/bitbake.inc",
    "content": "        <linkfile src=\".\" dest=\"bitbake\"/>\n"
  },
  {
    "path": "data/xml/intel-socfpga-dl.xml",
    "content": "    <project name=\"external/yocto/github.com.altera-opensource.intel-rsu\" remote=\"base\" path=\"layers/intel-socfpga-dl/git/github.com.altera-opensource.intel-rsu.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.altera-opensource.u-boot-socfpga\" remote=\"base\" path=\"layers/intel-socfpga-dl/git/github.com.altera-opensource.u-boot-socfpga.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.altera-opensource.arm-trusted-firmware\" remote=\"base\" path=\"layers/intel-socfpga-dl/git/github.com.altera-opensource.arm-trusted-firmware.git\" bare=\"True\"/>\n"
  },
  {
    "path": "data/xml/meta-anaconda-dl.xml",
    "content": "    <project name=\"external/yocto/github.com.rhinstaller.python-simpleline\" remote=\"base\" path=\"layers/meta-anaconda-dl/git/github.com.rhinstaller.python-simpleline\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.release-engineering.productmd\" remote=\"base\" path=\"layers/meta-anaconda-dl/git/github.com.release-engineering.productmd\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.rhinstaller.dasbus\" remote=\"base\" path=\"layers/meta-anaconda-dl/git/github.com.rhinstaller.dasbus.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.rhinstaller.anaconda\" remote=\"base\" path=\"layers/meta-anaconda-dl/git/github.com.rhinstaller.anaconda\" bare=\"True\"/>\n"
  },
  {
    "path": "data/xml/meta-cgl-common-dl.xml",
    "content": "    <project name=\"external/yocto/github.com.ClusterLabs.cluster-glue\" remote=\"base\" path=\"layers/meta-cgl-common-dl/git/github.com.ClusterLabs.cluster-glue.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.markfasheh.ocfs2-tools\" remote=\"base\" path=\"layers/meta-cgl-common-dl/git/github.com.markfasheh.ocfs2-tools\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.ClusterLabs.crmsh\" remote=\"base\" path=\"layers/meta-cgl-common-dl/git/github.com.ClusterLabs.crmsh.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.ClusterLabs.resource-agents\" remote=\"base\" path=\"layers/meta-cgl-common-dl/git/github.com.ClusterLabs.resource-agents\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.ClusterLabs.pacemaker\" remote=\"base\" path=\"layers/meta-cgl-common-dl/git/github.com.ClusterLabs.pacemaker.git\" bare=\"True\"/>\n"
  },
  {
    "path": "data/xml/meta-clang-dl.xml",
    "content": "    <project name=\"external/yocto/github.com.iovisor.bcc\" remote=\"base\" path=\"layers/meta-clang-dl/git/github.com.iovisor.bcc\" bare=\"True\"/>\n"
  },
  {
    "path": "data/xml/meta-cloud-services-dl-3-3.xml",
    "content": "    <project name=\"external/ovp/gitlab.xiph.org.xiph.celt\" remote=\"base\" path=\"layers/meta-cloud-services-dl-3.3/git/gitlab.xiph.org.xiph.celt.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.fujita.tgt\" remote=\"base\" path=\"layers/meta-cloud-services-dl-3.3/git/github.com.fujita.tgt.git\" bare=\"True\"/>\n"
  },
  {
    "path": "data/xml/meta-dpdk-dl.xml",
    "content": "    <project name=\"external/yocto/dpdk.org.dpdk-stable\" remote=\"base\" path=\"layers/meta-dpdk-dl/git/dpdk.org.dpdk-stable\" bare=\"True\"/>\n"
  },
  {
    "path": "data/xml/meta-efi-secure-boot-dl.xml",
    "content": "    <project name=\"external/yocto/github.com.jiazhang0.SELoader\" remote=\"base\" path=\"layers/meta-efi-secure-boot-dl/git/github.com.jiazhang0.SELoader.git\" bare=\"True\"/>\n    <project name=\"external/yocto/git.kernel.org.pub.scm.linux.kernel.git.jejb.efitools\" remote=\"base\" path=\"layers/meta-efi-secure-boot-dl/git/git.kernel.org.pub.scm.linux.kernel.git.jejb.efitools.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.lcp.mokutil\" remote=\"base\" path=\"layers/meta-efi-secure-boot-dl/git/github.com.lcp.mokutil.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.rhboot.shim\" remote=\"base\" path=\"layers/meta-efi-secure-boot-dl/git/github.com.rhboot.shim.git\" bare=\"True\"/>\n"
  },
  {
    "path": "data/xml/meta-encrypted-storage-dl.xml",
    "content": "    <project name=\"external/yocto/github.com.jiazhang0.cryptfs-tpm2\" remote=\"base\" path=\"layers/meta-encrypted-storage-dl/git/github.com.jiazhang0.cryptfs-tpm2.git\" bare=\"True\"/>\n"
  },
  {
    "path": "data/xml/meta-freescale-dl.xml",
    "content": "    <project name=\"external/yocto/source.codeaurora.org.external.qoriq.qoriq-components.dpdk\" remote=\"base\" path=\"layers/meta-freescale-dl/git/source.codeaurora.org.external.qoriq.qoriq-components.dpdk\" bare=\"True\"/>\n    <project name=\"external/yocto/source.codeaurora.org.external.qoriq.qoriq-components.fmc\" remote=\"base\" path=\"layers/meta-freescale-dl/git/source.codeaurora.org.external.qoriq.qoriq-components.fmc\" bare=\"True\"/>\n    <project name=\"external/yocto/source.codeaurora.org.external.qoriq.qoriq-components.fmlib\" remote=\"base\" path=\"layers/meta-freescale-dl/git/source.codeaurora.org.external.qoriq.qoriq-components.fmlib\" bare=\"True\"/>\n    <project name=\"external/yocto/source.codeaurora.org.external.qoriq.qoriq-components.u-boot\" remote=\"base\" path=\"layers/meta-freescale-dl/git/source.codeaurora.org.external.qoriq.qoriq-components.u-boot\" bare=\"True\"/>\n    <project name=\"external/yocto/source.codeaurora.org.external.qoriq.qoriq-components.rcw\" remote=\"base\" path=\"layers/meta-freescale-dl/git/source.codeaurora.org.external.qoriq.qoriq-components.rcw\" bare=\"True\"/>\n    <project name=\"external/yocto/source.codeaurora.org.external.qoriq.qoriq-components.tsntool\" remote=\"base\" path=\"layers/meta-freescale-dl/git/source.codeaurora.org.external.qoriq.qoriq-components.tsntool.git\" bare=\"True\"/>\n    <project name=\"external/yocto/source.codeaurora.org.external.qoriq.qoriq-components.odp\" remote=\"base\" path=\"layers/meta-freescale-dl/git/source.codeaurora.org.external.qoriq.qoriq-components.odp\" bare=\"True\"/>\n    <project name=\"external/yocto/source.codeaurora.org.external.qoriq.qoriq-components.ofp\" remote=\"base\" path=\"layers/meta-freescale-dl/git/source.codeaurora.org.external.qoriq.qoriq-components.ofp\" bare=\"True\"/>\n    <project name=\"external/yocto/source.codeaurora.org.external.qoriq.qoriq-components.dce\" remote=\"base\" path=\"layers/meta-freescale-dl/git/source.codeaurora.org.external.qoriq.qoriq-components.dce\" bare=\"True\"/>\n    <project name=\"external/yocto/source.codeaurora.org.external.qoriq.qoriq-components.restool\" remote=\"base\" path=\"layers/meta-freescale-dl/git/source.codeaurora.org.external.qoriq.qoriq-components.restool\" bare=\"True\"/>\n    <project name=\"external/yocto/source.codeaurora.org.external.qoriq.qoriq-components.ceetm\" remote=\"base\" path=\"layers/meta-freescale-dl/git/source.codeaurora.org.external.qoriq.qoriq-components.ceetm\" bare=\"True\"/>\n    <project name=\"external/yocto/source.codeaurora.org.external.qoriq.qoriq-components.qbman_userspace\" remote=\"base\" path=\"layers/meta-freescale-dl/git/source.codeaurora.org.external.qoriq.qoriq-components.qbman_userspace\" bare=\"True\"/>\n    <project name=\"external/yocto/source.codeaurora.org.external.qoriq.qoriq-components.flib\" remote=\"base\" path=\"layers/meta-freescale-dl/git/source.codeaurora.org.external.qoriq.qoriq-components.flib\" bare=\"True\"/>\n"
  },
  {
    "path": "data/xml/meta-ids-dl.xml",
    "content": "    <project name=\"external/yocto/github.com.archiecobbs.mtree-port\" remote=\"base\" path=\"layers/meta-ids-dl/git/github.com.archiecobbs.mtree-port.git\" bare=\"True\"/>\n"
  },
  {
    "path": "data/xml/meta-integrity-dl.xml",
    "content": "    <project name=\"external/yocto/git.code.sf.net.p.linux-ima.ima-evm-utils\" remote=\"base\" path=\"layers/meta-integrity-dl/git/git.code.sf.net.p.linux-ima.ima-evm-utils.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.mgerstner.ima-inspect\" remote=\"base\" path=\"layers/meta-integrity-dl/git/github.com.mgerstner.ima-inspect.git\" bare=\"True\"/>\n"
  },
  {
    "path": "data/xml/meta-intel-dl.xml",
    "content": "    <project name=\"external/yocto/github.com.intel.Intel-Linux-Processor-Microcode-Data-Files\" remote=\"base\" path=\"layers/meta-intel-dl/git/github.com.intel.Intel-Linux-Processor-Microcode-Data-Files.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.intel.ittapi\" remote=\"base\" path=\"layers/meta-intel-dl/git/github.com.intel.ittapi.git\" bare=\"True\"/>\n"
  },
  {
    "path": "data/xml/meta-iot-cloud-dl.xml",
    "content": "    <project name=\"external/yocto/github.com.awslabs.aws-c-auth\" remote=\"base\" path=\"layers/meta-iot-cloud-dl/git/github.com.awslabs.aws-c-auth.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.awslabs.aws-c-cal\" remote=\"base\" path=\"layers/meta-iot-cloud-dl/git/github.com.awslabs.aws-c-cal.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.awslabs.aws-c-common\" remote=\"base\" path=\"layers/meta-iot-cloud-dl/git/github.com.awslabs.aws-c-common.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.awslabs.aws-c-compression\" remote=\"base\" path=\"layers/meta-iot-cloud-dl/git/github.com.awslabs.aws-c-compression.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.awslabs.aws-c-event-stream\" remote=\"base\" path=\"layers/meta-iot-cloud-dl/git/github.com.awslabs.aws-c-event-stream.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.awslabs.aws-c-http\" remote=\"base\" path=\"layers/meta-iot-cloud-dl/git/github.com.awslabs.aws-c-http.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.awslabs.aws-c-io\" remote=\"base\" path=\"layers/meta-iot-cloud-dl/git/github.com.awslabs.aws-c-io.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.awslabs.aws-c-mqtt\" remote=\"base\" path=\"layers/meta-iot-cloud-dl/git/github.com.awslabs.aws-c-mqtt.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.awslabs.aws-checksums\" remote=\"base\" path=\"layers/meta-iot-cloud-dl/git/github.com.awslabs.aws-checksums.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.awslabs.aws-crt-cpp\" remote=\"base\" path=\"layers/meta-iot-cloud-dl/git/github.com.awslabs.aws-crt-cpp.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.aws.aws-iot-device-sdk-cpp-v2\" remote=\"base\" path=\"layers/meta-iot-cloud-dl/git/github.com.aws.aws-iot-device-sdk-cpp-v2.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.awslabs.s2n\" remote=\"base\" path=\"layers/meta-iot-cloud-dl/git/github.com.awslabs.s2n.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.Azure.azure-c-shared-utility\" remote=\"base\" path=\"layers/meta-iot-cloud-dl/git/github.com.Azure.azure-c-shared-utility.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.Azure.azure-iot-sdk-c\" remote=\"base\" path=\"layers/meta-iot-cloud-dl/git/github.com.Azure.azure-iot-sdk-c.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.Azure.azure-macro-utils-c\" remote=\"base\" path=\"layers/meta-iot-cloud-dl/git/github.com.Azure.azure-macro-utils-c.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.Azure.azure-uamqp-c\" remote=\"base\" path=\"layers/meta-iot-cloud-dl/git/github.com.Azure.azure-uamqp-c.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.Azure.azure-uhttp-c\" remote=\"base\" path=\"layers/meta-iot-cloud-dl/git/github.com.Azure.azure-uhttp-c.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.Azure.azure-umqtt-c\" remote=\"base\" path=\"layers/meta-iot-cloud-dl/git/github.com.Azure.azure-umqtt-c.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.kgabis.parson\" remote=\"base\" path=\"layers/meta-iot-cloud-dl/git/github.com.kgabis.parson.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.Azure.umock-c\" remote=\"base\" path=\"layers/meta-iot-cloud-dl/git/github.com.Azure.umock-c.git\" bare=\"True\"/>\n"
  },
  {
    "path": "data/xml/meta-openembedded-dl-3-3.xml",
    "content": "    <project name=\"external/yocto/git.code.sf.net.p.aufs.aufs-util\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/git.code.sf.net.p.aufs.aufs-util\" bare=\"True\"/>\n    <project name=\"external/yocto/www.aleph1.co.uk.yaffs2\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/www.aleph1.co.uk.yaffs2\" bare=\"True\"/>\n    <project name=\"external/yocto/git.kernel.org.pub.scm.linux.kernel.git.jaegeuk.f2fs-tools\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/git.kernel.org.pub.scm.linux.kernel.git.jaegeuk.f2fs-tools.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.engla.keybinder\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.engla.keybinder.git\" bare=\"True\"/>\n    <project name=\"external/yocto/git.kernel.org.pub.scm.boot.dracut.dracut\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/git.kernel.org.pub.scm.boot.dracut.dracut.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.rhboot.grubby\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.rhboot.grubby.git\" bare=\"True\"/>\n    <project name=\"external/yocto/pagure.io.netcf\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/pagure.io.netcf.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.open-iscsi.open-iscsi\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.open-iscsi.open-iscsi\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.open-iscsi.open-isns\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.open-iscsi.open-isns\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.dugsong.libdnet\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.dugsong.libdnet.git\" bare=\"True\"/>\n    <project name=\"external/yocto/git.kernel.org.pub.scm.linux.kernel.git.shemminger.bridge-utils\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/git.kernel.org.pub.scm.linux.kernel.git.shemminger.bridge-utils.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.sctp.lksctp-tools\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.sctp.lksctp-tools.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.maxmind.geoip-api-perl\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.maxmind.geoip-api-perl.git\" bare=\"True\"/>\n    <project name=\"external/ovp/anongit.freedesktop.org.spice.spice-protocol\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/anongit.freedesktop.org.spice.spice-protocol\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.LINBIT.drbd-utils\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.LINBIT.drbd-utils\" bare=\"True\"/>\n    <project name=\"external/yocto/anongit.freedesktop.org.spice.spice\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/anongit.freedesktop.org.spice.spice\" bare=\"True\"/>\n    <project name=\"external/yocto/anongit.freedesktop.org.spice.spice-common\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/anongit.freedesktop.org.spice.spice-common\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.LINBIT.drbd-headers\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.LINBIT.drbd-headers\" bare=\"True\"/>\n    <project name=\"external/yocto/salsa.debian.org.debian.ifenslave\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/salsa.debian.org.debian.ifenslave.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.cyrusimap.cyrus-sasl\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.cyrusimap.cyrus-sasl\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.maxmind.geoip-api-c\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.maxmind.geoip-api-c.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.FreeRADIUS.freeradius-server\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.FreeRADIUS.freeradius-server.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.kronosnet.kronosnet\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.kronosnet.kronosnet\" bare=\"True\"/>\n    <project name=\"external/yocto/git.netfilter.org.libnetfilter_queue\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/git.netfilter.org.libnetfilter_queue\" bare=\"True\"/>\n    <project name=\"external/yocto/git.netfilter.org.libnftnl\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/git.netfilter.org.libnftnl\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.OpenAoE.vblade\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.OpenAoE.vblade\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.ntop.nDPI\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.ntop.nDPI.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.ntop.ntopng\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.ntop.ntopng.git\" bare=\"True\"/>\n    <project name=\"external/agent-proxy\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/git.kernel.org.pub.scm.utils.kernel.kgdb.agent-proxy.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.ago.pps-tools\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.ago.pps-tools.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.anyc.pmtools\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.anyc.pmtools.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.esnet.iperf\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.esnet.iperf.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.grondo.edac-utils\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.grondo.edac-utils\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.jthornber.thin-provisioning-tools\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.jthornber.thin-provisioning-tools\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.libgd.libgd\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.libgd.libgd.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.libhugetlbfs.libhugetlbfs\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.libhugetlbfs.libhugetlbfs.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.lloyd.yajl\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.lloyd.yajl\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.oetiker.rrdtool-1.x\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.oetiker.rrdtool-1.x.git\" bare=\"True\"/>\n    <project name=\"external/yocto/git.kernel.org.pub.scm.utils.cpu.mce.mcelog\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/git.kernel.org.pub.scm.utils.cpu.mce.mcelog.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.rsyslog.libfastjson\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.rsyslog.libfastjson.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.rsyslog.librelp\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.rsyslog.librelp.git\" bare=\"True\"/>\n    <project name=\"external/yocto/git.0pointer.de.libatasmart\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/git.0pointer.de.libatasmart.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.google.leveldb\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.google.leveldb.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.protobuf-c.protobuf-c\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.protobuf-c.protobuf-c.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.jpirko.libndp\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.jpirko.libndp\" bare=\"True\"/>\n    <project name=\"external/yocto/git.kernel.org.pub.scm.utils.cpu.mce.mce-inject\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/git.kernel.org.pub.scm.utils.cpu.mce.mce-inject.git\" bare=\"True\"/>\n    <project name=\"external/yocto/git.kernel.org.pub.scm.utils.cpu.mce.mce-test\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/git.kernel.org.pub.scm.utils.cpu.mce.mce-test.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.vcrhonek.hwdata\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.vcrhonek.hwdata.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.ClusterLabs.libqb\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.ClusterLabs.libqb.git\" bare=\"True\"/>\n    <project name=\"external/yocto/git.kernel.dk.fio\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/git.kernel.dk.fio.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.TigerVNC.tigervnc\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.TigerVNC.tigervnc.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.abrt.satyr\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.abrt.satyr.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.abrt.libreport\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.abrt.libreport.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.rhinstaller.libbytesize\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.rhinstaller.libbytesize\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.rhinstaller.isomd5sum\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.rhinstaller.isomd5sum.git\" bare=\"True\"/>\n    <project name=\"external/yocto/git.code.sf.net.p.tclap.code\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/git.code.sf.net.p.tclap.code\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.gperftools.gperftools\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.gperftools.gperftools.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.storaged-project.udisks\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.storaged-project.udisks.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.jpirko.libteam\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.jpirko.libteam\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.facebook.rocksdb\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.facebook.rocksdb.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.pmem.ndctl\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.pmem.ndctl.git\" bare=\"True\"/>\n    <project name=\"external/yocto/git.sv.gnu.org.gnulib\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/git.sv.gnu.org.gnulib.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.jirka-h.haveged\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.jirka-h.haveged.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.mirror.xmlrpc-c\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.mirror.xmlrpc-c.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.alanxz.rabbitmq-c\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.alanxz.rabbitmq-c.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.perl5-dbi.DBD-mysql\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.perl5-dbi.DBD-mysql.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.crash-utility.crash\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.crash-utility.crash.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.gflags.gflags\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.gflags.gflags.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.troydhanson.uthash\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.troydhanson.uthash.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.lm-sensors.lm-sensors\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.lm-sensors.lm-sensors.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.intel.pm-graph\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.intel.pm-graph.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.pmem.pmdk\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.pmem.pmdk.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.uclouvain.openjpeg\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.uclouvain.openjpeg.git\" bare=\"True\"/>\n    <project name=\"external/yocto/sourceware.org.git.lvm2\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/sourceware.org.git.lvm2.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.vmware.open-vm-tools\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.vmware.open-vm-tools.git\" bare=\"True\"/>\n    <project name=\"external/yocto/repo.or.cz.iotop\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/repo.or.cz.iotop.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.c-ares.c-ares\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.c-ares.c-ares.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.opencv.ade\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.opencv.ade.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.google.glog\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.google.glog.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.oneapi-src.oneTBB\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.oneapi-src.oneTBB.git\" bare=\"True\"/>\n    <project name=\"external/yocto/luajit.org.git.luajit-2.0\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/luajit.org.git.luajit-2.0.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.libusb.libusb-compat-0.1\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.libusb.libusb-compat-0.1.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.storaged-project.libblockdev\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.storaged-project.libblockdev\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.protocolbuffers.protobuf\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.protocolbuffers.protobuf.git\" bare=\"True\"/>\n    <project name=\"external/yocto/anongit.freedesktop.org.xorg.driver.xf86-video-armsoc\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/anongit.freedesktop.org.xorg.driver.xf86-video-armsoc\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.apache.nifi-minifi-cpp\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.apache.nifi-minifi-cpp.git\" bare=\"True\"/>\n    <project name=\"external/yocto/gitlab.com.libeigen.eigen\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/gitlab.com.libeigen.eigen.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.htop-dev.htop\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.htop-dev.htop.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.makedumpfile.makedumpfile\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.makedumpfile.makedumpfile\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.google.flatbuffers\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.google.flatbuffers.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.rhinstaller.python-meh\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.rhinstaller.python-meh.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.seveas.python-prctl\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.seveas.python-prctl\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.berkerpeksag.astor\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.berkerpeksag.astor.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.keras-team.keras-applications\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.keras-team.keras-applications.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.python-pillow.Pillow\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.python-pillow.Pillow.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.cf-natali.ntplib\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.cf-natali.ntplib.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.rhinstaller.pykickstart\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.rhinstaller.pykickstart.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.rhinstaller.blivet\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.rhinstaller.blivet\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.rhinstaller.blivet-gui\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.rhinstaller.blivet-gui\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.schnitzeltony.xfce4-closebutton-plugin\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.schnitzeltony.xfce4-closebutton-plugin.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.ncopa.xfce-polkit\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.ncopa.xfce-polkit.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.schnitzeltony.xfce4-datetime-setter\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.schnitzeltony.xfce4-datetime-setter.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.westerndigitalcorporation.ufs-utils\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.westerndigitalcorporation.ufs-utils.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.OSSystems.inih\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.OSSystems.inih.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.libbpf.libbpf\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.libbpf.libbpf.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.catchorg.Catch2\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.catchorg.Catch2.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.OpenSC.libp11\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.OpenSC.libp11.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.abseil.abseil-cpp\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.abseil.abseil-cpp.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.google.re2\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.google.re2.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.google.googletest\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.google.googletest.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.grpc.grpc\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.grpc.grpc.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.opencv.opencv\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.opencv.opencv.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.opencv.opencv_contrib\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.opencv.opencv_contrib.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.opencv.opencv_3rdparty\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.opencv.opencv_3rdparty.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.rvoicilas.inotify-tools\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.rvoicilas.inotify-tools\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.WeChatCV.opencv_3rdparty\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.WeChatCV.opencv_3rdparty.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.DaveGamble.cJSON\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.DaveGamble.cJSON.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.CESNET.libyang\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.CESNET.libyang.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.LMDB.lmdb\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.LMDB.lmdb.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.jemalloc.jemalloc\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.jemalloc.jemalloc.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.CanonicalLtd.netplan\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.CanonicalLtd.netplan.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.opensvc.multipath-tools\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.opensvc.multipath-tools.git\" bare=\"True\"/>\n"
  },
  {
    "path": "data/xml/meta-qt5-dl.xml",
    "content": "    <project name=\"external/qt5/code.qt.io.qt-labs.qt5-everywhere-demo\" remote=\"base\" path=\"layers/meta-qt5-dl/git/code.qt.io.qt-labs.qt5-everywhere-demo.git\" bare=\"True\"/>\n    <project name=\"external/qt5/code.qt.io.qt.qt3d\" remote=\"base\" path=\"layers/meta-qt5-dl/git/code.qt.io.qt.qt3d.git\" bare=\"True\"/>\n    <project name=\"external/qt5/code.qt.io.qt.qtbase\" remote=\"base\" path=\"layers/meta-qt5-dl/git/code.qt.io.qt.qtbase.git\" bare=\"True\"/>\n    <project name=\"external/qt5/code.qt.io.qt.qtcharts\" remote=\"base\" path=\"layers/meta-qt5-dl/git/code.qt.io.qt.qtcharts.git\" bare=\"True\"/>\n    <project name=\"external/qt5/code.qt.io.qt.qtconnectivity\" remote=\"base\" path=\"layers/meta-qt5-dl/git/code.qt.io.qt.qtconnectivity.git\" bare=\"True\"/>\n    <project name=\"external/qt5/code.qt.io.qt.qtdeclarative\" remote=\"base\" path=\"layers/meta-qt5-dl/git/code.qt.io.qt.qtdeclarative.git\" bare=\"True\"/>\n    <project name=\"external/qt5/code.qt.io.qt.qtgraphicaleffects\" remote=\"base\" path=\"layers/meta-qt5-dl/git/code.qt.io.qt.qtgraphicaleffects.git\" bare=\"True\"/>\n    <project name=\"external/qt5/code.qt.io.qt.qtimageformats\" remote=\"base\" path=\"layers/meta-qt5-dl/git/code.qt.io.qt.qtimageformats.git\" bare=\"True\"/>\n    <project name=\"external/qt5/code.qt.io.qt.qtlocation\" remote=\"base\" path=\"layers/meta-qt5-dl/git/code.qt.io.qt.qtlocation.git\" bare=\"True\"/>\n    <project name=\"external/qt5/code.qt.io.qt.qtlocation-mapboxgl\" remote=\"base\" path=\"layers/meta-qt5-dl/git/code.qt.io.qt.qtlocation-mapboxgl.git\" bare=\"True\"/>\n    <project name=\"external/qt5/code.qt.io.qt.qtmqtt\" remote=\"base\" path=\"layers/meta-qt5-dl/git/code.qt.io.qt.qtmqtt.git\" bare=\"True\"/>\n    <project name=\"external/qt5/code.qt.io.qt.qtmultimedia\" remote=\"base\" path=\"layers/meta-qt5-dl/git/code.qt.io.qt.qtmultimedia.git\" bare=\"True\"/>\n    <project name=\"external/qt5/code.qt.io.qt.qtquickcontrols2\" remote=\"base\" path=\"layers/meta-qt5-dl/git/code.qt.io.qt.qtquickcontrols2.git\" bare=\"True\"/>\n    <project name=\"external/qt5/code.qt.io.qt.qtquickcontrols\" remote=\"base\" path=\"layers/meta-qt5-dl/git/code.qt.io.qt.qtquickcontrols.git\" bare=\"True\"/>\n    <project name=\"external/qt5/code.qt.io.qt.qtscript\" remote=\"base\" path=\"layers/meta-qt5-dl/git/code.qt.io.qt.qtscript.git\" bare=\"True\"/>\n    <project name=\"external/qt5/code.qt.io.qt.qtsensors\" remote=\"base\" path=\"layers/meta-qt5-dl/git/code.qt.io.qt.qtsensors.git\" bare=\"True\"/>\n    <project name=\"external/qt5/code.qt.io.qt.qtserialbus\" remote=\"base\" path=\"layers/meta-qt5-dl/git/code.qt.io.qt.qtserialbus.git\" bare=\"True\"/>\n    <project name=\"external/qt5/code.qt.io.qt.qtserialport\" remote=\"base\" path=\"layers/meta-qt5-dl/git/code.qt.io.qt.qtserialport.git\" bare=\"True\"/>\n    <project name=\"external/qt5/code.qt.io.qt.qtsvg\" remote=\"base\" path=\"layers/meta-qt5-dl/git/code.qt.io.qt.qtsvg.git\" bare=\"True\"/>\n    <project name=\"external/qt5/code.qt.io.qt.qtsystems\" remote=\"base\" path=\"layers/meta-qt5-dl/git/code.qt.io.qt.qtsystems.git\" bare=\"True\"/>\n    <project name=\"external/qt5/code.qt.io.qt.qttools\" remote=\"base\" path=\"layers/meta-qt5-dl/git/code.qt.io.qt.qttools.git\" bare=\"True\"/>\n    <project name=\"external/qt5/code.qt.io.qt.qttranslations\" remote=\"base\" path=\"layers/meta-qt5-dl/git/code.qt.io.qt.qttranslations.git\" bare=\"True\"/>\n    <project name=\"external/qt5/code.qt.io.qt.qtwebchannel\" remote=\"base\" path=\"layers/meta-qt5-dl/git/code.qt.io.qt.qtwebchannel.git\" bare=\"True\"/>\n    <project name=\"external/qt5/code.qt.io.qt.qtwebsockets\" remote=\"base\" path=\"layers/meta-qt5-dl/git/code.qt.io.qt.qtwebsockets.git\" bare=\"True\"/>\n    <project name=\"external/qt5/code.qt.io.qt.qtx11extras\" remote=\"base\" path=\"layers/meta-qt5-dl/git/code.qt.io.qt.qtx11extras.git\" bare=\"True\"/>\n    <project name=\"external/qt5/code.qt.io.qt.qtxmlpatterns\" remote=\"base\" path=\"layers/meta-qt5-dl/git/code.qt.io.qt.qtxmlpatterns.git\" bare=\"True\"/>\n    <project name=\"external/qt5/code.qt.io.qt.qtwayland\" remote=\"base\" path=\"layers/meta-qt5-dl/git/code.qt.io.qt.qtwayland.git\" bare=\"True\"/>\n    <project name=\"external/qt5/code.qt.io.qt-creator.qt-creator\" remote=\"base\" path=\"layers/meta-qt5-dl/git/code.qt.io.qt-creator.qt-creator.git\" bare=\"True\"/>\n"
  },
  {
    "path": "data/xml/meta-raspberrypi-dl.xml",
    "content": "    <project name=\"external/yocto/github.com.RPi-Distro.pi-bluetooth\" remote=\"base\" path=\"layers/meta-raspberrypi-dl/git/github.com.RPi-Distro.pi-bluetooth\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.Evilpaul.RPi-config\" remote=\"base\" path=\"layers/meta-raspberrypi-dl/git/github.com.Evilpaul.RPi-config.git\" bare=\"True\"/>\n"
  },
  {
    "path": "data/xml/meta-realtime-dl-3-3.xml",
    "content": "    <project name=\"external/yocto/github.com.jlelli.schedtool-dl\" remote=\"base\" path=\"layers/meta-realtime-dl-3.3/git/github.com.jlelli.schedtool-dl.git\" bare=\"True\"/>\n"
  },
  {
    "path": "data/xml/meta-security-compliance-dl.xml",
    "content": "    <project name=\"external/yocto/github.com.OpenSCAP.openscap\" remote=\"base\" path=\"layers/meta-security-compliance-dl/git/github.com.OpenSCAP.openscap.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.OpenSCAP.scap-security-guide\" remote=\"base\" path=\"layers/meta-security-compliance-dl/git/github.com.OpenSCAP.scap-security-guide.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.ComplianceAsCode.content\" remote=\"base\" path=\"layers/meta-security-compliance-dl/git/github.com.ComplianceAsCode.content.git\" bare=\"True\"/>\n"
  },
  {
    "path": "data/xml/meta-selinux-dl.xml",
    "content": "    <project name=\"external/yocto/github.com.SELinuxProject.refpolicy\" remote=\"base\" path=\"layers/meta-selinux-dl/git/github.com.SELinuxProject.refpolicy.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.SELinuxProject.setools\" remote=\"base\" path=\"layers/meta-selinux-dl/git/github.com.SELinuxProject.setools.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.linux-audit.audit-userspace\" remote=\"base\" path=\"layers/meta-selinux-dl/git/github.com.linux-audit.audit-userspace.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.SELinuxProject.selinux\" remote=\"base\" path=\"layers/meta-selinux-dl/git/github.com.SELinuxProject.selinux.git\" bare=\"True\"/>\n"
  },
  {
    "path": "data/xml/meta-signing-key-dl.xml",
    "content": "    <project name=\"external/yocto/github.com.jiazhang0.libsign\" remote=\"base\" path=\"layers/meta-signing-key-dl/git/github.com.jiazhang0.libsign.git\" bare=\"True\"/>\n    <project name=\"external/yocto/git.kernel.org.pub.scm.linux.kernel.git.jejb.sbsigntools\" remote=\"base\" path=\"layers/meta-signing-key-dl/git/git.kernel.org.pub.scm.linux.kernel.git.jejb.sbsigntools.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.rustyrussell.ccan\" remote=\"base\" path=\"layers/meta-signing-key-dl/git/github.com.rustyrussell.ccan.git\" bare=\"True\"/>\n"
  },
  {
    "path": "data/xml/meta-tensorflow-dl-3-3.xml",
    "content": "    <project name=\"external/yocto/github.com.tensorflow.tensorflow\" remote=\"base\" path=\"layers/meta-tensorflow-dl-3.3/git/github.com.tensorflow.tensorflow.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.tensorflow.estimator\" remote=\"base\" path=\"layers/meta-tensorflow-dl-3.3/git/github.com.tensorflow.estimator.git\" bare=\"True\"/>\n"
  },
  {
    "path": "data/xml/meta-tpm-dl.xml",
    "content": "    <project name=\"external/yocto/git.code.sf.net.p.trousers.tpm-tools\" remote=\"base\" path=\"layers/meta-tpm-dl/git/git.code.sf.net.p.trousers.tpm-tools\" bare=\"True\"/>\n    <project name=\"external/yocto/git.code.sf.net.p.trousers.trousers\" remote=\"base\" path=\"layers/meta-tpm-dl/git/git.code.sf.net.p.trousers.trousers\" bare=\"True\"/>\n    <project name=\"external/yocto/git.code.sf.net.p.tpmquotetools.tpm-quote-tools\" remote=\"base\" path=\"layers/meta-tpm-dl/git/git.code.sf.net.p.tpmquotetools.tpm-quote-tools\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.mgerstner.openssl_tpm_engine\" remote=\"base\" path=\"layers/meta-tpm-dl/git/github.com.mgerstner.openssl_tpm_engine.git\" bare=\"True\"/>\n"
  },
  {
    "path": "data/xml/meta-tpm2-dl.xml",
    "content": "    <project name=\"external/yocto/github.com.tpm2-software.tpm2-abrmd\" remote=\"base\" path=\"layers/meta-tpm2-dl/git/github.com.tpm2-software.tpm2-abrmd.git\" bare=\"True\"/>\n"
  },
  {
    "path": "data/xml/meta-virtualization-dl-3-3.xml",
    "content": "    <project name=\"external/yocto/github.com.coreos.go-systemd\" remote=\"base\" path=\"layers/meta-virtualization-dl-3.3/git/github.com.coreos.go-systemd.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.syndtr.gocapability\" remote=\"base\" path=\"layers/meta-virtualization-dl-3.3/git/github.com.syndtr.gocapability.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.grpc.grpc-go\" remote=\"base\" path=\"layers/meta-virtualization-dl-3.3/git/github.com.grpc.grpc-go.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.Sirupsen.logrus\" remote=\"base\" path=\"layers/meta-virtualization-dl-3.3/git/github.com.Sirupsen.logrus.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.gorilla.mux\" remote=\"base\" path=\"layers/meta-virtualization-dl-3.3/git/github.com.gorilla.mux.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.docker.distribution\" remote=\"base\" path=\"layers/meta-virtualization-dl-3.3/git/github.com.docker.distribution.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.tchap.go-patricia\" remote=\"base\" path=\"layers/meta-virtualization-dl-3.3/git/github.com.tchap.go-patricia.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.godbus.dbus\" remote=\"base\" path=\"layers/meta-virtualization-dl-3.3/git/github.com.godbus.dbus.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.gorilla.context\" remote=\"base\" path=\"layers/meta-virtualization-dl-3.3/git/github.com.gorilla.context.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.codegangsta.cli\" remote=\"base\" path=\"layers/meta-virtualization-dl-3.3/git/github.com.codegangsta.cli.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.docker.go-connections\" remote=\"base\" path=\"layers/meta-virtualization-dl-3.3/git/github.com.docker.go-connections.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.docker.notary\" remote=\"base\" path=\"layers/meta-virtualization-dl-3.3/git/github.com.docker.notary.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.aanand.compose-file\" remote=\"base\" path=\"layers/meta-virtualization-dl-3.3/git/github.com.aanand.compose-file.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.fsnotify.fsnotify\" remote=\"base\" path=\"layers/meta-virtualization-dl-3.3/git/github.com.fsnotify.fsnotify.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.krallin.tini\" remote=\"base\" path=\"layers/meta-virtualization-dl-3.3/git/github.com.krallin.tini.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.containerd.containerd\" remote=\"base\" path=\"layers/meta-virtualization-dl-3.3/git/github.com.containerd.containerd\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.docker.libnetwork\" remote=\"base\" path=\"layers/meta-virtualization-dl-3.3/git/github.com.docker.libnetwork.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.opencontainers.runc\" remote=\"base\" path=\"layers/meta-virtualization-dl-3.3/git/github.com.opencontainers.runc\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.chaos.diod\" remote=\"base\" path=\"layers/meta-virtualization-dl-3.3/git/github.com.chaos.diod.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.Irqbalance.irqbalance\" remote=\"base\" path=\"layers/meta-virtualization-dl-3.3/git/github.com.Irqbalance.irqbalance\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.kubernetes.kubernetes\" remote=\"base\" path=\"layers/meta-virtualization-dl-3.3/git/github.com.kubernetes.kubernetes.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.containernetworking.cni\" remote=\"base\" path=\"layers/meta-virtualization-dl-3.3/git/github.com.containernetworking.cni.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.containernetworking.plugins\" remote=\"base\" path=\"layers/meta-virtualization-dl-3.3/git/github.com.containernetworking.plugins.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.libvmi.libvmi\" remote=\"base\" path=\"layers/meta-virtualization-dl-3.3/git/github.com.libvmi.libvmi.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.docker.docker-ce\" remote=\"base\" path=\"layers/meta-virtualization-dl-3.3/git/github.com.docker.docker-ce.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.checkpoint-restore.criu\" remote=\"base\" path=\"layers/meta-virtualization-dl-3.3/git/github.com.checkpoint-restore.criu.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.creack.pty\" remote=\"base\" path=\"layers/meta-virtualization-dl-3.3/git/github.com.creack.pty.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.kubernetes.release\" remote=\"base\" path=\"layers/meta-virtualization-dl-3.3/git/github.com.kubernetes.release\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.jirutka.sloci-image\" remote=\"base\" path=\"layers/meta-virtualization-dl-3.3/git/github.com.jirutka.sloci-image.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.openvswitch.ovs\" remote=\"base\" path=\"layers/meta-virtualization-dl-3.3/git/github.com.openvswitch.ovs.git\" bare=\"True\"/>\n"
  },
  {
    "path": "data/xml/nxp-imx7.xml",
    "content": ""
  },
  {
    "path": "data/xml/nxp-s32g2xx-dl.xml",
    "content": "    <project name=\"external/yocto/source.codeaurora.org.external.autobsps32.u-boot\" remote=\"base\" path=\"layers/nxp-s32g2xx-dl/git/source.codeaurora.org.external.autobsps32.u-boot\" bare=\"True\"/>\n    <project name=\"external/yocto/source.codeaurora.org.external.autobsps32.extra.pfeng\" remote=\"base\" path=\"layers/nxp-s32g2xx-dl/git/source.codeaurora.org.external.autobsps32.extra.pfeng\" bare=\"True\"/>\n    <project name=\"external/yocto/source.codeaurora.org.external.autobsps32.arm-trusted-firmware\" remote=\"base\" path=\"layers/nxp-s32g2xx-dl/git/source.codeaurora.org.external.autobsps32.arm-trusted-firmware\" bare=\"True\"/>\n    <project name=\"external/yocto/source.codeaurora.org.external.autobsps32.ipcf.ipc-shm\" remote=\"base\" path=\"layers/nxp-s32g2xx-dl/git/source.codeaurora.org.external.autobsps32.ipcf.ipc-shm\" bare=\"True\"/>\n    <project name=\"external/yocto/git.trustedfirmware.org.TF-A.trusted-firmware-a\" remote=\"base\" path=\"layers/nxp-s32g2xx-dl/git/git.trustedfirmware.org.TF-A.trusted-firmware-a.git\" bare=\"True\"/>\n"
  },
  {
    "path": "data/xml/oe-core-dl-3-3.xml",
    "content": "    <project name=\"external/yocto/git.denx.de.u-boot\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/git.denx.de.u-boot.git\" bare=\"True\"/>\n    <project name=\"external/yocto/git.infradead.org.mtd-utils\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/git.infradead.org.mtd-utils.git\" bare=\"True\"/>\n    <project name=\"external/yocto/git.kernel.dk.blktrace\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/git.kernel.dk.blktrace.git\" bare=\"True\"/>\n    <project name=\"external/yocto/git.kernel.org.pub.scm.fs.ext2.e2fsprogs\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/git.kernel.org.pub.scm.fs.ext2.e2fsprogs.git\" bare=\"True\"/>\n    <project name=\"external/yocto/git.kernel.org.pub.scm.linux.kernel.git.cjb.mmc-utils\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/git.kernel.org.pub.scm.linux.kernel.git.cjb.mmc-utils.git\" bare=\"True\"/>\n    <project name=\"external/yocto/git.kernel.org.pub.scm.linux.kernel.git.kdave.btrfs-progs\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/git.kernel.org.pub.scm.linux.kernel.git.kdave.btrfs-progs.git\" bare=\"True\"/>\n    <project name=\"external/yocto/git.kernel.org.pub.scm.utils.dtc.dtc\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/git.kernel.org.pub.scm.utils.dtc.dtc.git\" bare=\"True\"/>\n    <project name=\"external/yocto/git.kernel.org.pub.scm.utils.kernel.kmod.kmod\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/git.kernel.org.pub.scm.utils.kernel.kmod.kmod.git\" bare=\"True\"/>\n    <project name=\"external/yocto/git.kernel.org.pub.scm.utils.rt-tests.rt-tests\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/git.kernel.org.pub.scm.utils.rt-tests.rt-tests.git\" bare=\"True\"/>\n    <project name=\"external/yocto/git.tartarus.org.simon.puzzles\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/git.tartarus.org.simon.puzzles.git\" bare=\"True\"/>\n    <project name=\"external/yocto/git.yoctoproject.org.dbus-wait\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/git.yoctoproject.org.dbus-wait\" bare=\"True\"/>\n    <project name=\"external/yocto/git.yoctoproject.org.libfakekey\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/git.yoctoproject.org.libfakekey\" bare=\"True\"/>\n    <project name=\"external/yocto/git.yoctoproject.org.libmatchbox\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/git.yoctoproject.org.libmatchbox\" bare=\"True\"/>\n    <project name=\"external/yocto/git.yoctoproject.org.matchbox-config-gtk\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/git.yoctoproject.org.matchbox-config-gtk\" bare=\"True\"/>\n    <project name=\"external/yocto/git.yoctoproject.org.matchbox-desktop-2\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/git.yoctoproject.org.matchbox-desktop-2\" bare=\"True\"/>\n    <project name=\"external/yocto/git.yoctoproject.org.matchbox-keyboard\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/git.yoctoproject.org.matchbox-keyboard\" bare=\"True\"/>\n    <project name=\"external/yocto/git.yoctoproject.org.matchbox-panel-2\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/git.yoctoproject.org.matchbox-panel-2\" bare=\"True\"/>\n    <project name=\"external/yocto/git.yoctoproject.org.matchbox-sato\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/git.yoctoproject.org.matchbox-sato\" bare=\"True\"/>\n    <project name=\"external/yocto/git.yoctoproject.org.matchbox-terminal\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/git.yoctoproject.org.matchbox-terminal\" bare=\"True\"/>\n    <project name=\"external/yocto/git.yoctoproject.org.matchbox-window-manager\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/git.yoctoproject.org.matchbox-window-manager\" bare=\"True\"/>\n    <project name=\"external/yocto/git.yoctoproject.org.prelink-cross\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/git.yoctoproject.org.prelink-cross.git\" bare=\"True\"/>\n    <project name=\"external/yocto/git.yoctoproject.org.psplash\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/git.yoctoproject.org.psplash\" bare=\"True\"/>\n    <project name=\"external/yocto/git.yoctoproject.org.ptest-runner2\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/git.yoctoproject.org.ptest-runner2\" bare=\"True\"/>\n    <project name=\"external/yocto/git.yoctoproject.org.screenshot\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/git.yoctoproject.org.screenshot\" bare=\"True\"/>\n    <project name=\"external/yocto/git.yoctoproject.org.xcursor-transparent-theme\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/git.yoctoproject.org.xcursor-transparent-theme\" bare=\"True\"/>\n    <project name=\"external/yocto/git.yoctoproject.org.xsettings-daemon\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/git.yoctoproject.org.xsettings-daemon\" bare=\"True\"/>\n    <project name=\"external/yocto/git.yoctoproject.org.yocto-kernel-tools\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/git.yoctoproject.org.yocto-kernel-tools.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.clutter-project.mx\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.clutter-project.mx.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.connectivity.connman-gnome\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.connectivity.connman-gnome.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.file.file\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.file.file.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.kraj.localedef\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.kraj.localedef\" bare=\"True\"/>\n    <project name=\"external/github.com.linux-test-project.ltp\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.linux-test-project.ltp.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.openSUSE.libsolv\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.openSUSE.libsolv.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.plougher.squashfs-tools\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.plougher.squashfs-tools.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.stevenhoneyman.l3afpad\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.stevenhoneyman.l3afpad.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.systemd.systemd-bootchart\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.systemd.systemd-bootchart.git\" bare=\"True\"/>\n    <project name=\"external/yocto/sourceware.org.git.binutils-gdb\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/sourceware.org.git.binutils-gdb.git\" bare=\"True\"/>\n    <project name=\"external/yocto/sourceware.org.git.glibc\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/sourceware.org.git.glibc.git\" bare=\"True\"/>\n    <project name=\"external/yocto/sourceware.org.git.systemtap\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/sourceware.org.git.systemtap.git\" bare=\"True\"/>\n    <project name=\"external/yocto/anongit.freedesktop.org.xorg.driver.xf86-video-intel\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/anongit.freedesktop.org.xorg.driver.xf86-video-intel\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.rpm-software-management.libdnf\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.rpm-software-management.libdnf\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.rpm-software-management.dnf\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.rpm-software-management.dnf.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.rpm-software-management.rpm\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.rpm-software-management.rpm\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.tianocore.edk2\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.tianocore.edk2.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.rpm-software-management.librepo\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.rpm-software-management.librepo.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.rpm-software-management.libcomps\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.rpm-software-management.libcomps.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.rpm-software-management.createrepo_c\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.rpm-software-management.createrepo_c\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.lz4.lz4\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.lz4.lz4.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.thkukuk.libnsl\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.thkukuk.libnsl\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.golang.example\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.golang.example\" bare=\"True\"/>\n    <project name=\"external/yocto/gitlab.com.psmisc.psmisc\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/gitlab.com.psmisc.psmisc.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.Masterminds.glide\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.Masterminds.glide\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.iputils.iputils\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.iputils.iputils\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.ninja-build.ninja\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.ninja-build.ninja.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.p11-glue.p11-kit\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.p11-glue.p11-kit\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.cryptodev-linux.cryptodev-linux\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.cryptodev-linux.cryptodev-linux\" bare=\"True\"/>\n    <project name=\"external/yocto/git.yoctoproject.org.pseudo\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/git.yoctoproject.org.pseudo\" bare=\"True\"/>\n    <project name=\"external/yocto/salsa.debian.org.debian.ncurses\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/salsa.debian.org.debian.ncurses.git\" bare=\"True\"/>\n    <project name=\"external/yocto/salsa.debian.org.debian.ca-certificates\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/salsa.debian.org.debian.ca-certificates.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.besser82.libxcrypt\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.besser82.libxcrypt.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.xrmx.bootchart\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.xrmx.bootchart.git\" bare=\"True\"/>\n    <project name=\"external/yocto/pagure.io.libaio\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/pagure.io.libaio.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.thkukuk.libnss_nis\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.thkukuk.libnss_nis\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.thkukuk.rpcsvc-proto\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.thkukuk.rpcsvc-proto\" bare=\"True\"/>\n    <project name=\"external/yocto/salsa.debian.org.debian.ifupdown\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/salsa.debian.org.debian.ifupdown.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.distcc.distcc\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.distcc.distcc.git\" bare=\"True\"/>\n    <project name=\"external/yocto/salsa.debian.org.iso-codes-team.iso-codes\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/salsa.debian.org.iso-codes-team.iso-codes.git\" bare=\"True\"/>\n    <project name=\"external/yocto/git.yoctoproject.org.update-rc.d\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/git.yoctoproject.org.update-rc.d\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.g-truc.glm\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.g-truc.glm\" bare=\"True\"/>\n    <project name=\"external/yocto/git.code.sf.net.p.dos2unix.dos2unix\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/git.code.sf.net.p.dos2unix.dos2unix\" bare=\"True\"/>\n    <project name=\"external/yocto/gitlab.gnome.org.GNOME.mobile-broadband-provider-info\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/gitlab.gnome.org.GNOME.mobile-broadband-provider-info.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.fedora-modularity.libmodulemd\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.fedora-modularity.libmodulemd\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.nhorman.rng-tools\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.nhorman.rng-tools.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.smuellerDD.jitterentropy-library\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.smuellerDD.jitterentropy-library.git\" bare=\"True\"/>\n    <project name=\"external/yocto/gitlab.gnome.org.GNOME.gnome-desktop-testing\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/gitlab.gnome.org.GNOME.gnome-desktop-testing.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.KhronosGroup.Vulkan-Loader\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.KhronosGroup.Vulkan-Loader.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.intel.bmap-tools\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.intel.bmap-tools\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.vim.vim\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.vim.vim.git\" bare=\"True\"/>\n    <project name=\"external/yocto/gitlab.freedesktop.org.gstreamer.gst-examples\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/gitlab.freedesktop.org.gstreamer.gst-examples.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.systemd.systemd-stable\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.systemd.systemd-stable.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.troglobit.sysklogd\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.troglobit.sysklogd.git\" bare=\"True\"/>\n    <project name=\"external/yocto/gitlab.freedesktop.org.mesa.piglit\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/gitlab.freedesktop.org.mesa.piglit.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.riscv.opensbi\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.riscv.opensbi.git\" bare=\"True\"/>\n    <project name=\"external/yocto/git.lttng.org.lttng-modules\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/git.lttng.org.lttng-modules\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.unfs3.unfs3\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.unfs3.unfs3.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.KhronosGroup.Vulkan-Headers\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.KhronosGroup.Vulkan-Headers.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.KhronosGroup.Vulkan-Tools\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.KhronosGroup.Vulkan-Tools.git\" bare=\"True\"/>\n    <project name=\"external/yocto/gitlab.freedesktop.org.mesa.kmscube\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/gitlab.freedesktop.org.mesa.kmscube\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.openssl.openssl\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.openssl.openssl\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.ucb-bar.berkeley-softfloat-3\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.ucb-bar.berkeley-softfloat-3.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.krb5.krb5\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.krb5.krb5\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.pyca.cryptography\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.pyca.cryptography.git\" bare=\"True\"/>\n    <project name=\"external/yocto/boringssl.googlesource.com.boringssl\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/boringssl.googlesource.com.boringssl\" bare=\"True\"/>\n    <project name=\"external/yocto/git.cryptomilk.org.projects.cmocka\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/git.cryptomilk.org.projects.cmocka.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.kkos.oniguruma\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.kkos.oniguruma.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.hillbig.esaxx\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.hillbig.esaxx.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.y-256.libdivsufsort\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.y-256.libdivsufsort.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.linux-can.can-utils\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/github.com.linux-can.can-utils.git\" bare=\"True\"/>\n    <project name=\"external/yocto/git.pengutronix.de.git.tools.libsocketcan\" remote=\"base\" path=\"layers/meta-openembedded-dl-3.3/git/git.pengutronix.de.git.tools.libsocketcan.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.lathiat.nss-mdns\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.lathiat.nss-mdns\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.rhinstaller.efivar\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.rhinstaller.efivar.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.rhinstaller.efibootmgr\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.rhinstaller.efibootmgr.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.intel.libva-utils\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.intel.libva-utils.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.sbabic.libubootenv\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.sbabic.libubootenv\" bare=\"True\"/>\n    <project name=\"external/yocto/salsa.debian.org.debian.resolvconf\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/salsa.debian.org.debian.resolvconf.git\" bare=\"True\"/>\n    <project name=\"external/yocto/gitlab.freedesktop.org.xdg.shared-mime-info\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/gitlab.freedesktop.org.xdg.shared-mime-info.git\" bare=\"True\"/>\n    <project name=\"external/yocto/gitlab.com.procps-ng.procps\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/gitlab.com.procps-ng.procps.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.NixOS.patchelf\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.NixOS.patchelf\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.KhronosGroup.KTX-Software\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.KhronosGroup.KTX-Software\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.fenrus75.powertop\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.fenrus75.powertop\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.openSUSE.xinetd\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.openSUSE.xinetd.git\" bare=\"True\"/>\n    <project name=\"external/yocto/git.efficios.com.babeltrace\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/git.efficios.com.babeltrace.git\" bare=\"True\"/>\n    <project name=\"external/yocto/salsa.debian.org.debian.init-system-helpers\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/salsa.debian.org.debian.init-system-helpers.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.libuv.libuv\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.libuv.libuv\" bare=\"True\"/>\n    <project name=\"external/yocto/gitlab.freedesktop.org.drm.igt-gpu-tools\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/gitlab.freedesktop.org.drm.igt-gpu-tools.git\" bare=\"True\"/>\n    <project name=\"external/yocto/sourceware.org.git.bzip2-tests\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/sourceware.org.git.bzip2-tests.git\" bare=\"True\"/>\n    <project name=\"external/yocto/salsa.debian.org.dpkg-team.dpkg\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/salsa.debian.org.dpkg-team.dpkg.git\" bare=\"True\"/>\n    <project name=\"external/yocto/git.code.sf.net.p.net-tools.code\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/git.code.sf.net.p.net-tools.code\" bare=\"True\"/>\n    <project name=\"external/yocto/gitlab.gnome.org.GNOME.libhandy\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/gitlab.gnome.org.GNOME.libhandy.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.llvm.llvm-project\" remote=\"base\" path=\"layers/meta-clang-dl/git/github.com.llvm.llvm-project.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.mirror.x264\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.mirror.x264\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.kreijack.xinput_calibrator\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.kreijack.xinput_calibrator.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.boostorg.build\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.boostorg.build\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.KhronosGroup.SPIRV-Tools\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.KhronosGroup.SPIRV-Tools.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.KhronosGroup.SPIRV-Headers\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.KhronosGroup.SPIRV-Headers.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.google.shaderc\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.google.shaderc.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.KhronosGroup.glslang\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.KhronosGroup.glslang.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.flatpak.libportal\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.flatpak.libportal.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.KhronosGroup.Vulkan-Samples\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.KhronosGroup.Vulkan-Samples.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.GPUOpen-LibrariesAndSDKs.VulkanMemoryAllocator\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.GPUOpen-LibrariesAndSDKs.VulkanMemoryAllocator\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.vit-vit.CTPL\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.vit-vit.CTPL\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.nothings.stb\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.nothings.stb\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.docopt.docopt.cpp\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.docopt.docopt.cpp\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.ARM-software.HWCPipe\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.ARM-software.HWCPipe\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.KhronosGroup.SPIRV-Cross\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.KhronosGroup.SPIRV-Cross\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.ARM-software.astc-encoder\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.ARM-software.astc-encoder\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.KhronosGroup.Vulkan-Samples-Assets\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.KhronosGroup.Vulkan-Samples-Assets\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.zeux.volk\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.zeux.volk\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.glfw.glfw\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.glfw.glfw\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.ocornut.imgui\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.ocornut.imgui\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.syoyo.tinygltf\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.syoyo.tinygltf\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.gabime.spdlog\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.gabime.spdlog\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.numactl.numactl\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.numactl.numactl\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.google.brotli\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.google.brotli.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.libgit2.libgit2\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.libgit2.libgit2.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.akheron.jansson\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.akheron.jansson.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.facebook.zstd\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.facebook.zstd.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.Cyan4973.xxHash\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.Cyan4973.xxHash.git\" bare=\"True\"/>\n    <project name=\"external/yocto/gitlab.freedesktop.org.pkg-config.pkg-config\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/gitlab.freedesktop.org.pkg-config.pkg-config.git\" bare=\"True\"/>\n    <project name=\"external/yocto/salsa.debian.org.md.netbase\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/salsa.debian.org.md.netbase.git\" bare=\"True\"/>\n    <project name=\"external/yocto/git.eclipse.org.r.tcf.org.eclipse.tcf.agent\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/git.eclipse.org.r.tcf.org.eclipse.tcf.agent.git\" bare=\"True\"/>\n    <project name=\"external/yocto/gitlab.freedesktop.org.mesa.waffle\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/gitlab.freedesktop.org.mesa.waffle.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.asciidoc.asciidoc-py\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/github.com.asciidoc.asciidoc-py\" bare=\"True\"/>\n    <project name=\"external/yocto/git.savannah.gnu.org.git.config\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/git.savannah.gnu.org.git.config.git\" bare=\"True\"/>\n    <project name=\"external/yocto/anongit.freedesktop.org.git.virglrenderer\" remote=\"base\" path=\"layers/oe-core-dl-3.3/git/anongit.freedesktop.org.git.virglrenderer\" bare=\"True\"/>\n"
  },
  {
    "path": "data/xml/openembedded-core.inc",
    "content": "        <linkfile src=\"oe-init-build-env\" dest=\"oe-init-build-env\"/>\n        <linkfile src=\"meta\" dest=\"meta\"/>\n        <linkfile src=\"scripts\" dest=\"scripts\"/>\n"
  },
  {
    "path": "data/xml/ti-j72xx-dl.xml",
    "content": "    <project name=\"external/yocto/git.ti.com.rpmsg.ti-rpmsg-char\" remote=\"base\" path=\"layers/ti-j72xx-dl/git/git.ti.com.rpmsg.ti-rpmsg-char.git\" bare=\"True\"/>\n    <project name=\"external/yocto/git.ti.com.graphics.img-pvr-sdk\" remote=\"base\" path=\"layers/ti-j72xx-dl/git/git.ti.com.graphics.img-pvr-sdk.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.dentonw.devil\" remote=\"base\" path=\"layers/ti-j72xx-dl/git/github.com.dentonw.devil.git\" bare=\"True\"/>\n    <project name=\"external/yocto/git.ti.com.ti-u-boot.ti-u-boot\" remote=\"base\" path=\"layers/ti-j72xx-dl/git/git.ti.com.ti-u-boot.ti-u-boot.git\" bare=\"True\"/>\n    <project name=\"external/yocto/git.ti.com.jacinto7_multimedia.viddec-test-app\" remote=\"base\" path=\"layers/ti-j72xx-dl/git/git.ti.com.jacinto7_multimedia.viddec-test-app.git\" bare=\"True\"/>\n    <project name=\"external/yocto/git.ti.com.jacinto7_multimedia.videnc-test-app\" remote=\"base\" path=\"layers/ti-j72xx-dl/git/git.ti.com.jacinto7_multimedia.videnc-test-app.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.OP-TEE.optee_os\" remote=\"base\" path=\"layers/ti-j72xx-dl/git/github.com.OP-TEE.optee_os.git\" bare=\"True\"/>\n    <project name=\"external/yocto/git.ti.com.atf.arm-trusted-firmware\" remote=\"base\" path=\"layers/ti-j72xx-dl/git/git.ti.com.atf.arm-trusted-firmware.git\" bare=\"True\"/>\n    <project name=\"external/yocto/git.ti.com.processor-firmware.ti-linux-firmware\" remote=\"base\" path=\"layers/ti-j72xx-dl/git/git.ti.com.processor-firmware.ti-linux-firmware.git\" bare=\"True\"/>\n    <project name=\"external/yocto/git.ti.com.k3-image-gen.k3-image-gen\" remote=\"base\" path=\"layers/ti-j72xx-dl/git/git.ti.com.k3-image-gen.k3-image-gen.git\" bare=\"True\"/>\n"
  },
  {
    "path": "data/xml/wr-ostree-dl.xml",
    "content": "<project name=\"external/overc/github.com.ostreedev.ostree\" remote=\"base\" path=\"layers/wr-ostree-dl/git/github.com.ostreedev.ostree.git\" bare=\"True\"/>\n<project name=\"external/overc/gitlab.gnome.org.GNOME.libglnx\" remote=\"base\" path=\"layers/wr-ostree-dl/git/gitlab.gnome.org.GNOME.libglnx.git\" bare=\"True\"/>\n<project name=\"external/overc/github.com.mendsley.bsdiff\" remote=\"base\" path=\"layers/wr-ostree-dl/git/github.com.mendsley.bsdiff.git\" bare=\"True\"/>\n<project name=\"external/yocto/github.com.advancedtelematic.sota-tools\" remote=\"base\" path=\"layers/wr-ostree-dl/git/github.com.advancedtelematic.sota-tools.git\" bare=\"True\"/>\n"
  },
  {
    "path": "data/xml/wrlinux-dl.xml",
    "content": "    <project name=\"external/yocto/github.com.WindRiver-OpenSourceLabs.anspass\" remote=\"base\" path=\"layers/wrlinux-dl/git/github.com.WindRiver-OpenSourceLabs.anspass\" bare=\"True\"/>\n    <project name=\"external/poky\" remote=\"base\" path=\"layers/wrlinux-dl/git/git.yoctoproject.org.poky\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.openSUSE.build-compare\" remote=\"base\" path=\"layers/wrlinux-dl/git/github.com.openSUSE.build-compare.git\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.containers.skopeo\" remote=\"base\" path=\"layers/wrlinux-dl/git/github.com.containers.skopeo\" bare=\"True\"/>\n    <project name=\"external/yocto/github.com.opencontainers.umoci\" remote=\"base\" path=\"layers/wrlinux-dl/git/github.com.opencontainers.umoci\" bare=\"True\"/>\n    <project name=\"external/extra/github.com.xontab.chrome-virtual-keyboard\" remote=\"base\" path=\"layers/wrlinux-dl/git/github.com.xontab.chrome-virtual-keyboard.git\" bare=\"True\"/>\n"
  },
  {
    "path": "data/xml/wrlinux.xml",
    "content": "    <project name=\"yocto-kernel-cache-5.10\" remote=\"base\" path=\"layers/wrlinux/git/yocto-kernel-cache.git\" bare=\"True\"/>\n    <project name=\"linux-yocto-5.10\" remote=\"base\" path=\"layers/wrlinux/git/linux-yocto.git\" bare=\"True\"/>\n"
  },
  {
    "path": "data/xml/xilinx-zynqmp-dl.xml",
    "content": "    <project name=\"external/yocto/github.com.Xilinx.u-boot-xlnx\" remote=\"base\" path=\"layers/xilinx-zynqmp-dl/git/github.com.Xilinx.u-boot-xlnx.git\" bare=\"True\"/>\n"
  },
  {
    "path": "setup.sh",
    "content": "#!/bin/bash\n#\n# Copyright (C) 2016 Wind River Systems, Inc.\n#\n# This program is free software; you can redistribute it and/or modify\n# it under the terms of the GNU General Public License version 2 as\n# published by the Free Software Foundation.\n#\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n# See the GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program; if not, write to the Free Software\n# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n\nif [ -z \"${BASH_VERSION}\" ]; then\n\techo \"This script must be run with bash.\" >&2\n\texit 1\nfi\n\nwhich python3 > /dev/null\nif [ $? -ne 0 ]; then\n       echo >&2 \"WRLinux setup requires 'python3'.\"\n       echo >&2 \"Please install python3.\"\n       exit 1\nfi\n\nif [ `id -u` = 0 ]; then\n       echo >&2 \"Do not run setup as root.\"\n       exit 1\nfi\n\n: \"${GIT_USERNAME=customer}\"\n: \"${GIT_USEREMAIL=customer@company.com}\"\n\n# Requires python3\nCMD=\"bin/setup.py\"\n\n# Adds arguments to the arg processing\n#   1 - argument\n#   2 - variable to define\n#   3 - keep or discard (if defined, keep)\n#       there may be arguments you don't want passed to the .py script\nsetup_add_arg() {\n\tfound=0\n\tfor parse in ${ARGPARSE[@]}; do\n\t\tcomp=${parse%%:*}\n\t\tif [ \"${comp}\" = \"$1\" ]; then\n\t\t\tfound=1\n\t\tfi\n\tdone\n\n\tif [ ${found} -eq 0 ]; then\n\t\tARGPARSE[${#ARGPARSE[@]}]=\"$1:$2:$3\"\n\tfi\n}\n\n# Functions that add functionality during early processing\nsetup_add_func() {\n\tADDFUNCS[${#ADDFUNCS[@]}]=\"$1\"\n}\n\n# Functions that export variables (or need to run very late)\nsetup_export_func() {\n\tEXPORTFUNCS[${#EXPORTFUNCS[@]}]=\"$1\"\n}\n\n# Functions that run on shutdown\nsetup_shutdown_func() {\n\tSHUTDOWNFUNCS[${#SHUTDOWNFUNCS[@]}]=\"$1\"\n}\n\n# Takes value_name default_value\n# value_name is set to the first value found in the list:\n# git config, git config --global, and finally default_value\nadd_gitconfig() {\n\tVAR=$(git config \"$1\" || git config --global \"$1\" || echo \"$2\")\n\tgit config -f .gitconfig \"${1}\" \"${VAR}\"\n}\n\nshutdown() {\n\tfor func in \"${SHUTDOWNFUNCS[@]}\"; do\n\t\t# During shutdown, we don't care about return codes\n\t\t$func\n\tdone\n}\n\nshutdown_handler() {\n    echo -e \"\\nAborted by user, will terminate this setup.\"\n    shutdown\n    exit 1\n}\n\n# Input: argument list\n# Output: 'help=1' or unset\n#          PASSARGS set to the arguments to pass on\nparse_arguments() {\n\tlocal found keep comp next val\n\twhile [ $# -ge 1 ] ; do\n\t\tfound=0\n\t\tif [ \"$1\" = \"--help\" -o \"$1\" = \"-h\" ]; then\n\t\t\t# Default into a --help module which is part of setup.py\n\t\t\thelp=1\n\t\t\tPASSARGS[${#PASSARGS[@]}]=\"$1\"\n\t\t\tshift\n\t\t\tcontinue\n\t\tfi\n\t\tfor parse in ${ARGPARSE[@]}; do\n\t\t\tcomp=${parse%%:*}\n\t\t\tnext=${parse#${comp}:}\n\t\t\tval=${next%%:*}\n\t\t\tnext=${next#${val}:}\n\t\t\tif [ \"${next}\" != \"${val}\" ]; then\n\t\t\t\tkeep=${next}\n\t\t\telse\n\t\t\t\tkeep=\"\"\n\t\t\tfi\n\t\t\tcase \"$1\" in\n\t\t\t\t${comp}=*)\n\t\t\t\t\teval ${val}=\\${1#*=}\n\t\t\t\t\tif [ -n \"${keep}\" ]; then\n\t\t\t\t\t\tPASSARGS[${#PASSARGS[@]}]=\"$1\"\n\t\t\t\t\tfi\n\t\t\t\t\tshift\n\t\t\t\t\tfound=1\n\t\t\t\t\tbreak\n\t\t\t\t\t;;\n\t\t\t\t${comp})\n\t\t\t\t\teval ${val}=\\${2}\n\t\t\t\t\tif [ -n \"${keep}\" ]; then\n\t\t\t\t\t\tPASSARGS[${#PASSARGS[@]}]=\"$1\"\n\t\t\t\t\t\t# Only check whether $2 is set or not, set to \"\" or '--foo'\n\t\t\t\t\t\t# should work because:\n\t\t\t\t\t\t# - set to \"\": keep align with argparse since it works in this way.\n\t\t\t\t\t\t# - set to \"--foo\": argparse knows it's not the arg of $1,\n\t\t\t\t\t\t#                   but another option, and can handle it correctly.\n\t\t\t\t\t\tif [ -n \"${2+x}\" ]; then\n\t\t\t\t\t\t\tPASSARGS[${#PASSARGS[@]}]=\"$2\"\n\t\t\t\t\t\tfi\n\t\t\t\t\tfi\n\t\t\t\t\tif [ -z \"${2+x}\" ]; then\n\t\t\t\t\t\tshift 1\n\t\t\t\t\telse\n\t\t\t\t\t\tshift 2\n\t\t\t\t\tfi\n\t\t\t\t\tfound=1\n\t\t\t\t\tbreak\n\t\t\t\t\t;;\n\t\t\tesac\n\t\tdone\n\t\tif [ $found -ne 1 ]; then\n\t\t\tPASSARGS[${#PASSARGS[@]}]=\"$1\"\n\t\t\tshift\n\t\tfi\n\tdone\n}\n\n\ntrap shutdown_handler INT\n\n# Setup the minimal defaults first..\n# BASEDIR, BASEURL and BASEBRANCH\nBASEDIR=$(readlink -f \"$(dirname \"$0\")\")\n\n# Argument parsing, define a limited set of args\nsetup_add_arg --base-url BASEURL keep\nsetup_add_arg --base-branch BASEBRANCH keep\n\nhelp=0\nparse_arguments \"$@\"\nunset PASSARGS\n\n# setup git url\nREMOTEURL=$(cd \"$BASEDIR\" ; git config remote.origin.url 2>/dev/null)\n\n# BASEURL is one directory above the git checkout\nBASEREPO=\"\"\nif [ -z \"${BASEURL}\" ]; then\n\tBASEURL=$(echo \"$REMOTEURL\" | sed -e 's,/$,,' -e 's,/[^/]*$,,')\n\tBASEREPO=${REMOTEURL##$BASEURL\\/}\nfi\n\n# First check if this is an absolute path (starts w/ '/')\n# If it's not, we then check if it's a valid URL (contains ://)\nif [ \"${BASEURL:0:1}\" != '/' ]; then\n\tif [ \"${BASEURL#*://}\" == \"${BASEURL}\" -a \"${BASEURL#*:}\" == \"${BASEURL}\" ]; then\n\t\techo >&2\n\t\techo \"ERROR: The BASEURL ($BASEURL) is not in a supported format.\" >&2\n\t\tif [ -n \"${BASEREPO}\" ]; then\n\t\t\techo \"The BASEURL was derived from the URL of $BASEREPO ($REMOTEURL).\" >&2\n\t\t\techo \"Either update the repository URL or use the --base-url argument to override.\" >&2\n\t\tfi\n\t\techo >&2\n\t\techo \"BASEURL must use an absolute file path, or a properly formatted remote URL\" >&2\n\t\techo \"such as:\" >&2\n\t\techo \"  /home/user/path or file:///home/user/path\" >&2\n\t\techo \"  http://hostname/path\" >&2\n\t\techo \"  https://hostname/path\" >&2\n\t\techo \"  git://hostname/path\" >&2\n\t\techo \"  ssh://user@hostname/path\" >&2\n\t\techo \"  [user@]hostname:path\" >&2\n\t\techo >&2\n\t\texit 1\n\tfi\nfi\n\ngit_cmd=\"git --git-dir=$BASEDIR/.git\"\nif [ -z \"${BASEBRANCH}\" ]; then\n\tBASEBRANCH=$($git_cmd rev-parse --abbrev-ref HEAD)\n\tif [ \"$BASEBRANCH\" = \"HEAD\" ]; then\n\t\t# Maybe this is a tag instead?\n\t\tBASEBRANCH=$($git_cmd describe HEAD 2>/dev/null)\n\t\tif [ $? -ne 0 ]; then\n\t\t\t# No reasonable branch/tag name found...\n\t\t\tBASEBRANCH=\"\"\n\t\telse\n\t\t\techo \"$BASEBRANCH\" | grep -q \"vWRLINUX_CI_\"\n\t\t\tif [ $? -ne 0 ]; then\n\t\t\t\techo \"ERROR: Tag $BASEBRANCH is not supported by setup.sh, please use a branch.\" >&2\n\t\t\t\techo \"\"\n\t\t\t\texit 1\n\t\t\tfi\n\t\t\tlatest_tag=$($git_cmd tag --sort=taggerdate |tail -1)\n\t\t\tif [ \"$latest_tag\" != \"$BASEBRANCH\" ]; then\n\t\t\t\t\techo \"ERROR: Only latest tag is supported\" >&2\n\t\t\t\t\techo \"ERROR: Current tag: $BASEBRANCH\" >&2\n\t\t\t\t\techo \"ERROR: Latest  tag: $latest_tag\" >&2\n\t\t\t\t\techo \"\"\n\t\t\t\t\texit 1\n\t\t\tfi\n\t\t\tBASEBRANCH=\"refs/tags/$BASEBRANCH\"\n\t\tfi\n\tfi\nfi\n\n# Load custom setup additions\nif [ -d \"${BASEDIR}/data/environment.d\" ]; then\n\tfor envfile in ${BASEDIR}/data/environment.d/*.sh ; do\n\t\t. $envfile\n\tdone\nfi\n\n# We need to reparse the arguments as we've now loaded the environment.d\n# extensions\nhelp=0\nparse_arguments \"$@\"\n\nif [ $help -ne 1 ]; then\n\t# Before doing anything else, error out if the project directory\n\t# is unsafe.\n\tcase \"$PWD\" in\n\t\t$BASEDIR | $BASEDIR/*)\n\t\techo >&2 \"$0: The current working directory is used as your project directory\"\n\t\techo >&2 \"    Your project directory must not be in or under\"\n\t\techo >&2 \"    '${BASEDIR}'\"\n\t\techo >&2 \"\"\n\t\techo >&2 \"    Typically a project is setup by doing:\"\n\t\techo >&2 \"      $ mkdir my_project\"\n\t\techo >&2 \"      $ cd my_project\"\n\t\techo >&2 \"      $ git clone --branch $BASEBRANCH $REMOTEURL\"\n\t\techo >&2 \"      $ .$(echo $REMOTEURL | sed \"s,$BASEURL,,\")/setup.sh $@\"\n\t\texit 1\n\t\t;;\n\tesac\n\n\tif [ -z \"$BASEBRANCH\" ]; then\n\t\techo \"May be on a detached HEAD, HEAD must be on a branch or tag. ($BASEDIR)\" >&2\n\t\techo \"You can avoid this by passing the branch using --base-branch=\" >&2\n\t\texit 1\n\tfi\n\n        # Is this a tag?  If so, don't allow tags w/ '-'\n\tif [ \"$BASEBRANCH\" != \"${BASEBRANCH##refs/tags/}\" ]; then\n\t\tif [ \"$BASEBRANCH\" != \"${BASEBRANCH//-*}\" ]; then\n\t\t\techo \"Checkout may be on a detached HEAD, this HEAD does not appear to\" >&2\n\t\t\techo \"correspond to a specific, tag.  (It appears you may be working with\" >&2\n\t\t\techo \"tag ${BASEBRANCH//-*}.  If this is correct, use\" >&2\n\t\t\techo \"--base-branch=${BASEBRANCH//-*} in the arguments to\" >&2\n\t\t\techo \"$0.\"\n\t\t\texit 1\n\t\tfi\n\tfi\n\n\tfor func in \"${ADDFUNCS[@]}\"; do\n\t\t$func\n\t\trc=$?\n\t\tif [ $rc -ne 0 ]; then\n\t\t\techo \"Stopping: an error occurred in $func.\" >&2\n\t\t\tshutdown\n\t\t\texit $rc\n\t\tfi\n\tdone\n\n\t# Configure the current directory so repo works seemlessly\n\tadd_gitconfig \"user.name\" \"${GIT_USERNAME}\"\n\tadd_gitconfig \"user.email\" \"${GIT_USEREMAIL}\"\n\tadd_gitconfig \"color.ui\" \"false\"\n\tadd_gitconfig \"color.diff\" \"false\"\n\tadd_gitconfig \"color.status\" \"false\"\nfi # if help -ne 1\n\n# We potentially have code that doesn't parse correctly with older versions \n# of Python, and rather than fixing that and being eternally vigilant for \n# any other new feature use, just check the version here.\npy_v35_check=$(python3 -c 'import sys; print(sys.version_info >= (3,5,0))')\nif [ \"$py_v35_check\" != \"True\" ]; then\n    echo >&2 \"BitBake requires Python 3.5.0 or later as 'python3 (scripts/install-buildtools can be used if needed)'\"\n    return 1\nfi\nunset py_v35_check\n\n# This can happen if python3/urllib was not built with SSL support.\npython3 -c 'import urllib.request ; dir(urllib.request.HTTPSHandler)' >/dev/null 2>&1\nif [ $? -ne 0 ]; then\n\techo >&2 \"The setup tool requires Python 3.4.0 or later with support for 'urllib.request.HTTPSHandler'\"\n\texit 1\nfi\n\n# Python 3 required utf-8 support to work properly, adjust the LANG to en_US.UTF-8.\nexport LANG='en_US.UTF-8'\n\n# Pass the computed url and branch to ${cmd}\nexport OE_BASEURL=${BASEURL}\nexport OE_BASEBRANCH=${BASEBRANCH}\n\nfor func in \"${EXPORTFUNCS[@]}\"; do\n\t$func\n\trc=$?\n\tif [ $rc -ne 0 ]; then\n\t\techo \"Stopping: an error occurred in $func.\" >&2\n\t\tshutdown\n\t\texit $rc\n\tfi\ndone\n\ntrap - INT\n# Switch to the python script\n${BASEDIR}/${CMD} \"${PASSARGS[@]}\"\nrc=$?\n\nshutdown\n\n# Preserve the return code from the python script\nexit $rc\n"
  }
]