├── .gitattributes ├── .gitignore ├── Kconfig ├── LICENSE ├── MANIFEST.in ├── README.md ├── archive.py ├── cmds ├── Kconfig ├── __init__.py ├── cmd_menuconfig.py ├── cmd_package │ ├── __init__.py │ ├── cmd_package_list.py │ ├── cmd_package_printenv.py │ ├── cmd_package_update.py │ ├── cmd_package_upgrade.py │ ├── cmd_package_utils.py │ └── cmd_package_wizard.py ├── cmd_sdk.py └── cmd_system.py ├── env.json ├── env.ps1 ├── env.py ├── env.sh ├── install_arch.sh ├── install_macos.sh ├── install_suse.sh ├── install_ubuntu.sh ├── install_windows.ps1 ├── kconfig-mconf.zip ├── kconfig.py ├── menuconfig ├── package.py ├── pkgs ├── pkgsdb.py ├── pyproject.toml ├── sdk ├── setup.py ├── statistics.py ├── touch_env.ps1 ├── touch_env.py ├── touch_env.sh └── vars.py /.gitattributes: -------------------------------------------------------------------------------- 1 | # .gitattributes for Env Project. 2 | 3 | # Handle line endings automatically for files detected as text 4 | # and leave all files detected as binary untouched. 5 | # ============ 6 | * text=auto 7 | 8 | # Source files 9 | # ============ 10 | *.pxd text eol=crlf diff=python 11 | *.py text eol=crlf diff=python 12 | *.py3 text eol=crlf diff=python 13 | *.pyw text eol=crlf diff=python 14 | *.pyx text eol=crlf diff=python 15 | *.pyz text eol=crlf diff=python 16 | *.pyi text eol=crlf diff=python 17 | 18 | # Binary files 19 | # ============ 20 | *.db binary 21 | *.p binary 22 | *.pkl binary 23 | *.pickle binary 24 | *.pyc binary 25 | *.pyd binary 26 | *.pyo binary 27 | 28 | # MarkDown 29 | *.md text eol=crlf 30 | 31 | *.bat text eol=crlf 32 | *.ps1 text eol=crlf -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | 49 | # Translations 50 | *.mo 51 | *.pot 52 | 53 | # Django stuff: 54 | *.log 55 | local_settings.py 56 | 57 | # Flask stuff: 58 | instance/ 59 | .webassets-cache 60 | 61 | # Scrapy stuff: 62 | .scrapy 63 | 64 | # Sphinx documentation 65 | docs/_build/ 66 | 67 | # PyBuilder 68 | target/ 69 | 70 | # Jupyter Notebook 71 | .ipynb_checkpoints 72 | 73 | # pyenv 74 | .python-version 75 | 76 | # celery beat schedule file 77 | celerybeat-schedule 78 | 79 | # SageMath parsed files 80 | *.sage.py 81 | 82 | # dotenv 83 | .env 84 | 85 | # virtualenv 86 | .venv 87 | venv/ 88 | ENV/ 89 | 90 | # Spyder project settings 91 | .spyderproject 92 | .spyproject 93 | 94 | # Rope project settings 95 | .ropeproject 96 | 97 | # mkdocs documentation 98 | /site 99 | 100 | # mypy 101 | .mypy_cache/ 102 | .vscode/settings.json 103 | cmds/.config.old 104 | /cmds/.config 105 | 106 | # packages and sdk 107 | packages 108 | sdk_list.json 109 | sdk_cfg.json 110 | .config 111 | .config.old 112 | -------------------------------------------------------------------------------- /Kconfig: -------------------------------------------------------------------------------- 1 | config PKGS_DIR 2 | string 3 | option env="PKGS_ROOT" 4 | default "packages" 5 | 6 | config TARGET_FILE 7 | string 8 | default "" 9 | 10 | config HOSTOS 11 | string 12 | option env="HOSTOS" 13 | default "Linux" 14 | 15 | source "$PKGS_DIR/sdk/$HOSTOS/Kconfig" 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RT-Thread/env/501626f9a5ee4b2067fba084bb197d64e350aba0/MANIFEST.in -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Python Scripts for RT-Thread Env 2 | 3 | > WARNING 4 | > 5 | > [env v2.0](https://github.com/RT-Thread/env/tree/master) and [env-windows v2.0](https://github.com/RT-Thread/env-windows/tree/v2.0.0) only **FULL SUPPORT** RT-Thread > v5.1.0 or [master](https://github.com/rt-thread/rt-thread) branch. if you work on RT-Thread <= v5.1.0, please use [env v1.5.x](https://github.com/RT-Thread/env/tree/v1.5.x) for linux, [env-windows v1.5.x](https://github.com/RT-Thread/env-windows/tree/v1.5.2) for windows 6 | > 7 | > env v2.0 has made the following important changes: 8 | > - Upgrading Python version from v2 to v3 9 | > - Replacing kconfig-frontends with Python kconfiglib 10 | > 11 | > env v2.0 require python kconfiglib (install by `pip install kconfiglib`), but env v1.5.x confilt with kconfiglib (please run `pip uninstall kconfiglib`) 12 | 13 | ## Usage under Linux 14 | 15 | ### Tutorial 16 | 17 | [How to install Env Tool with QEMU simulator in Ubuntu](https://github.com/RT-Thread/rt-thread/blob/master/documentation/quick-start/quick_start_qemu/quick_start_qemu_linux.md) 18 | 19 | ### Install Env 20 | 21 | ``` 22 | wget https://raw.githubusercontent.com/RT-Thread/env/master/install_ubuntu.sh 23 | chmod 777 install_ubuntu.sh 24 | ./install_ubuntu.sh 25 | rm install_ubuntu.sh 26 | ``` 27 | 28 | 对于中国大陆用户,请使用以下命令 29 | 30 | ``` 31 | wget https://gitee.com/RT-Thread-Mirror/env/raw/master/install_ubuntu.sh 32 | chmod 777 install_ubuntu.sh 33 | ./install_ubuntu.sh --gitee 34 | rm install_ubuntu.sh 35 | ``` 36 | 37 | ### Prepare Env 38 | 39 | PLAN A: Whenever start the ubuntu system, you need to type command `source ~/.env/env.sh` to activate the environment variables. 40 | 41 | or PLAN B: open `~/.bashrc` file, and attach the command `source ~/.env/env.sh` at the end of the file. It will be automatically executed when you log in the ubuntu, and you don't need to execute that command any more. 42 | 43 | ### Use Env 44 | 45 | Please see: 46 | 47 | ## Usage under Windows 48 | 49 | Tested on the following version of PowerShell: 50 | 51 | - PSVersion 5.1.22621.963 52 | - PSVersion 5.1.19041.2673 53 | 54 | ### Install Env 55 | 56 | 您需要以管理员身份运行 PowerShell 来设置执行。(You need to run PowerShell as an administrator to set up execution.) 57 | 58 | 在 PowerShell 中执行(Execute the command in PowerShell): 59 | 60 | ```powershell 61 | wget https://raw.githubusercontent.com/RT-Thread/env/master/install_windows.ps1 -O install_windows.ps1 62 | set-executionpolicy remotesigned 63 | .\install_windows.ps1 64 | ``` 65 | 66 | 对于中国大陆用户,请使用以下命令: 67 | 68 | ```powershell 69 | wget https://gitee.com/RT-Thread-Mirror/env/raw/master/install_windows.ps1 -O install_windows.ps1 70 | set-executionpolicy remotesigned 71 | .\install_windows.ps1 --gitee 72 | ``` 73 | 74 | 注意: 75 | 76 | 1. Powershell要以管理员身份运行。 77 | 2. 将其设置为 remotesigned 后,您可以作为普通用户运行 PowerShell。( After setting it to remotesigned, you can run PowerShell as a normal user.) 78 | 3. 一定要关闭杀毒软件,否则安装过程可能会被杀毒软件强退 79 | 80 | ### Prepare Env 81 | 82 | 方案 A:每次重启 PowerShell 时,都需要输入命令 `~/.env/env.ps1`,以激活环境变量。(PLAN A: Each time you restart PowerShell, you need to enter the command `~/.env/env.ps1` to activate the environment variable.) 83 | 84 | 方案 B (推荐):打开 `C:\Users\user\Documents\WindowsPowerShell`,如果没有`WindowsPowerShell`则新建该文件夹。新建文件 `Microsoft.PowerShell_profile.ps1`,然后写入 `~/.env/env.ps1` 内容即可,它将在你重启 PowerShell 时自动执行,无需再执行方案 A 中的命令。(or PLAN B (recommended): Open `C:\Users\user\Documents\WindowsPowerShell` and create a new file `Microsoft.PowerShell_profile.ps1`. Then write `~/.env/env.ps1` to the file. It will be executed automatically when you restart PowerShell, without having to execute the command in scenario A.) 85 | -------------------------------------------------------------------------------- /archive.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | # 3 | # File : archive.py 4 | # This file is part of RT-Thread RTOS 5 | # COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team 6 | # 7 | # This program is free software; you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation; either version 2 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # This program is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License along 18 | # with this program; if not, write to the Free Software Foundation, Inc., 19 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 20 | # 21 | # Change Logs: 22 | # Date Author Notes 23 | # 2018-5-28 SummerGift Add copyright information 24 | # 2020-4-10 SummerGift Code clear up 25 | # 26 | 27 | import logging 28 | import os 29 | import shutil 30 | import tarfile 31 | import zipfile 32 | import pkgsdb 33 | from cmds.cmd_package.cmd_package_utils import is_windows, remove_folder 34 | from tqdm import tqdm 35 | 36 | 37 | def unpack(archive_filename, bsp_package_path, package_info, package_name): 38 | if archive_filename.endswith(".zip"): 39 | return handle_zip_package(archive_filename, bsp_package_path, package_name, package_info) 40 | 41 | if ".tar." in archive_filename: 42 | return handle_tar_package(archive_filename, bsp_package_path, package_name, package_info) 43 | 44 | return True 45 | 46 | 47 | def handle_tar_package(archive_filename, bsp_package_path, package_name, package_info): 48 | package_version = package_info['ver'] 49 | package_temp_path = os.path.join(bsp_package_path, "package_temp") 50 | 51 | try: 52 | if remove_folder(package_temp_path): 53 | os.makedirs(package_temp_path) 54 | except Exception as e: 55 | logging.warning('Error message : {0}'.format(e)) 56 | 57 | logging.info("BSP packages path {0}".format(bsp_package_path)) 58 | logging.info("BSP package temp path: {0}".format(package_temp_path)) 59 | logging.info("archive filename : {0}".format(archive_filename)) 60 | 61 | try: 62 | flag = True 63 | package_folder_name = "" 64 | package_name_with_version = "" 65 | arch = tarfile.open(archive_filename, "r") 66 | for item in tqdm(arch.getnames()): 67 | arch.extract(item, package_temp_path) 68 | if not os.path.isdir(os.path.join(package_temp_path, item)): 69 | # Gets the folder name and changed folder name only once 70 | if flag: 71 | package_folder_name = item.split('/')[0] 72 | package_name_with_version = package_name + '-' + package_version 73 | flag = False 74 | 75 | if is_windows(): 76 | right_path = item.replace('/', '\\') 77 | else: 78 | right_path = item 79 | 80 | right_name_to_db = right_path.replace(package_folder_name, package_name_with_version, 1) 81 | right_path = os.path.join("package_temp", right_path) 82 | pkgsdb.save_to_database(right_name_to_db, archive_filename, right_path) 83 | arch.close() 84 | 85 | if not move_package_to_bsp_packages( 86 | package_folder_name, package_name, package_temp_path, package_version, bsp_package_path 87 | ): 88 | return False 89 | 90 | except Exception as e: 91 | logging.warning('unpack error message : {0}'.format(e)) 92 | logging.warning('unpack {0} failed'.format(os.path.basename(archive_filename))) 93 | # remove temp folder and archive file 94 | remove_folder(package_temp_path) 95 | os.remove(archive_filename) 96 | return False 97 | 98 | return True 99 | 100 | 101 | def handle_zip_package(archive_filename, bsp_package_path, package_name, package_info): 102 | package_version = package_info['ver'] 103 | package_temp_path = os.path.join(bsp_package_path, "package_temp") 104 | 105 | try: 106 | if remove_folder(package_temp_path): 107 | os.makedirs(package_temp_path) 108 | except Exception as e: 109 | logging.warning('Error message : {0}'.format(e)) 110 | 111 | logging.info("BSP packages path {0}".format(bsp_package_path)) 112 | logging.info("BSP package temp path: {0}".format(package_temp_path)) 113 | logging.info("archive filename : {0}".format(archive_filename)) 114 | 115 | try: 116 | flag = True 117 | package_folder_name = "" 118 | package_name_with_version = "" 119 | arch = zipfile.ZipFile(archive_filename, "r") 120 | for item in tqdm(arch.namelist()): 121 | arch.extract(item, package_temp_path) 122 | if not os.path.isdir(os.path.join(package_temp_path, item)): 123 | # Gets the folder name and changed folder name only once 124 | if flag: 125 | package_folder_name = item.split('/')[0] 126 | package_name_with_version = package_name + '-' + package_version 127 | flag = False 128 | if is_windows(): 129 | right_path = item.replace('/', '\\') 130 | else: 131 | right_path = item 132 | 133 | right_name_to_db = right_path.replace(package_folder_name, package_name_with_version, 1) 134 | right_path = os.path.join("package_temp", right_path) 135 | pkgsdb.save_to_database(right_name_to_db, archive_filename, right_path) 136 | arch.close() 137 | 138 | if not move_package_to_bsp_packages( 139 | package_folder_name, package_name, package_temp_path, package_version, bsp_package_path 140 | ): 141 | return False 142 | except Exception as e: 143 | logging.warning('unpack error message : {0}'.format(e)) 144 | logging.warning('unpack {0} failed'.format(os.path.basename(archive_filename))) 145 | # remove temp folder and archive file 146 | remove_folder(package_temp_path) 147 | os.remove(archive_filename) 148 | return False 149 | 150 | return True 151 | 152 | 153 | def move_package_to_bsp_packages(package_folder_name, package_name, package_temp_path, package_version, bsp_packages_path): 154 | """move package in temp folder to bsp packages folder.""" 155 | origin_package_folder_path = os.path.join(package_temp_path, package_folder_name) 156 | package_name_with_version = package_name + '-' + package_version 157 | package_folder_in_temp = os.path.join(package_temp_path, package_name_with_version) 158 | bsp_package_path = os.path.join(bsp_packages_path, package_name_with_version) 159 | logging.info("origin name: {0}".format(origin_package_folder_path)) 160 | logging.info("rename name: {0}".format(package_folder_in_temp)) 161 | 162 | result = True 163 | try: 164 | # rename package folder name to package name with version 165 | os.rename(origin_package_folder_path, package_folder_in_temp) 166 | 167 | # if there is no specified version package in the bsp package path, 168 | # then move package from package_folder_in_temp to bsp_package_path 169 | if not os.path.isdir(bsp_package_path): 170 | shutil.move(package_folder_in_temp, bsp_package_path) 171 | except Exception as e: 172 | logging.warning('{0}'.format(e)) 173 | result = False 174 | finally: 175 | # must remove temp folder 176 | remove_folder(package_temp_path) 177 | 178 | return result 179 | 180 | 181 | def package_integrity_test(path): 182 | ret = True 183 | 184 | if path.endswith(".zip"): 185 | try: 186 | if zipfile.is_zipfile(path): 187 | # Test zip again to make sure it's a right zip file. 188 | arch = zipfile.ZipFile(path, "r") 189 | if arch.testzip(): 190 | ret = False 191 | arch.close() 192 | else: 193 | ret = False 194 | print('package check error. \n') 195 | except Exception as e: 196 | print('Package test error message:%s\t' % e) 197 | print("The archive package is broken. \n") 198 | arch.close() 199 | ret = False 200 | 201 | # if ".tar.*" in path:. 202 | if path.endswith(".tar.bz2") or path.endswith(".tar.gz") or path.endswith(".tar.xz"): 203 | try: 204 | if not tarfile.is_tarfile(path): 205 | ret = False 206 | except Exception as e: 207 | print('Error message:%s' % e) 208 | ret = False 209 | 210 | return ret 211 | -------------------------------------------------------------------------------- /cmds/Kconfig: -------------------------------------------------------------------------------- 1 | menu "Env config" 2 | 3 | config SYS_AUTO_UPDATE_PKGS 4 | bool "Auto update pkgs config" 5 | default y 6 | 7 | choice 8 | prompt "Select download server" 9 | config SYS_DOWNLOAD_SERVER_AUTO 10 | bool "Auto" 11 | 12 | config SYS_DOWNLOAD_SERVER_GITHUB 13 | bool "Github" 14 | 15 | config SYS_DOWNLOAD_SERVER_GITEE 16 | bool "Gitee" 17 | endchoice 18 | 19 | config SYS_CREATE_MDK_IAR_PROJECT 20 | bool "Auto create a Keil-MDK or IAR project" 21 | default n 22 | 23 | if SYS_CREATE_MDK_IAR_PROJECT 24 | 25 | choice 26 | prompt "Project type" 27 | help 28 | Select the project type mdk or iar 29 | 30 | config SYS_CREATE_MDK5 31 | bool "MDK5" 32 | 33 | config SYS_CREATE_IAR 34 | bool "IAR" 35 | 36 | config SYS_CREATE_MDK4 37 | bool "MDK4" 38 | endchoice 39 | 40 | config SYS_CREATE_MDK_EXEC_PATH 41 | string "MDK Path" 42 | depends on SYS_CREATE_MDK5 || SYS_CREATE_MDK4 43 | default "C:/Keil_v5" 44 | 45 | config SYS_CREATE_IAR_EXEC_PATH 46 | string "IAR Path" 47 | depends on SYS_CREATE_IAR 48 | default "C:/Program Files (x86)/IAR Systems/Embedded Workbench 8.3" 49 | 50 | endif 51 | 52 | config SYS_PKGS_USING_STATISTICS 53 | bool "Send usage data for improve product" 54 | default y 55 | help 56 | Reads the user's mac address and returns it to the rt-thread official, 57 | which is used to count the number of users 58 | 59 | endmenu 60 | 61 | -------------------------------------------------------------------------------- /cmds/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | # 3 | # File : cmds.py 4 | # This file is part of RT-Thread RTOS 5 | # COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team 6 | # 7 | # This program is free software; you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation; either version 2 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # This program is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License along 18 | # with this program; if not, write to the Free Software Foundation, Inc., 19 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 20 | # 21 | # Change Logs: 22 | # Date Author Notes 23 | # 2018-5-28 SummerGift Add copyright information 24 | # 25 | 26 | __all__ = ['cmd_package', 'cmd_system', 'cmd_menuconfig', 'cmd_sdk'] 27 | 28 | try: 29 | import requests 30 | except ImportError: 31 | print( 32 | "****************************************\n" 33 | "* Import requests module error.\n" 34 | "* Please install requests module first.\n" 35 | "* pip install step:\n" 36 | "* $ pip install requests\n" 37 | "* command install step:\n" 38 | "* $ sudo apt-get install python-requests\n" 39 | "****************************************\n" 40 | ) 41 | -------------------------------------------------------------------------------- /cmds/cmd_menuconfig.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | # 3 | # File : cmd_menuconfig.py 4 | # This file is part of RT-Thread RTOS 5 | # COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team 6 | # 7 | # This program is free software; you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation; either version 2 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # This program is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License along 18 | # with this program; if not, write to the Free Software Foundation, Inc., 19 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 20 | # 21 | # Change Logs: 22 | # Date Author Notes 23 | # 2018-05-28 SummerGift Add copyright information 24 | # 2019-01-07 SummerGift The prompt supports utf-8 encoding 25 | # 2019-10-30 SummerGift fix bug when generate some config item 26 | # 27 | 28 | import os 29 | import platform 30 | import re 31 | import sys 32 | 33 | from vars import Import 34 | from .cmd_package.cmd_package_utils import find_bool_macro_in_config, find_IAR_EXEC_PATH, find_MDK_EXEC_PATH 35 | 36 | 37 | def is_in_powershell(): 38 | rst = False 39 | try: 40 | import psutil 41 | 42 | rst = bool(re.fullmatch('pwsh|pwsh.exe|powershell.exe', psutil.Process(os.getppid()).name())) 43 | except: 44 | pass 45 | 46 | return rst 47 | 48 | 49 | def build_kconfig_frontends(rtt_root): 50 | kconfig_dir = os.path.join(rtt_root, 'tools', 'kconfig-frontends') 51 | os.system('scons -C ' + kconfig_dir) 52 | 53 | 54 | def get_rtt_root(): 55 | rtt_root = os.getenv("RTT_ROOT") 56 | if rtt_root is None: 57 | bsp_root = Import("bsp_root") 58 | if not os.path.exists(os.path.join(bsp_root, 'Kconfig')): 59 | return rtt_root 60 | with open(os.path.join(bsp_root, 'Kconfig')) as kconfig: 61 | lines = kconfig.readlines() 62 | for i in range(len(lines)): 63 | if "config RTT_DIR" in lines[i]: 64 | rtt_root = lines[i + 3].strip().split(" ")[1].strip('"') 65 | if not os.path.isabs(rtt_root): 66 | rtt_root = os.path.join(bsp_root, rtt_root) 67 | break 68 | return rtt_root 69 | 70 | 71 | def is_pkg_special_config(config_str): 72 | """judge if it's CONFIG_PKG_XX_PATH or CONFIG_PKG_XX_VER""" 73 | 74 | if isinstance(config_str, str): 75 | if config_str.startswith("PKG_") and (config_str.endswith('_PATH') or config_str.endswith('_VER')): 76 | return True 77 | return False 78 | 79 | 80 | def get_target_file(filename): 81 | try: 82 | config = open(filename, "r") 83 | except: 84 | print('open config:%s failed' % filename) 85 | return None 86 | 87 | for line in config: 88 | line = line.lstrip(' ').replace('\n', '').replace('\r', '') 89 | 90 | if len(line) == 0: 91 | continue 92 | 93 | if line[0] == '#': 94 | continue 95 | else: 96 | setting = line.split('=') 97 | if len(setting) >= 2: 98 | if setting[0].startswith('CONFIG_TARGET_FILE'): 99 | target_fn = re.findall(r"^.*?=(.*)$", line)[0] 100 | if target_fn.startswith('"'): 101 | target_fn = target_fn.replace('"', '') 102 | 103 | if target_fn == '': 104 | return None 105 | else: 106 | return target_fn 107 | 108 | return 'rtconfig.h' 109 | 110 | 111 | def mk_rtconfig(filename): 112 | try: 113 | config = open(filename, 'r') 114 | except Exception as e: 115 | print('Error message:%s' % e) 116 | print('open config:%s failed' % filename) 117 | return 118 | 119 | target_fn = get_target_file(filename) 120 | if target_fn == None: 121 | return 122 | 123 | rtconfig = open(target_fn, 'w') 124 | rtconfig.write('#ifndef RT_CONFIG_H__\n') 125 | rtconfig.write('#define RT_CONFIG_H__\n\n') 126 | 127 | empty_line = 1 128 | 129 | for line in config: 130 | line = line.lstrip(' ').replace('\n', '').replace('\r', '') 131 | 132 | if len(line) == 0: 133 | continue 134 | 135 | if line[0] == '#': 136 | if len(line) == 1: 137 | if empty_line: 138 | continue 139 | 140 | rtconfig.write('\n') 141 | empty_line = 1 142 | continue 143 | 144 | if line.startswith('# CONFIG_'): 145 | line = ' ' + line[9:] 146 | else: 147 | line = line[1:] 148 | rtconfig.write('/*%s */\n' % line) 149 | 150 | empty_line = 0 151 | else: 152 | empty_line = 0 153 | setting = line.split('=') 154 | if len(setting) >= 2: 155 | if setting[0].startswith('CONFIG_'): 156 | setting[0] = setting[0][7:] 157 | 158 | # remove CONFIG_PKG_XX_PATH or CONFIG_PKG_XX_VER 159 | if is_pkg_special_config(setting[0]): 160 | continue 161 | 162 | if setting[1] == 'y': 163 | rtconfig.write('#define %s\n' % setting[0]) 164 | else: 165 | rtconfig.write('#define %s %s\n' % (setting[0], re.findall(r"^.*?=(.*)$", line)[0])) 166 | 167 | if os.path.isfile('rtconfig_project.h'): 168 | rtconfig.write('#include "rtconfig_project.h"\n') 169 | 170 | rtconfig.write('\n') 171 | rtconfig.write('#endif\n') 172 | rtconfig.close() 173 | 174 | 175 | # fix locale for kconfiglib 176 | def kconfiglib_fix_locale(): 177 | import os 178 | import locale 179 | 180 | # Get the list of supported locales 181 | supported_locales = set(locale.locale_alias.keys()) 182 | 183 | # Check if LANG is set and its value is not in the supported locales 184 | if 'LANG' in os.environ and os.environ['LANG'] not in supported_locales: 185 | os.environ['LANG'] = 'C' 186 | 187 | def cmd(args): 188 | import menuconfig 189 | import defconfig 190 | 191 | env_root = Import('env_root') 192 | 193 | # get RTT_DIR from environment or Kconfig file 194 | if get_rtt_root(): 195 | os.environ['RTT_DIR'] = get_rtt_root() 196 | 197 | if not os.path.exists('Kconfig'): 198 | if platform.system() == "Windows": 199 | os.system('chcp 65001 > nul') 200 | 201 | print( 202 | "\n\033[1;31;40m 命令应当在某一特定 BSP 目录下执行,例如:\"rt-thread/bsp/stm32/stm32f091-st-nucleo\"\033[0m" 203 | ) 204 | print("\033[1;31;40m请确保当前目录为 BSP 根目录,并且该目录中有 Kconfig 文件。\033[0m\n") 205 | 206 | print(" command should be used in a bsp root path with a Kconfig file.") 207 | print("Example: \"rt-thread/bsp/stm32/stm32f091-st-nucleo\"") 208 | print("You should check if there is a Kconfig file in your bsp root first.") 209 | 210 | if platform.system() == "Windows": 211 | os.system('chcp 437 > nul') 212 | 213 | return False 214 | 215 | if platform.system() == "Windows": 216 | os.system('chcp 437 > nul') 217 | 218 | # Env config, auto update packages and create mdk/iar project 219 | if args.menuconfig_setting: 220 | env_kconfig_path = os.path.join(env_root, 'tools', 'scripts', 'cmds') 221 | beforepath = os.getcwd() 222 | os.chdir(env_kconfig_path) 223 | sys.argv = ['menuconfig', 'Kconfig'] 224 | menuconfig._main() 225 | os.chdir(beforepath) 226 | return 227 | 228 | # generate rtconfig.h by .config. 229 | if args.menuconfig_g: 230 | print('generate rtconfig.h from .config') 231 | mk_rtconfig(".config") 232 | return 233 | 234 | if os.path.isfile(".config"): 235 | mtime = os.path.getmtime(".config") 236 | else: 237 | mtime = -1 238 | 239 | # Using the user specified configuration file 240 | if args.menuconfig_fn: 241 | print('use', args.menuconfig_fn) 242 | import shutil 243 | 244 | shutil.copy(args.menuconfig_fn, ".config") 245 | 246 | if args.menuconfig_silent: 247 | sys.argv = ['defconfig', '--kconfig=Kconfig', '.config'] 248 | defconfig.main() 249 | else: 250 | sys.argv = ['menuconfig', 'Kconfig'] 251 | kconfiglib_fix_locale() 252 | menuconfig._main() 253 | 254 | if os.path.isfile(".config"): 255 | mtime2 = os.path.getmtime(".config") 256 | else: 257 | mtime2 = -1 258 | 259 | # generate rtconfig.h by .config. 260 | if mtime != mtime2: 261 | mk_rtconfig(".config") 262 | 263 | # update pkgs 264 | env_kconfig_path = os.path.join(env_root, 'tools', 'scripts', 'cmds') 265 | fn = os.path.join(env_kconfig_path, '.config') 266 | 267 | if not os.path.isfile(fn): 268 | return 269 | 270 | if find_bool_macro_in_config(fn, 'SYS_AUTO_UPDATE_PKGS'): 271 | if is_in_powershell(): 272 | os.system('powershell pkgs.ps1 --update') 273 | else: 274 | os.system('pkgs --update') 275 | print("==============================>The packages have been updated completely.") 276 | 277 | if platform.system() == "Windows": 278 | if find_bool_macro_in_config(fn, 'SYS_CREATE_MDK_IAR_PROJECT'): 279 | mdk_path = find_MDK_EXEC_PATH() 280 | iar_path = find_IAR_EXEC_PATH() 281 | 282 | if find_bool_macro_in_config(fn, 'SYS_CREATE_MDK4'): 283 | if mdk_path: 284 | os.system('scons --target=mdk4 -s --exec-path="' + mdk_path + '"') 285 | else: 286 | os.system('scons --target=mdk4 -s') 287 | print("Create Keil-MDK4 project done") 288 | elif find_bool_macro_in_config(fn, 'SYS_CREATE_MDK5'): 289 | if mdk_path: 290 | os.system('scons --target=mdk5 -s --exec-path="' + mdk_path + '"') 291 | else: 292 | os.system('scons --target=mdk5 -s') 293 | print("Create Keil-MDK5 project done") 294 | elif find_bool_macro_in_config(fn, 'SYS_CREATE_IAR'): 295 | if iar_path: 296 | os.system('scons --target=iar -s --exec-path="' + iar_path + '"') 297 | else: 298 | os.system('scons --target=iar -s') 299 | print("Create IAR project done") 300 | 301 | 302 | def add_parser(sub): 303 | parser = sub.add_parser( 304 | 'menuconfig', 305 | help=__doc__, 306 | description=__doc__, 307 | ) 308 | 309 | parser.add_argument( 310 | '--config', 311 | help='Using the user specified configuration file.', 312 | dest='menuconfig_fn', 313 | ) 314 | 315 | parser.add_argument( 316 | '--generate', 317 | help='generate rtconfig.h by .config.', 318 | action='store_true', 319 | default=False, 320 | dest='menuconfig_g', 321 | ) 322 | 323 | parser.add_argument( 324 | '--silent', 325 | help='Silent mode,don\'t display menuconfig window.', 326 | action='store_true', 327 | default=False, 328 | dest='menuconfig_silent', 329 | ) 330 | 331 | parser.add_argument( 332 | '-s', 333 | '--setting', 334 | help='Env config,auto update packages and create mdk/iar project', 335 | action='store_true', 336 | default=False, 337 | dest='menuconfig_setting', 338 | ) 339 | 340 | # parser.add_argument('--easy', 341 | # help='easy mode, place kconfig everywhere, modify the option env="RTT_ROOT" default "../.."', 342 | # action='store_true', 343 | # default=False, 344 | # dest='menuconfig_easy') 345 | 346 | parser.set_defaults(func=cmd) 347 | -------------------------------------------------------------------------------- /cmds/cmd_package/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | # 3 | # File : cmd_package.py 4 | # This file is part of RT-Thread RTOS 5 | # COPYRIGHT (C) 2006 - 2020, RT-Thread Development Team 6 | # 7 | # This program is free software; you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation; either version 2 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # This program is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License along 18 | # with this program; if not, write to the Free Software Foundation, Inc., 19 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 20 | # 21 | # Change Logs: 22 | # Date Author Notes 23 | # 2018-05-28 SummerGift Add copyright information 24 | # 2018-12-28 Ernest Chen Add package information and enjoy package maker 25 | # 2019-01-07 SummerGift The prompt supports utf-8 encoding 26 | # 2020-04-08 SummerGift Optimize program structure 27 | # 28 | 29 | from .cmd_package_printenv import package_print_env, package_print_help 30 | from .cmd_package_list import list_packages, get_packages 31 | from .cmd_package_wizard import package_wizard 32 | from .cmd_package_update import package_update 33 | from .cmd_package_upgrade import package_upgrade, package_upgrade_modules 34 | 35 | 36 | def run_env_cmd(args): 37 | """Run packages command.""" 38 | 39 | if args.package_update_force: 40 | package_update(True) 41 | elif args.package_update: 42 | package_update() 43 | elif args.package_create: 44 | package_wizard() 45 | elif args.list_packages: 46 | list_packages() 47 | elif args.package_upgrade: 48 | package_upgrade() 49 | elif args.package_upgrade_force: 50 | package_upgrade(force_upgrade=True) 51 | elif args.package_upgrade_script_force: 52 | package_upgrade(force_upgrade=True, upgrade_script=True) 53 | elif args.package_upgrade_modules: 54 | package_upgrade_modules() 55 | elif args.package_print_env: 56 | package_print_env() 57 | else: 58 | package_print_help() 59 | 60 | 61 | def add_parser(sub): 62 | """The packages command parser for env.""" 63 | 64 | parser = sub.add_parser( 65 | 'pkg', 66 | aliases=['pkgs', 'package'], 67 | help=__doc__, 68 | description=__doc__, 69 | ) 70 | 71 | parser.add_argument( 72 | '--update', 73 | help='update packages, install or remove the packages by your settings in menuconfig', 74 | action='store_true', 75 | default=False, 76 | dest='package_update', 77 | ) 78 | 79 | parser.add_argument( 80 | '--update-force', 81 | '--force-update', 82 | help='forcely update and clean packages, install or remove packages by settings in menuconfig', 83 | action='store_true', 84 | default=False, 85 | dest='package_update_force', 86 | ) 87 | 88 | parser.add_argument( 89 | '--list', 90 | help='list target packages', 91 | action='store_true', 92 | default=False, 93 | dest='list_packages', 94 | ) 95 | 96 | parser.add_argument( 97 | '--wizard', 98 | help='create a new package with wizard', 99 | action='store_true', 100 | default=False, 101 | dest='package_create', 102 | ) 103 | 104 | parser.add_argument( 105 | '--upgrade', 106 | help='upgrade local packages index from git repository', 107 | action='store_true', 108 | default=False, 109 | dest='package_upgrade', 110 | ) 111 | 112 | parser.add_argument( 113 | '--upgrade-force', 114 | '--force-upgrade', 115 | help='forcely upgrade local packages index from git repository', 116 | action='store_true', 117 | default=False, 118 | dest='package_upgrade_force', 119 | ) 120 | 121 | parser.add_argument( 122 | '--upgrade-script-force', 123 | help='forcely upgrade local packages index and Env script from git repository', 124 | action='store_true', 125 | default=False, 126 | dest='package_upgrade_script_force', 127 | ) 128 | 129 | parser.add_argument( 130 | '--upgrade-modules', 131 | help='upgrade python modules, e.g. requests module', 132 | action='store_true', 133 | default=False, 134 | dest='package_upgrade_modules', 135 | ) 136 | 137 | parser.add_argument( 138 | '--printenv', 139 | help='print environmental variables to check', 140 | action='store_true', 141 | default=False, 142 | dest='package_print_env', 143 | ) 144 | 145 | parser.set_defaults(func=run_env_cmd) 146 | -------------------------------------------------------------------------------- /cmds/cmd_package/cmd_package_list.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | # 3 | # File : cmd_package.py 4 | # This file is part of RT-Thread RTOS 5 | # COPYRIGHT (C) 2006 - 2020, RT-Thread Development Team 6 | # 7 | # This program is free software; you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation; either version 2 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # This program is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License along 18 | # with this program; if not, write to the Free Software Foundation, Inc., 19 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 20 | # 21 | # Change Logs: 22 | # Date Author Notes 23 | # 2020-04-08 SummerGift Optimize program structure 24 | # 25 | 26 | import os 27 | import platform 28 | import kconfig 29 | from package import PackageOperation 30 | from vars import Import 31 | 32 | 33 | def get_packages(): 34 | """Get the packages list in env. 35 | 36 | Read the.config file in the BSP directory, 37 | and return the version number of the selected package. 38 | """ 39 | 40 | config_file = '.config' 41 | pkgs_root = Import('pkgs_root') 42 | packages = [] 43 | if not os.path.isfile(config_file): 44 | print( 45 | "\033[1;31;40mWarning: Can't find .config.\033[0m" 46 | '\033[1;31;40mYou should use command to config bsp first.\033[0m' 47 | ) 48 | 49 | return packages 50 | 51 | packages = kconfig.parse(config_file) 52 | 53 | for pkg in packages: 54 | pkg_path = pkg['path'] 55 | if pkg_path[0] == '/' or pkg_path[0] == '\\': 56 | pkg_path = pkg_path[1:] 57 | 58 | # parse package to get information 59 | package = PackageOperation() 60 | pkg_path = os.path.join(pkgs_root, pkg_path, 'package.json') 61 | package.parse(pkg_path) 62 | 63 | # update package name 64 | package_name_in_json = package.get_name() 65 | pkg['name'] = package_name_in_json 66 | 67 | return packages 68 | 69 | 70 | def list_packages(): 71 | """Print the packages list in env. 72 | 73 | Read the.config file in the BSP directory, 74 | and list the version number of the selected package. 75 | """ 76 | 77 | config_file = '.config' 78 | pkgs_root = Import('pkgs_root') 79 | 80 | if not os.path.isfile(config_file): 81 | if platform.system() == "Windows": 82 | os.system('chcp 65001 > nul') 83 | 84 | print("\033[1;31;40mWarning: Can't find .config.\033[0m") 85 | print('\033[1;31;40mYou should use command to config bsp first.\033[0m') 86 | 87 | if platform.system() == "Windows": 88 | os.system('chcp 437 > nul') 89 | 90 | return 91 | 92 | packages = kconfig.parse(config_file) 93 | 94 | for pkg in packages: 95 | package = PackageOperation() 96 | pkg_path = pkg['path'] 97 | if pkg_path[0] == '/' or pkg_path[0] == '\\': 98 | pkg_path = pkg_path[1:] 99 | 100 | pkg_path = os.path.join(pkgs_root, pkg_path, 'package.json') 101 | package.parse(pkg_path) 102 | 103 | package_name_in_json = package.get_name().encode("utf-8") 104 | print("package name : %s, ver : %s " % (package_name_in_json, pkg['ver'].encode("utf-8"))) 105 | 106 | if not packages: 107 | print("Packages list is empty.") 108 | print('You can use < menuconfig > command to select online packages.') 109 | print('Then use < pkgs --update > command to install them.') 110 | return 111 | -------------------------------------------------------------------------------- /cmds/cmd_package/cmd_package_printenv.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | # 3 | # File : cmd_package.py 4 | # This file is part of RT-Thread RTOS 5 | # COPYRIGHT (C) 2006 - 2020, RT-Thread Development Team 6 | # 7 | # This program is free software; you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation; either version 2 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # This program is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License along 18 | # with this program; if not, write to the Free Software Foundation, Inc., 19 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 20 | # 21 | # Change Logs: 22 | # Date Author Notes 23 | # 2020-04-08 SummerGift Optimize program structure 24 | # 25 | 26 | import os 27 | import platform 28 | 29 | 30 | def package_print_env(): 31 | print("Here are some environmental variables.") 32 | print("If you meet some problems,please check them. Make sure the configuration is correct.") 33 | print("RTT_EXEC_PATH:%s" % (os.getenv("RTT_EXEC_PATH"))) 34 | print("RTT_CC:%s" % (os.getenv("RTT_CC"))) 35 | print("SCONS:%s" % (os.getenv("SCONS"))) 36 | print("PKGS_ROOT:%s" % (os.getenv("PKGS_ROOT"))) 37 | 38 | env_root = os.getenv('ENV_ROOT') 39 | if env_root is None: 40 | if platform.system() != 'Windows': 41 | env_root = os.path.join(os.getenv('HOME'), '.env') 42 | 43 | print("ENV_ROOT:%s" % env_root) 44 | 45 | 46 | def package_print_help(): 47 | os.system('pkgs -h') 48 | -------------------------------------------------------------------------------- /cmds/cmd_package/cmd_package_update.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | # 3 | # File : cmd_package.py 4 | # This file is part of RT-Thread RTOS 5 | # COPYRIGHT (C) 2006 - 2020, RT-Thread Development Team 6 | # 7 | # This program is free software; you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation; either version 2 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # This program is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License along 18 | # with this program; if not, write to the Free Software Foundation, Inc., 19 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 20 | # 21 | # Change Logs: 22 | # Date Author Notes 23 | # 2020-04-08 SummerGift Optimize program structure 24 | # 2020-04-13 SummerGift refactoring 25 | # 26 | 27 | import json 28 | import logging 29 | import os 30 | import platform 31 | import shutil 32 | import time 33 | 34 | import requests 35 | 36 | import archive 37 | import kconfig 38 | import pkgsdb 39 | from package import PackageOperation, Bridge_SConscript 40 | from vars import Import, Export 41 | from .cmd_package_utils import get_url_from_mirror_server, execute_command, git_pull_repo, user_input, find_bool_macro_in_config 42 | 43 | 44 | def determine_support_chinese(env_root): 45 | get_flag_file_path = os.path.join(env_root, 'tools', 'bin', 'env_above_ver_1_1') 46 | if os.path.isfile(get_flag_file_path): 47 | return True 48 | else: 49 | return False 50 | 51 | 52 | def get_mirror_giturl(submodule_name): 53 | """Gets the submodule's url on mirror server. 54 | 55 | Retrurn the download address of the submodule on the mirror server from the submod_name. 56 | """ 57 | 58 | mirror_url = 'https://gitee.com/RT-Thread-Mirror/submod_' + submodule_name + '.git' 59 | return mirror_url 60 | 61 | 62 | def get_esp_mirror_giturl(submodule_name): 63 | if submodule_name == "cexception": 64 | submodule_name = "CException" 65 | elif submodule_name == "unity": 66 | submodule_name = "Unity" 67 | mirror_url = 'https://gitee.com/esp-submodules/' + submodule_name + '.git' 68 | return mirror_url 69 | 70 | 71 | def modify_submod_file_to_mirror(gitmodule_path, use_esp_mirror): 72 | """Modify the.gitmodules file based on the submodule to be updated""" 73 | 74 | replace_list = [] 75 | try: 76 | with open(gitmodule_path, 'r') as f: 77 | line = f.readline() 78 | while line: 79 | line = line.replace('\t', '').replace(' ', '').replace('\n', '').replace('\r', '') 80 | if line.startswith('path'): 81 | submodule_path = line.split("=")[1] 82 | line = f.readline() 83 | line = line.replace('\t', '').replace(' ', '').replace('\n', '').replace('\r', '') 84 | if line.startswith('url'): 85 | submodule_git_url = line.split('=')[1] 86 | submodule_name = submodule_git_url.split('/')[-1].replace('.git', '') 87 | if not use_esp_mirror: 88 | query_submodule_name = 'submod_' + submodule_name 89 | get_package_url, get_ver_sha = get_url_from_mirror_server(query_submodule_name, 'latest') 90 | else: 91 | get_package_url = get_esp_mirror_giturl(submodule_name) 92 | 93 | if get_package_url is not None and determine_url_valid(get_package_url): 94 | replace_list.append((submodule_git_url, get_package_url, submodule_name, submodule_path)) 95 | line = f.readline() 96 | 97 | with open(gitmodule_path, 'r+') as f: 98 | submod_file_count = f.read() 99 | 100 | write_content = submod_file_count 101 | 102 | for item in replace_list: 103 | write_content = write_content.replace(item[0], item[1]) 104 | 105 | with open(gitmodule_path, 'w') as f: 106 | f.write(str(write_content)) 107 | 108 | return replace_list 109 | 110 | except Exception as e: 111 | logging.warning('Error message:%s\t' % e) 112 | 113 | 114 | def determine_url_valid(url_from_srv): 115 | headers = { 116 | 'Connection': 'keep-alive', 117 | 'Accept-Encoding': 'gzip, deflate', 118 | 'Accept': '*/*', 119 | 'User-Agent': 'curl/7.54.0', 120 | } 121 | 122 | # noinspection PyBroadException 123 | try: 124 | for i in range(0, 3): 125 | r = requests.get(url_from_srv, stream=True, headers=headers) 126 | if r.status_code == requests.codes.not_found: 127 | if i == 2: 128 | print("Warning : %s is invalid." % url_from_srv) 129 | return False 130 | time.sleep(1) 131 | else: 132 | break 133 | 134 | return True 135 | 136 | except Exception as e: 137 | # So much error message should be ignore 138 | logging.error('Network connection error or the url : %s is invalid.\n' % url_from_srv.encode("utf-8")) 139 | 140 | 141 | def is_user_mange_package(bsp_package_path, pkg): 142 | for root, dirs, files in os.walk(bsp_package_path, topdown=True): 143 | for name in dirs: 144 | package_name_lower = pkg["name"].lower() 145 | folder_name_lower = name.lower() 146 | folder_name_common = folder_name_lower.replace("-", "_") 147 | if folder_name_lower == package_name_lower or folder_name_common == package_name_lower: 148 | return True 149 | break 150 | return False 151 | 152 | 153 | is_China_ip = None 154 | 155 | 156 | def need_using_mirror_download(): 157 | global is_China_ip 158 | 159 | if is_China_ip != None: 160 | return is_China_ip 161 | 162 | server_decision = "" 163 | config_file = os.path.join(Import('env_root'), 'tools', 'scripts', 'cmds', '.config') 164 | if os.path.isfile(config_file) and find_bool_macro_in_config(config_file, 'SYS_DOWNLOAD_SERVER_GITHUB'): 165 | is_China_ip = False # Github which means not China IP 166 | server_decision = "manually decision" 167 | elif os.path.isfile(config_file) and find_bool_macro_in_config(config_file, 'SYS_DOWNLOAD_SERVER_GITEE'): 168 | is_China_ip = True # Gitee which means China IP 169 | server_decision = "manually decision" 170 | else: 171 | try: 172 | ip = requests.get('https://ifconfig.me/ip').content.decode() 173 | url = 'http://www.ip-api.com/json/' + ip 174 | if requests.get(url).json()['country'] == 'China': 175 | is_China_ip = True 176 | else: 177 | is_China_ip = False 178 | server_decision = "auto decision based on IP location" 179 | except: 180 | if (-time.timezone) / 3600 == 8: 181 | is_China_ip = True 182 | else: 183 | is_China_ip = False 184 | server_decision = "auto decision based on timezone" 185 | 186 | print("[Use {} server - {}]".format(("Gitee" if is_China_ip else "Github"), server_decision)) 187 | return is_China_ip 188 | 189 | 190 | def is_git_url(package_url): 191 | return package_url.endswith('.git') 192 | 193 | 194 | def update_submodule(repo_path, use_esp_mirror): 195 | print(repo_path) 196 | # If there is a .gitmodules file in the package, prepare to update submodule. 197 | gitmodules_path = os.path.join(repo_path, '.gitmodules') 198 | if os.path.isfile(gitmodules_path): 199 | if need_using_mirror_download(): 200 | replace_list = modify_submod_file_to_mirror(gitmodules_path, use_esp_mirror) 201 | cmd = 'git submodule update --init' 202 | execute_command(cmd, cwd=repo_path) 203 | for item in replace_list: 204 | submodule_path = os.path.join(repo_path, item[3]) 205 | print(submodule_path) 206 | if os.path.isdir(submodule_path): 207 | update_submodule(submodule_path, use_esp_mirror) 208 | cmd = 'git checkout .gitmodules' 209 | execute_command(cmd, cwd=repo_path) 210 | cmd = 'git submodule sync' 211 | execute_command(cmd, cwd=repo_path) 212 | else: 213 | cmd = 'git submodule update --init --recursive' 214 | execute_command(cmd, cwd=repo_path) 215 | 216 | 217 | def install_git_package(bsp_package_path, package_name, package_info, package_url, ver_sha, upstream_changed, url_origin): 218 | try: 219 | repo_path = os.path.join(bsp_package_path, package_name) 220 | repo_path = repo_path + '-' + package_info['ver'] 221 | repo_name_with_version = '"' + repo_path + '"' 222 | 223 | clone_cmd = 'git clone ' + package_url + ' ' + repo_name_with_version 224 | logging.info(clone_cmd) 225 | execute_command(clone_cmd, cwd=bsp_package_path) 226 | 227 | git_check_cmd = ( 228 | 'git remote set-branches origin ' + ver_sha + ';git fetch --depth 1 origin ' + ver_sha + ';git checkout -q ' + ver_sha 229 | ) 230 | execute_command(git_check_cmd, cwd=repo_path) 231 | except Exception as e: 232 | print('Error message:%s' % e) 233 | print("\nFailed to download software package with git. Please check the network connection.") 234 | return False 235 | 236 | # change upstream to origin url 237 | if upstream_changed: 238 | cmd = 'git remote set-url origin ' + url_origin 239 | execute_command(cmd, cwd=repo_path) 240 | 241 | # If there is a .gitmodules file in the package, prepare to update submodule. 242 | gitmodules_path = os.path.join(repo_path, '.gitmodules') 243 | if os.path.isfile(gitmodules_path): 244 | print("Start to update submodule") 245 | update_submodule(repo_path, package_name == u"ESP-IDF") 246 | 247 | return True 248 | 249 | 250 | def install_not_git_package(package, package_info, local_pkgs_path, package_url, bsp_package_path, package_name): 251 | result = True 252 | # Download a package of compressed package type. 253 | if not package.download(package_info['ver'], local_pkgs_path, package_url): 254 | return False 255 | 256 | pkg_dir = package.get_filename(package_info['ver']) 257 | pkg_dir = os.path.splitext(pkg_dir)[0] 258 | package_path = os.path.join(local_pkgs_path, package.get_filename(package_info['ver'])) 259 | 260 | if not archive.package_integrity_test(package_path): 261 | print("package : %s is invalid" % package_path.encode("utf-8")) 262 | return False 263 | 264 | # unpack package 265 | if not os.path.exists(pkg_dir): 266 | try: 267 | if not archive.unpack(package_path, bsp_package_path, package_info, package_name): 268 | result = False 269 | except Exception as e: 270 | result = False 271 | logging.error('Error message: {0}'.format(e)) 272 | else: 273 | print("The file does not exist.") 274 | 275 | return result 276 | 277 | 278 | # noinspection PyUnboundLocalVariable 279 | def install_package(env_root, pkgs_root, bsp_root, package_info, force_update): 280 | """Install the required packages.""" 281 | 282 | result = True 283 | local_pkgs_path = os.path.join(env_root, 'local_pkgs') 284 | bsp_package_path = os.path.join(bsp_root, 'packages') 285 | 286 | if not force_update: 287 | logging.info("Begin to check if it's an user managed package {0}, {1} \n".format(bsp_package_path, package_info)) 288 | if is_user_mange_package(bsp_package_path, package_info): 289 | logging.info("User managed package {0}, {1} no need install. \n".format(bsp_package_path, package_info)) 290 | return result 291 | else: 292 | logging.info("NOT User managed package {0}, {1} need install. \n".format(bsp_package_path, package_info)) 293 | 294 | package = PackageOperation() 295 | pkg_path = package_info['path'] 296 | if pkg_path[0] == '/' or pkg_path[0] == '\\': 297 | pkg_path = pkg_path[1:] 298 | pkg_path = os.path.join(pkgs_root, pkg_path, 'package.json') 299 | package.parse(pkg_path) 300 | 301 | try: 302 | url_from_json = package.get_url(package_info['ver']) 303 | except: 304 | print( 305 | "Warning: cannot find the corresponding version. Please check {}'s Kconfig file".format( 306 | package_info['name'].capitalize() 307 | ) 308 | ) 309 | return False 310 | 311 | if not url_from_json: 312 | return False 313 | 314 | package_url = url_from_json 315 | 316 | pkgs_name_in_json = package.get_name() 317 | logging.info("begin to install packages: {0}".format(pkgs_name_in_json)) 318 | if is_git_url(package_url): 319 | ver_sha = package.get_versha(package_info['ver']) 320 | 321 | upstream_changed = False 322 | 323 | # noinspection PyBroadException 324 | try: 325 | if need_using_mirror_download(): 326 | get_package_url, get_ver_sha = get_url_from_mirror_server(pkgs_name_in_json, package_info['ver']) 327 | 328 | # Check whether the package package url is valid 329 | if get_package_url and determine_url_valid(get_package_url): 330 | package_url = get_package_url 331 | 332 | if get_ver_sha: 333 | ver_sha = get_ver_sha 334 | 335 | upstream_changed = True 336 | except Exception as e: 337 | logging.warning("Failed to connect to the mirror server, package will be downloaded from non-mirror server.\n") 338 | 339 | if is_git_url(package_url): 340 | if not install_git_package( 341 | bsp_package_path, pkgs_name_in_json, package_info, package_url, ver_sha, upstream_changed, url_from_json 342 | ): 343 | result = False 344 | else: 345 | if not install_not_git_package( 346 | package, package_info, local_pkgs_path, package_url, bsp_package_path, pkgs_name_in_json 347 | ): 348 | result = False 349 | return result 350 | 351 | 352 | def sub_list(aList, bList): 353 | """Return the items in aList but not in bList.""" 354 | 355 | tmp = [] 356 | for a in aList: 357 | if a not in bList: 358 | tmp.append(a) 359 | return tmp 360 | 361 | 362 | def and_list(aList, bList): 363 | """Return the items in aList and in bList.""" 364 | 365 | tmp = [] 366 | for a in aList: 367 | if a in bList: 368 | tmp.append(a) 369 | return tmp 370 | 371 | 372 | def get_package_folder(origin_path, version): 373 | return origin_path + '-' + version 374 | 375 | 376 | def git_cmd_exec(cmd, cwd): 377 | try: 378 | execute_command(cmd, cwd=cwd) 379 | except Exception as e: 380 | logging.warning('Error message:%s%s. %s \n\t' % (cwd.encode("utf-8"), " path doesn't exist", e)) 381 | print("You can solve this problem by manually removing old packages and re-downloading them using env.") 382 | 383 | 384 | def update_latest_packages(sys_value): 385 | """update the packages that are latest version. 386 | 387 | If the selected package is the latest version, 388 | check to see if it is the latest version after the update command, 389 | if not, then update the latest version from the remote repository. 390 | If the download has a conflict, you are currently using the prompt 391 | message provided by git. 392 | """ 393 | 394 | logging.info("Begin to update latest version packages") 395 | 396 | result = True 397 | 398 | package_filename = sys_value[3] 399 | bsp_packages_path = sys_value[5] 400 | 401 | env_root = Import('env_root') 402 | pkgs_root = Import('pkgs_root') 403 | 404 | with open(package_filename, 'r') as f: 405 | read_back_pkgs_json = json.load(f) 406 | 407 | for pkg in read_back_pkgs_json: 408 | right_path_flag = True 409 | package = PackageOperation() 410 | pkg_path = pkg['path'] 411 | if pkg_path[0] == '/' or pkg_path[0] == '\\': 412 | pkg_path = pkg_path[1:] 413 | 414 | pkg_path = os.path.join(pkgs_root, pkg_path, 'package.json') 415 | package.parse(pkg_path) 416 | pkgs_name_in_json = package.get_name() 417 | 418 | # Find out the packages which version is 'latest' 419 | if pkg['ver'] == "latest_version" or pkg['ver'] == "latest": 420 | repo_path = os.path.join(bsp_packages_path, pkgs_name_in_json) 421 | repo_path = get_package_folder(repo_path, pkg['ver']) 422 | 423 | # noinspection PyBroadException 424 | try: 425 | # If mirror acceleration is enabled, get the update address from the mirror server. 426 | if need_using_mirror_download(): 427 | payload_pkgs_name_in_json = pkgs_name_in_json.encode("utf-8") 428 | 429 | # Change repo's upstream address. 430 | mirror_url = get_url_from_mirror_server(payload_pkgs_name_in_json, pkg['ver']) 431 | 432 | # if git root is same as repo path, then change the upstream 433 | get_git_root = get_git_root_path(repo_path) 434 | if get_git_root: 435 | if os.path.normcase(repo_path) == os.path.normcase(get_git_root): 436 | if mirror_url[0] is not None: 437 | cmd = 'git remote set-url origin ' + mirror_url[0] 438 | git_cmd_exec(cmd, repo_path) 439 | else: 440 | print("\n==============================> updating") 441 | print("Package path: %s" % repo_path) 442 | print("Git root: %s" % get_git_root) 443 | print("Error: Not currently in a git root directory, cannot switch upstream.\n") 444 | right_path_flag = False 445 | result = False 446 | else: 447 | right_path_flag = False 448 | result = False 449 | 450 | except Exception as e: 451 | logging.warning("Failed to connect to the mirror server, using non-mirror server to update.") 452 | 453 | if not right_path_flag: 454 | continue 455 | 456 | # Update the package repository from upstream. 457 | git_pull_repo(repo_path) 458 | 459 | # If the package has submodules, update the submodules. 460 | update_submodule(repo_path, pkgs_name_in_json == u"ESP-IDF") 461 | 462 | # recover origin url to the path which get from packages.json file 463 | if package.get_url(pkg['ver']): 464 | cmd = 'git remote set-url origin ' + package.get_url(pkg['ver']) 465 | git_cmd_exec(cmd, repo_path) 466 | else: 467 | print("Can't find the package : %s's url in file : %s" % (payload_pkgs_name_in_json, pkg_path)) 468 | 469 | print("==============================> %s update done\n" % pkgs_name_in_json) 470 | 471 | return result 472 | 473 | 474 | def get_git_root_path(repo_path): 475 | if os.path.isdir(repo_path): 476 | try: 477 | before = os.getcwd() 478 | os.chdir(repo_path) 479 | result = os.popen("git rev-parse --show-toplevel") 480 | result = result.read() 481 | for line in result.splitlines()[:5]: 482 | get_git_root = line 483 | break 484 | os.chdir(before) 485 | return get_git_root 486 | except Exception as e: 487 | logging.warning("Error message : %s" % e) 488 | return None 489 | else: 490 | logging.warning("Missing path {0}".format(repo_path)) 491 | logging.warning("If you manage this package manually, Env tool will not update it.") 492 | return None 493 | 494 | 495 | def pre_package_update(): 496 | """Make preparations before updating the software package.""" 497 | 498 | logging.info("Begin prepare package update") 499 | bsp_root = Import('bsp_root') 500 | env_root = Import('env_root') 501 | 502 | if not os.path.exists('.config'): 503 | if platform.system() == "Windows": 504 | os.system('chcp 65001 > nul') 505 | 506 | print("\n\033[1;31;40m当前路径下没有发现 .config 文件,请确保当前目录为 BSP 根目录。\033[0m") 507 | print("\033[1;31;40m如果确定当前目录为 BSP 根目录,请先使用 命令来生成 .config 文件。\033[0m\n") 508 | 509 | print('No system configuration file : .config.') 510 | print('You should use < menuconfig > command to config bsp first.') 511 | 512 | if platform.system() == "Windows": 513 | os.system('chcp 437 > nul') 514 | 515 | return False 516 | 517 | # According to the env version, whether Chinese output is supported or not 518 | if determine_support_chinese(env_root): 519 | if platform.system() == "Windows": 520 | os.system('chcp 65001 > nul') 521 | 522 | # create packages folder 523 | bsp_packages_path = os.path.join(bsp_root, 'packages') 524 | if not os.path.exists(bsp_packages_path): 525 | os.mkdir("packages") 526 | os.chdir(bsp_packages_path) 527 | fp = open("pkgs.json", 'w') 528 | fp.write("[]") 529 | fp.close() 530 | 531 | fp = open("pkgs_error.json", 'w') 532 | fp.write("[]") 533 | fp.close() 534 | os.chdir(bsp_root) 535 | 536 | # prepare target packages file 537 | dbsqlite_pathname = os.path.join(bsp_packages_path, 'packages.dbsqlite') 538 | Export('dbsqlite_pathname') 539 | dbsqlite_pathname = dbsqlite_pathname.encode('utf-8').decode('gbk') 540 | 541 | # avoid creating tables more than one time 542 | if not os.path.isfile(dbsqlite_pathname): 543 | conn = pkgsdb.get_conn(dbsqlite_pathname) 544 | sql = '''CREATE TABLE packagefile 545 | (pathname TEXT ,package TEXT ,md5 TEXT );''' 546 | pkgsdb.create_table(conn, sql) 547 | 548 | fn = '.config' 549 | pkgs = kconfig.parse(fn) 550 | newpkgs = pkgs 551 | 552 | # regenerate file : packages/pkgs.json 553 | package_json_filename = os.path.join(bsp_packages_path, 'pkgs.json') 554 | if not os.path.exists(package_json_filename): 555 | os.chdir(bsp_packages_path) 556 | fp = open("pkgs.json", 'w') 557 | fp.write("[]") 558 | fp.close() 559 | os.chdir(bsp_root) 560 | 561 | # Reading data back from pkgs.json 562 | with open(package_json_filename, 'r') as f: 563 | oldpkgs = json.load(f) 564 | 565 | # regenerate file : packages/pkgs_error.json 566 | pkgs_error_list_fn = os.path.join(bsp_packages_path, 'pkgs_error.json') 567 | 568 | if not os.path.exists(pkgs_error_list_fn): 569 | os.chdir(bsp_packages_path) 570 | fp = open("pkgs_error.json", 'w') 571 | fp.write("[]") 572 | fp.close() 573 | os.chdir(bsp_root) 574 | 575 | # read data back from pkgs_error.json 576 | with open(pkgs_error_list_fn, 'r') as f: 577 | package_error = json.load(f) 578 | 579 | # create SConscript file 580 | if not os.path.isfile(os.path.join(bsp_packages_path, 'SConscript')): 581 | with open(os.path.join(bsp_packages_path, 'SConscript'), 'w') as f: 582 | f.write(str(Bridge_SConscript)) 583 | 584 | return [oldpkgs, newpkgs, package_error, package_json_filename, pkgs_error_list_fn, bsp_packages_path, dbsqlite_pathname] 585 | 586 | 587 | def error_packages_handle(error_packages_list, read_back_pkgs_json, package_filename, force_update): 588 | bsp_root = Import('bsp_root') 589 | env_root = Import('env_root') 590 | pkgs_root = Import('pkgs_root') 591 | download_error = [] 592 | flag = True 593 | 594 | if len(error_packages_list): 595 | print("\n==============================> Packages list to download : \n") 596 | for package in error_packages_list: 597 | print("Package name : %s, Ver : %s" % (package['name'].encode("utf-8"), package['ver'].encode("utf-8"))) 598 | print("\nThe packages in the list above are accidentally deleted or renamed.") 599 | print("\nIf you manually delete the version suffix of the package folder name, ") 600 | print("you can use command to re-download these packages.") 601 | print("In case of accidental deletion, the ENV tool will automatically re-download these packages.") 602 | 603 | # re-download the packages in error_packages_list 604 | for package in error_packages_list: 605 | if install_package(env_root, pkgs_root, bsp_root, package, force_update): 606 | print( 607 | "\n==============================> %s %s update done \n" 608 | % (package['name'].encode("utf-8"), package['ver'].encode("utf-8")) 609 | ) 610 | else: 611 | download_error.append(package) 612 | print(package, 'download failed.') 613 | flag = False 614 | 615 | if len(download_error): 616 | print("%s" % download_error) 617 | 618 | for package in download_error: 619 | print( 620 | "Packages:%s, %s re-download error, you can use command to re-download them." 621 | % (package['name'].encode("utf-8"), package['ver'].encode("utf-8")) 622 | ) 623 | 624 | error_write_back = sub_list(read_back_pkgs_json, download_error) 625 | with open(package_filename, 'w') as f: 626 | f.write(json.dumps(error_write_back, indent=1)) 627 | 628 | return flag 629 | 630 | 631 | def rm_package(dir_remove): 632 | logging.info("remove dir: {0}".format(dir_remove)) 633 | 634 | if platform.system() != "Windows": 635 | shutil.rmtree(dir_remove) 636 | else: 637 | dir_remove = '"' + dir_remove + '"' 638 | cmd = 'rd /s /q ' + dir_remove 639 | os.system(cmd) 640 | 641 | if os.path.isdir(dir_remove): 642 | if platform.system() != "Windows": 643 | shutil.rmtree(dir_remove) 644 | else: 645 | dir_remove = '"' + dir_remove + '"' 646 | cmd = 'rmdir /s /q ' + dir_remove 647 | os.system(cmd) 648 | 649 | if os.path.isdir(dir_remove): 650 | print("Folder path: %s" % dir_remove.encode("utf-8")) 651 | return False 652 | else: 653 | print("Path: %s \nSuccess: Folder has been removed. " % dir_remove.encode("utf-8")) 654 | return True 655 | 656 | 657 | def get_package_remove_path(pkg, bsp_packages_path): 658 | dir_path = pkg['path'] 659 | ver = pkg['ver'] 660 | if dir_path[0] == '/' or dir_path[0] == '\\': 661 | dir_path = dir_path[1:] 662 | 663 | if platform.system() == "Windows": 664 | dir_path = os.path.basename(dir_path.replace('/', '\\')) 665 | else: 666 | dir_path = os.path.basename(dir_path) 667 | 668 | # Handles the deletion of git repository folders with version Numbers 669 | remove_path = os.path.join(bsp_packages_path, dir_path) 670 | remove_path_ver = get_package_folder(remove_path, ver) 671 | return remove_path_ver 672 | 673 | 674 | def handle_download_error_packages(sys_value, force_update): 675 | """handle download error packages. 676 | 677 | Check to see if the packages stored in the Json file list actually exist, 678 | and then download the packages if they don't exist. 679 | """ 680 | 681 | logging.info("begin to handel download error packages") 682 | package_filename = sys_value[3] 683 | bsp_packages_path = sys_value[5] 684 | 685 | with open(package_filename, 'r') as f: 686 | package_json = json.load(f) 687 | 688 | error_packages_list = [] 689 | 690 | for pkg in package_json: 691 | remove_path = get_package_remove_path(pkg, bsp_packages_path) 692 | if os.path.exists(remove_path): 693 | continue 694 | else: 695 | print("Error package : %s" % pkg) 696 | error_packages_list.append(pkg) 697 | 698 | # Handle the failed download packages 699 | get_flag = error_packages_handle(error_packages_list, package_json, package_filename, force_update) 700 | 701 | return get_flag 702 | 703 | 704 | def delete_useless_packages(sys_value): 705 | logging.info("Begin to delete useless packages") 706 | package_delete_error_list = sys_value[2] 707 | bsp_packages_path = sys_value[5] 708 | 709 | # try to delete useless packages, exit command if fails 710 | if len(package_delete_error_list): 711 | for error_package in package_delete_error_list: 712 | remove_path_with_version = get_package_remove_path(error_package, bsp_packages_path) 713 | if os.path.isdir(remove_path_with_version): 714 | print("\nError: %s package delete failed, begin to remove it." % error_package['name'].encode("utf-8")) 715 | 716 | if not rm_package(remove_path_with_version): 717 | print( 718 | "Error: Delete package %s failed! Please delete the folder manually.\n" 719 | % error_package['name'].encode("utf-8") 720 | ) 721 | return False 722 | return True 723 | 724 | 725 | def is_git_package(pkg, bsp_packages_path): 726 | remove_path_with_version = get_package_remove_path(pkg, bsp_packages_path) 727 | remove_path_git = os.path.join(remove_path_with_version, '.git') 728 | return os.path.isdir(remove_path_with_version) and os.path.isdir(remove_path_git) 729 | 730 | 731 | def delete_git_package(pkg, remove_path_with_version, force_update, package_delete_fail_list): 732 | git_folder_to_remove = remove_path_with_version 733 | 734 | print("\nStart to remove %s \nplease wait..." % git_folder_to_remove.encode("utf-8")) 735 | if force_update: 736 | logging.info("package force update, Begin to remove package {0}".format(git_folder_to_remove)) 737 | if not rm_package(git_folder_to_remove): 738 | print("Floder delete fail: %s" % git_folder_to_remove.encode("utf-8")) 739 | print("Please delete this folder manually.") 740 | else: 741 | print("The folder is managed by git. Do you want to delete this folder?\n") 742 | rc = user_input('Press the Y Key to delete the folder or just press Enter to keep it : ') 743 | if rc == 'y' or rc == 'Y': 744 | try: 745 | if not rm_package(git_folder_to_remove): 746 | package_delete_fail_list.append(pkg) 747 | print("Error: Please delete the folder manually.") 748 | except Exception as e: 749 | logging.warning( 750 | 'Error message:%s%s. error.message: %s\n\t' 751 | % ("Delete folder failed: ", git_folder_to_remove.encode("utf-8"), e) 752 | ) 753 | 754 | 755 | def delete_zip_package(pkg, remove_path_with_version, force_update, package_delete_fail_list, sqlite_pathname): 756 | if os.path.isdir(remove_path_with_version): 757 | print("Start to remove %s \nplease wait..." % remove_path_with_version.encode("utf-8")) 758 | if force_update: 759 | logging.info("package force update, Begin to remove package {0}".format(remove_path_with_version)) 760 | if not rm_package(remove_path_with_version): 761 | print("Floder delete fail: %s" % remove_path_with_version.encode("utf-8")) 762 | print("Please delete this folder manually.") 763 | else: 764 | try: 765 | pkgsdb.deletepackdir(remove_path_with_version, sqlite_pathname) 766 | except Exception as e: 767 | package_delete_fail_list.append(pkg) 768 | logging.warning( 769 | 'Error message:\n%s %s. %s \n\t' 770 | % ("Delete folder failed, please delete the folder manually", remove_path_with_version.encode("utf-8"), e) 771 | ) 772 | 773 | 774 | def remove_packages(sys_value, force_update): 775 | logging.info("Begin to remove packages") 776 | old_package = sys_value[0] 777 | new_package = sys_value[1] 778 | package_error_list_filename = sys_value[4] 779 | bsp_packages_path = sys_value[5] 780 | sqlite_pathname = sys_value[6] 781 | 782 | case_delete = sub_list(old_package, new_package) 783 | package_delete_fail_list = [] 784 | 785 | for pkg in case_delete: 786 | remove_path_with_version = get_package_remove_path(pkg, bsp_packages_path) 787 | 788 | # delete .git directory 789 | if is_git_package(pkg, bsp_packages_path): 790 | delete_git_package(pkg, remove_path_with_version, force_update, package_delete_fail_list) 791 | else: 792 | delete_zip_package(pkg, remove_path_with_version, force_update, package_delete_fail_list, sqlite_pathname) 793 | 794 | # write error messages 795 | with open(package_error_list_filename, 'w') as f: 796 | f.write(str(json.dumps(package_delete_fail_list, indent=1))) 797 | 798 | if len(package_delete_fail_list): 799 | return False 800 | 801 | return True 802 | 803 | 804 | def install_packages(sys_value, force_update): 805 | """ 806 | If the package download fails, record it, 807 | and then download again when the update command is executed. 808 | """ 809 | 810 | logging.info("Begin to install packages") 811 | 812 | old_package = sys_value[0] 813 | new_package = sys_value[1] 814 | 815 | logging.info("old_package {0}".format(old_package)) 816 | logging.info("new_package {0}".format(new_package)) 817 | 818 | package_filename = sys_value[3] 819 | bsp_root = Import('bsp_root') 820 | pkgs_root = Import('pkgs_root') 821 | env_root = Import('env_root') 822 | 823 | case_download = sub_list(new_package, old_package) 824 | packages_download_fail_list = [] 825 | 826 | for package in case_download: 827 | if install_package(env_root, pkgs_root, bsp_root, package, force_update): 828 | print("==============================> %s %s is downloaded successfully. \n" % (package['name'], package['ver'])) 829 | else: 830 | # if package download fails, record it in the packages_download_fail_list 831 | packages_download_fail_list.append(package) 832 | print(package, 'download failed.') 833 | return False 834 | 835 | # Get the currently updated configuration. 836 | new_package = sub_list(new_package, packages_download_fail_list) 837 | 838 | # Give hints based on the success of the download. 839 | if len(packages_download_fail_list): 840 | print("\nPackage download failed list:") 841 | for item in packages_download_fail_list: 842 | print(item) 843 | 844 | print("You need to reuse the command to download again.") 845 | 846 | # Update pkgs.json and SConscript 847 | with open(package_filename, 'w') as f: 848 | f.write(str(json.dumps(new_package, indent=1))) 849 | 850 | return True 851 | 852 | 853 | def package_update(force_update=False): 854 | """Update env's packages. 855 | 856 | Compare the old and new software package list and update the package. 857 | Remove unwanted packages and download the newly selected package.- 858 | Check if the files in the deleted packages have been changed, and if so, 859 | remind the user saved the modified file. 860 | """ 861 | 862 | sys_value = pre_package_update() 863 | if not sys_value: 864 | return 865 | 866 | flag = True 867 | 868 | if not delete_useless_packages(sys_value): 869 | return 870 | 871 | # 1.in old and not in new : Software packages that need to be removed 872 | if not remove_packages(sys_value, force_update): 873 | return 874 | 875 | # 2.in new not in old : Software packages to be installed. 876 | if not install_packages(sys_value, force_update): 877 | flag = False 878 | 879 | # 3.handle download error packages. 880 | if not handle_download_error_packages(sys_value, force_update): 881 | flag = False 882 | 883 | # 4.update the software packages, which the version is 'latest' 884 | if not update_latest_packages(sys_value): 885 | flag = False 886 | 887 | if flag: 888 | print("Operation completed successfully.") 889 | else: 890 | print("Operation failed.") 891 | -------------------------------------------------------------------------------- /cmds/cmd_package/cmd_package_upgrade.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | # 3 | # File : cmd_package.py 4 | # This file is part of RT-Thread RTOS 5 | # COPYRIGHT (C) 2006 - 2020, RT-Thread Development Team 6 | # 7 | # This program is free software; you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation; either version 2 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # This program is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License along 18 | # with this program; if not, write to the Free Software Foundation, Inc., 19 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 20 | # 21 | # Change Logs: 22 | # Date Author Notes 23 | # 2020-04-08 SummerGift Optimize program structure 24 | # 25 | 26 | import os 27 | import uuid 28 | from vars import Import 29 | from .cmd_package_utils import git_pull_repo, get_url_from_mirror_server, find_bool_macro_in_config 30 | from .cmd_package_update import need_using_mirror_download 31 | 32 | try: 33 | import requests 34 | except ImportError: 35 | print( 36 | "****************************************\n" 37 | "* Import requests module error.\n" 38 | "* Please install requests module first.\n" 39 | "* pip install step:\n" 40 | "* $ pip install requests\n" 41 | "* command install step:\n" 42 | "* $ sudo apt-get install python-requests\n" 43 | "****************************************\n" 44 | ) 45 | 46 | 47 | def upgrade_packages_index(force_upgrade=False): 48 | """Update the package repository index.""" 49 | 50 | pkgs_root = Import('pkgs_root') 51 | 52 | if need_using_mirror_download(): 53 | get_package_url, get_ver_sha = get_url_from_mirror_server('packages', 'latest') 54 | 55 | if get_package_url is not None: 56 | git_repo = get_package_url 57 | else: 58 | print("Failed to get url from mirror server. Using default url.") 59 | git_repo = 'https://gitee.com/RT-Thread-Mirror/packages.git' 60 | else: 61 | git_repo = 'https://github.com/RT-Thread/packages.git' 62 | 63 | packages_root = pkgs_root 64 | pkgs_path = os.path.join(packages_root, 'packages') 65 | 66 | if not os.path.isdir(pkgs_path): 67 | cmd = 'git clone ' + git_repo + ' ' + pkgs_path + ' --depth=1' 68 | os.system(cmd) 69 | print("upgrade from :%s" % (git_repo.encode("utf-8"))) 70 | else: 71 | if force_upgrade: 72 | cwd = os.getcwd() 73 | os.chdir(pkgs_path) 74 | os.system('git fetch --all') 75 | os.system('git reset --hard origin/master') 76 | os.chdir(cwd) 77 | print("Begin to upgrade env packages.") 78 | git_pull_repo(pkgs_path, git_repo) 79 | print("==============================> Env packages upgrade done \n") 80 | 81 | for filename in os.listdir(packages_root): 82 | package_path = os.path.join(packages_root, filename) 83 | if os.path.isdir(package_path): 84 | 85 | if package_path == pkgs_path: 86 | continue 87 | 88 | if os.path.isdir(os.path.join(package_path, '.git')): 89 | print("Begin to upgrade %s." % filename) 90 | if force_upgrade: 91 | cwd = os.getcwd() 92 | os.chdir(package_path) 93 | os.system('git fetch --all') 94 | os.system('git reset --hard origin/master') 95 | os.chdir(cwd) 96 | git_pull_repo(package_path) 97 | print("==============================> Env %s update done \n" % filename) 98 | 99 | 100 | def upgrade_env_script(force_upgrade=False): 101 | """Update env function scripts.""" 102 | 103 | env_root = Import('env_root') 104 | 105 | if need_using_mirror_download(): 106 | get_package_url, get_ver_sha = get_url_from_mirror_server('env', 'latest') 107 | 108 | if get_package_url is not None: 109 | env_scripts_repo = get_package_url 110 | else: 111 | print("Failed to get url from mirror server. Using default url.") 112 | env_scripts_repo = 'https://gitee.com/RT-Thread-Mirror/env.git' 113 | else: 114 | env_scripts_repo = 'https://github.com/RT-Thread/env.git' 115 | 116 | env_scripts_root = os.path.join(env_root, 'tools', 'scripts') 117 | if force_upgrade: 118 | cwd = os.getcwd() 119 | os.chdir(env_scripts_root) 120 | os.system('git fetch --all') 121 | os.system('git reset --hard origin/master') 122 | os.chdir(cwd) 123 | print("Begin to upgrade env scripts.") 124 | git_pull_repo(env_scripts_root, env_scripts_repo) 125 | print("==============================> Env scripts upgrade done \n") 126 | 127 | 128 | def get_mac_address(): 129 | mac = uuid.UUID(int=uuid.getnode()).hex[-12:] 130 | return ":".join([mac[e : e + 2] for e in range(0, 11, 2)]) 131 | 132 | 133 | def Information_statistics(): 134 | env_root = Import('env_root') 135 | # get the .config file from env 136 | env_kconfig_path = os.path.join(env_root, 'tools', 'scripts', 'cmds') 137 | env_config_file = os.path.join(env_kconfig_path, '.config') 138 | 139 | if find_bool_macro_in_config(env_config_file, 'SYS_PKGS_USING_STATISTICS'): 140 | mac_addr = get_mac_address() 141 | response = requests.get( 142 | 'https://www.rt-thread.org/studio/statistics/api/envuse?userid=' 143 | + str(mac_addr) 144 | + '&username=' 145 | + str(mac_addr) 146 | + '&envversion=1.0&studioversion=2.0&ip=127.0.0.1' 147 | ) 148 | if response.status_code != 200: 149 | return 150 | else: 151 | return 152 | 153 | 154 | def package_upgrade(force_upgrade=False, upgrade_script=False): 155 | """Update the package repository directory and env function scripts.""" 156 | 157 | if os.environ.get('RTTS_PLATFROM') != 'STUDIO': # not used in studio 158 | Information_statistics() 159 | 160 | upgrade_packages_index(force_upgrade=force_upgrade) 161 | 162 | if upgrade_script: 163 | upgrade_env_script(force_upgrade=force_upgrade) 164 | 165 | 166 | # upgrade python modules 167 | def package_upgrade_modules(): 168 | try: 169 | from subprocess import call 170 | 171 | call('python -m pip install --upgrade pip', shell=True) 172 | 173 | import pip 174 | from pip._internal.utils.misc import get_installed_distributions 175 | 176 | for dist in get_installed_distributions(): 177 | call('python -m pip install --upgrade ' + dist.project_name, shell=True) 178 | except: 179 | print('Fail to upgrade python modules!') 180 | -------------------------------------------------------------------------------- /cmds/cmd_package/cmd_package_utils.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | # 3 | # File : cmd_package.py 4 | # This file is part of RT-Thread RTOS 5 | # COPYRIGHT (C) 2006 - 2020, RT-Thread Development Team 6 | # 7 | # This program is free software; you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation; either version 2 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # This program is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License along 18 | # with this program; if not, write to the Free Software Foundation, Inc., 19 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 20 | # 21 | # Change Logs: 22 | # Date Author Notes 23 | # 2020-04-08 SummerGift Optimize program structure 24 | # 25 | 26 | import json 27 | import os 28 | import platform 29 | import subprocess 30 | import sys 31 | import time 32 | import shutil 33 | import requests 34 | import logging 35 | from vars import Import 36 | 37 | 38 | def execute_command(cmd_string, cwd=None, shell=True): 39 | """Execute the system command at the specified address.""" 40 | 41 | sub = subprocess.Popen(cmd_string, cwd=cwd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, shell=shell, bufsize=4096) 42 | 43 | stdout_str = '' 44 | while sub.poll() is None: 45 | stdout_str += str(sub.stdout.read()) 46 | time.sleep(0.1) 47 | 48 | return stdout_str 49 | 50 | 51 | def is_windows(): 52 | if platform.system() == "Windows": 53 | return True 54 | else: 55 | return False 56 | 57 | 58 | def git_pull_repo(repo_path, repo_url=''): 59 | try: 60 | if is_windows(): 61 | cmd = r'git config --local core.autocrlf true' 62 | execute_command(cmd, cwd=repo_path) 63 | cmd = r'git pull ' + repo_url 64 | execute_command(cmd, cwd=repo_path) 65 | except Exception as e: 66 | print('Error message:%s' % e) 67 | 68 | 69 | def get_url_from_mirror_server(package_name, package_version): 70 | """Get the download address from the mirror server based on the package name.""" 71 | 72 | try: 73 | if type(package_name) == bytes: 74 | if sys.version_info < (3, 0): 75 | package_name = str(package_name) 76 | else: 77 | package_name = str(package_name, encoding='utf-8') 78 | except Exception as e: 79 | print('Error message:%s' % e) 80 | print("\nThe mirror server could not be contacted. Please check your network connection.") 81 | return None, None 82 | 83 | payload = { 84 | "userName": "RT-Thread", 85 | "packages": [ 86 | { 87 | "name": "NULL", 88 | } 89 | ], 90 | } 91 | payload["packages"][0]['name'] = package_name 92 | 93 | try: 94 | r = requests.post("https://api.rt-thread.org/packages/queries", data=json.dumps(payload)) 95 | 96 | if r.status_code == requests.codes.ok: 97 | package_info = json.loads(r.text) 98 | 99 | # Can't find package,change git package SHA if it's a git 100 | # package 101 | if len(package_info['packages']) == 0: 102 | print("Package was NOT found on mirror server. Using a non-mirrored address to download.") 103 | return None, None 104 | else: 105 | for item in package_info['packages'][0]['packages_info']['site']: 106 | if item['version'] == package_version: 107 | # Change download url 108 | download_url = item['URL'] 109 | if download_url[-4:] == '.git': 110 | # Change git package SHA 111 | repo_sha = item['VER_SHA'] 112 | return download_url, repo_sha 113 | return download_url, None 114 | 115 | print("\nTips : \nThe system needs to be upgraded.") 116 | print("Please use the command to upgrade packages index.\n") 117 | return None, None 118 | 119 | except Exception as e: 120 | print('Error message:%s' % e) 121 | print("\nThe mirror server could not be contacted. Please check your network connection.") 122 | return None, None 123 | 124 | 125 | def user_input(msg=None): 126 | """Gets the union keyboard input.""" 127 | 128 | if sys.version_info < (3, 0): 129 | if msg is not None: 130 | value = raw_input(msg) 131 | else: 132 | value = raw_input() 133 | else: 134 | if msg is not None: 135 | value = input(msg) 136 | else: 137 | value = input() 138 | 139 | return value 140 | 141 | 142 | # Find the string after '=' 143 | # e.g CONFIG_SYS_AUTO_UPDATE_PKGS=y 144 | # this function will return True and 'y' 145 | # True means this macro has been set and y is the string after '=' 146 | def find_string_in_config(filename, macro_name): 147 | try: 148 | config = open(filename, "r") 149 | except Exception as e: 150 | print('Error message:%s' % e) 151 | print('open .config failed') 152 | return (False, None) 153 | 154 | empty_line = 1 155 | 156 | for line in config: 157 | line = line.lstrip(' ').replace('\n', '').replace('\r', '') 158 | 159 | if len(line) == 0: 160 | continue 161 | 162 | if line[0] == '#': 163 | if len(line) == 1: 164 | if empty_line: 165 | continue 166 | 167 | empty_line = 1 168 | continue 169 | 170 | # comment_line = line[1:] 171 | if line.startswith('# CONFIG_'): 172 | line = ' ' + line[9:] 173 | else: 174 | line = line[1:] 175 | 176 | # print line 177 | 178 | empty_line = 0 179 | else: 180 | empty_line = 0 181 | setting = line.split('=') 182 | if len(setting) >= 2: 183 | if setting[0].startswith('CONFIG_'): 184 | setting[0] = setting[0][7:] 185 | 186 | if setting[0] == macro_name: 187 | config.close() 188 | return (True, setting[1]) 189 | 190 | config.close() 191 | return (False, None) 192 | 193 | 194 | # check if the bool macro is set or not 195 | # e.g CONFIG_SYS_AUTO_UPDATE_PKGS=y 196 | # will return True because this macro has been set 197 | # If this macro cannot find or the .config cannot find or the macro is not set (n), 198 | # the function will return False 199 | def find_bool_macro_in_config(filename, macro_name): 200 | rst, str = find_string_in_config(filename, macro_name) 201 | if rst == True and str == 'y': 202 | return True 203 | else: 204 | return False 205 | 206 | 207 | # find a string macro is defined or not 208 | # e.g. CONFIG_SYS_CREATE_IAR_EXEC_PATH="C:/Program Files (x86)/IAR Systems/Embedded Workbench 8.3" 209 | # will return "C:/Program Files (x86)/IAR Systems/Embedded Workbench 8.3" 210 | # If this macro cannot find or .config cannot find 211 | # the function will return None 212 | def find_string_macro_in_config(filename, macro_name): 213 | rst, str = find_string_in_config(filename, macro_name) 214 | if rst == True: 215 | str = str.strip('"') 216 | return str 217 | else: 218 | return None 219 | 220 | 221 | # return IAR execution path string or None for failure 222 | def find_IAR_EXEC_PATH(): 223 | env_root = Import('env_root') 224 | # get the .config file from env 225 | env_kconfig_path = os.path.join(env_root, 'tools', 'scripts', 'cmds') 226 | env_config_file = os.path.join(env_kconfig_path, '.config') 227 | 228 | return find_string_macro_in_config(env_config_file, 'SYS_CREATE_IAR_EXEC_PATH') 229 | 230 | 231 | # return Keil-MDK execution path string or None for failure 232 | def find_MDK_EXEC_PATH(): 233 | env_root = Import('env_root') 234 | # get the .config file from env 235 | env_kconfig_path = os.path.join(env_root, 'tools', 'scripts', 'cmds') 236 | env_config_file = os.path.join(env_kconfig_path, '.config') 237 | 238 | return find_string_macro_in_config(env_config_file, 'SYS_CREATE_MDK_EXEC_PATH') 239 | 240 | 241 | def remove_folder(folder_path): 242 | try: 243 | if os.path.isdir(folder_path): 244 | if is_windows(): 245 | cmd = 'rd /s /q ' + folder_path 246 | os.system(cmd) 247 | else: 248 | shutil.rmtree(folder_path) 249 | return True 250 | else: 251 | return True 252 | except Exception as e: 253 | logging.warning('Error message : {0}'.format(e)) 254 | return False 255 | -------------------------------------------------------------------------------- /cmds/cmd_package/cmd_package_wizard.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | # 3 | # File : cmd_package.py 4 | # This file is part of RT-Thread RTOS 5 | # COPYRIGHT (C) 2006 - 2020, RT-Thread Development Team 6 | # 7 | # This program is free software; you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation; either version 2 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # This program is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License along 18 | # with this program; if not, write to the Free Software Foundation, Inc., 19 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 20 | # 21 | # Change Logs: 22 | # Date Author Notes 23 | # 2020-04-08 SummerGift Optimize program structure 24 | # 25 | 26 | import os 27 | import re 28 | from package import Kconfig_file, Package_json_file 29 | from string import Template 30 | from .cmd_package_utils import user_input 31 | 32 | 33 | def package_wizard(): 34 | """Packages creation wizard. 35 | 36 | The user enters the package name, version number, category, and automatically generates the package index file. 37 | """ 38 | 39 | # Welcome 40 | print('\033[4;32;40mWelcome to using package wizard, please follow below steps.\033[0m\n') 41 | 42 | # Simple introduction about the wizard 43 | print('note :') 44 | print(' \033[5;35;40m[ ]\033[0m means default setting or optional information.') 45 | print(' \033[5;35;40mEnter\033[0m means using default option or ending and proceeding to the next step.') 46 | 47 | # first step 48 | print('\033[5;33;40m\n1.Please input a new package name :\033[0m') 49 | 50 | name = user_input().strip() 51 | regular_obj = re.compile(r'^[\w\d_-]*$') 52 | while name == '' or name.isspace() == True or regular_obj.search(name) == None: 53 | if name == '' or name.isspace(): 54 | print('\033[1;31;40mError: you must input a package name. Try again.\033[0m') 55 | else: 56 | print('\033[1;31;40mError: package name is made of alphabet, number, underline and dash. Try again.\033[0m') 57 | name = user_input().strip() 58 | 59 | default_description = 'Please add description of ' + name + ' in English.' 60 | description = default_description 61 | description_zh = "请添加软件包 " + name + " 的中文描述。" 62 | 63 | # second step 64 | print("\033[5;33;40m\n2.Please input this package version, default : '1.0.0' \033[0m") 65 | ver = user_input().strip() 66 | if ver == '': 67 | print("using default version 1.0.0") 68 | ver = '1.0.0' 69 | 70 | ver_standard = ver.replace('.', '') 71 | keyword = name 72 | 73 | # third step 74 | package_class_list = ( 75 | 'iot', 76 | 'language', 77 | 'misc', 78 | 'multimedia', 79 | 'peripherals', 80 | 'security', 81 | 'system', 82 | 'tools', 83 | 'peripherals/sensors', 84 | 'ai', 85 | ) 86 | 87 | arduino_class_list = ( 88 | 'arduino/sensors', 89 | 'arduino/timing', 90 | 'arduino/communication', 91 | 'arduino/dataprocessing', 92 | 'arduino/datastorage', 93 | 'arduino/devicecontrol', 94 | 'arduino/display', 95 | 'arduino/other', 96 | 'arduino/signalio', 97 | 'arduino/uncategorized', 98 | 'arduino/projects', 99 | ) 100 | 101 | print('\033[5;33;40m\n3.Please choose a package category from 1 to 11 : \033[0m') 102 | print( 103 | "\033[1;32;40m[1:iot]|[2:language]|[3:misc]|[4:multimedia]|" 104 | "[5:peripherals]|[6:security]|[7:system]|[8:tools]|[9:sensors]|[10:ai]|[11:arduino]\033[0m" 105 | ) # arduino category must be the last one 106 | 107 | class_number = user_input().strip() 108 | while class_number == '' or class_number.isdigit() is False or int(class_number) < 1 or int(class_number) > 11: 109 | if class_number == '': 110 | print('\033[1;31;40mError: You must choose a package category. Try again.\033[0m') 111 | else: 112 | print('\033[1;31;40mError: You must input an integer number from 1 to 11. Try again.\033[0m') 113 | class_number = user_input().strip() 114 | 115 | is_arduino_library = False 116 | if int(class_number) == 11: # Arduino category 117 | print('\033[5;33;40m\n3.Please choose an Arduino library category from 1 to 11 : \033[0m') 118 | print( 119 | "\033[1;32;40m[1:Sensors]|[2:Timing]|[3:Communication]|[4:Data Processing]|" 120 | "[5:Data Storage]|[6:Device Control]|[7:Display]|[8:Other]|[9:Signal Input/Output]|[10:Uncategorized]|[11:Project]\033[0m" 121 | ) 122 | 123 | arduino_class_number = user_input().strip() 124 | while ( 125 | arduino_class_number == '' 126 | or arduino_class_number.isdigit() is False 127 | or int(arduino_class_number) < 1 128 | or int(arduino_class_number) > 11 129 | ): 130 | if arduino_class_number == '': 131 | print('\033[1;31;40mError: You must choose a category. Try again.\033[0m') 132 | else: 133 | print('\033[1;31;40mError: You must input an integer number from 1 to 11. Try again.\033[0m') 134 | arduino_class_number = user_input().strip() 135 | 136 | package_class = arduino_class_list[int(arduino_class_number) - 1] 137 | is_arduino_library = True 138 | 139 | else: # other category 140 | package_class = package_class_list[int(class_number) - 1] 141 | 142 | # fourth step 143 | print("\033[5;33;40m\n4.Please input author's github ID of this package :\033[0m") 144 | 145 | author_name = user_input().strip() 146 | while author_name == '': 147 | print("\033[1;31;40mError: you must input author's github ID of this package. Try again.\033[0m") 148 | author_name = user_input().strip() 149 | 150 | # fifth step 151 | author_email = user_input('\033[5;33;40m\n5.Please input author email of this package :\n\033[0m') 152 | while author_email == '': 153 | print('\033[1;31;40mError: you must input author email of this package. Try again.\033[0m') 154 | author_email = user_input().strip() 155 | 156 | # sixth step 157 | print('\033[5;33;40m\n6.Please choose a license of this package from 1 to 6, or input other license name :\033[0m') 158 | print("\033[1;32;40m[1:Apache-2.0]|[2:MIT]|[3:LGPL-2.1]|[4:GPL-2.0]|[5:BSD-3-Clause]|[6:Unknown]\033[0m") 159 | license_index = ('Apache-2.0', 'MIT', 'LGPL-2.1', 'GPL-2.0', 'BSD-3-Clause', 'Unknown') 160 | license_class = user_input().strip() 161 | while license_class == '': 162 | print('\033[1;31;40mError: you must choose or input a license of this package. Try again.\033[0m') 163 | license_class = user_input().strip() 164 | 165 | if license_class.isdigit() and 1 <= int(license_class) <= 6: 166 | license_choice = license_index[int(license_class) - 1] 167 | else: 168 | license_choice = license_class 169 | 170 | # seventh step 171 | print('\033[5;33;40m\n7.Please input the repository of this package :\033[0m') 172 | print( 173 | "\033[1;32;40mFor example, hello package's repository url " "is 'https://github.com/RT-Thread-packages/hello'.\033[0m" 174 | ) 175 | 176 | repository = user_input().strip() 177 | while repository == '': 178 | print('\033[1;31;40mError: you must input a repository of this package. Try again.\033[0m') 179 | repository = user_input().strip() 180 | 181 | pkg_path = name 182 | if not os.path.exists(pkg_path): 183 | os.mkdir(pkg_path) 184 | else: 185 | print("\033[1;31;40mError: the package directory is exits!\033[0m") 186 | 187 | s = Template(Kconfig_file) 188 | upper_name = str.upper(name) 189 | upper_name = upper_name.replace('-', '_') 190 | if is_arduino_library: 191 | upper_name = 'ARDUINO_' + upper_name 192 | kconfig = s.substitute( 193 | name=upper_name, 194 | description=description, 195 | version=ver, 196 | pkgs_class=package_class, 197 | lowercase_name=name, 198 | version_standard=ver_standard, 199 | ) 200 | f = open(os.path.join(pkg_path, 'Kconfig'), 'w') 201 | f.write(kconfig) 202 | f.close() 203 | 204 | s = Template(Package_json_file) 205 | package = s.substitute( 206 | name=name, 207 | pkgsclass=package_class, 208 | authorname=author_name, 209 | authoremail=author_email, 210 | description=description, 211 | description_zh=description_zh, 212 | version=ver, 213 | keyword=keyword, 214 | license=license_choice, 215 | repository=repository, 216 | pkgs_using_name=upper_name, 217 | ) 218 | f = open(os.path.join(pkg_path, 'package.json'), 'w') 219 | f.write(package) 220 | f.close() 221 | 222 | print('\nThe package index has been created \033[1;32;40msuccessfully\033[0m.') 223 | print( 224 | 'Please \033[5;34;40mupdate\033[0m other information of this package ' 225 | 'based on Kconfig and package.json in directory ' + name + '.' 226 | ) 227 | -------------------------------------------------------------------------------- /cmds/cmd_sdk.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | # 3 | # File : cmd_sdk.py 4 | # This file is part of RT-Thread RTOS 5 | # COPYRIGHT (C) 2024, RT-Thread Development Team 6 | # 7 | # This program is free software; you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation; either version 2 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # This program is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License along 18 | # with this program; if not, write to the Free Software Foundation, Inc., 19 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 20 | # 21 | # Change Logs: 22 | # Date Author Notes 23 | # 2024-04-04 bernard the first version 24 | 25 | import os 26 | import json 27 | import platform 28 | import sys 29 | from vars import Import, Export 30 | 31 | '''RT-Thread environment sdk setting''' 32 | 33 | 34 | def cmd(args): 35 | import menuconfig 36 | from cmds.cmd_package import list_packages 37 | from cmds.cmd_package import get_packages 38 | from cmds.cmd_package import package_update 39 | 40 | # change to sdk root directory 41 | tools_kconfig_path = os.path.join(Import('env_root'), 'tools', 'scripts') 42 | beforepath = os.getcwd() 43 | os.chdir(tools_kconfig_path) 44 | 45 | # set HOSTOS 46 | os.environ['HOSTOS'] = platform.system() 47 | 48 | # change bsp root to sdk root 49 | bsp_root = tools_kconfig_path 50 | before_bsp_root = Import('bsp_root') 51 | Export('bsp_root') 52 | 53 | # do menuconfig 54 | sys.argv = ['menuconfig', 'Kconfig'] 55 | menuconfig._main() 56 | 57 | # update package 58 | package_update() 59 | 60 | # update sdk list information 61 | packages = get_packages() 62 | 63 | sdk_packages = [] 64 | for item in packages: 65 | sdk_item = {} 66 | sdk_item['name'] = item['name'] 67 | sdk_item['path'] = item['name'] + '-' + item['ver'] 68 | 69 | sdk_packages.append(sdk_item) 70 | 71 | # write sdk_packages to sdk_list.json 72 | with open(os.path.join(tools_kconfig_path, 'sdk_list.json'), 'w', encoding='utf-8') as f: 73 | json.dump(sdk_packages, f, ensure_ascii=False, indent=4) 74 | 75 | # restore the old directory 76 | os.chdir(beforepath) 77 | 78 | # restore the old bsp_root 79 | bsp_root = before_bsp_root 80 | Export('bsp_root') 81 | 82 | 83 | def add_parser(sub): 84 | parser = sub.add_parser('sdk', help=__doc__, description=__doc__) 85 | 86 | parser.set_defaults(func=cmd) 87 | -------------------------------------------------------------------------------- /cmds/cmd_system.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | # 3 | # File : cmd_system.py 4 | # This file is part of RT-Thread RTOS 5 | # COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team 6 | # 7 | # This program is free software; you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation; either version 2 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # This program is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License along 18 | # with this program; if not, write to the Free Software Foundation, Inc., 19 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 20 | # 21 | # Change Logs: 22 | # Date Author Notes 23 | # 2018-5-28 SummerGift Add copyright information 24 | # 25 | 26 | import os 27 | from vars import Import 28 | 29 | '''RT-Thread environment package system''' 30 | 31 | 32 | def cmd(args): 33 | packages_root = Import('pkgs_root') 34 | 35 | if args.system_update: 36 | dir_list = os.listdir(packages_root) 37 | 38 | with open(os.path.join(packages_root, 'Kconfig'), 'w') as kconfig: 39 | for item in dir_list: 40 | if os.path.isfile(os.path.join(packages_root, item, 'Kconfig')): 41 | kconfig.write('source "$PKGS_DIR/' + item + '/Kconfig"') 42 | kconfig.write('\n') 43 | 44 | 45 | def add_parser(sub): 46 | parser = sub.add_parser( 47 | 'system', 48 | help=__doc__, 49 | description=__doc__, 50 | ) 51 | 52 | parser.add_argument( 53 | '--update', 54 | help='update system menuconfig\'s online package options ', 55 | action='store_true', 56 | default=False, 57 | dest='system_update', 58 | ) 59 | 60 | parser.set_defaults(func=cmd) 61 | -------------------------------------------------------------------------------- /env.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "RT-Thread Env Tool", 3 | "version": "v2.0.2", 4 | "description": "A terminal env tool for RT-Thread", 5 | "repository": { 6 | "url": "https://github.com/RT-Thread/env" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /env.ps1: -------------------------------------------------------------------------------- 1 | $VENV_ROOT = "$PSScriptRoot\.venv" 2 | # rt-env目录是否存在 3 | if (-not (Test-Path -Path $VENV_ROOT)) { 4 | Write-Host "Create Python venv for RT-Thread..." 5 | python -m venv $VENV_ROOT 6 | # 激活python venv 7 | & "$VENV_ROOT\Scripts\Activate.ps1" 8 | # 安装env-script 9 | pip install "$PSScriptRoot\tools\scripts" 10 | } else { 11 | # 激活python venv 12 | & "$VENV_ROOT\Scripts\Activate.ps1" 13 | } 14 | 15 | $env:pathext = ".PS1;$env:pathext" 16 | -------------------------------------------------------------------------------- /env.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | # 3 | # File : env.py 4 | # This file is part of RT-Thread RTOS 5 | # COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team 6 | # 7 | # This program is free software; you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation; either version 2 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # This program is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License along 18 | # with this program; if not, write to the Free Software Foundation, Inc., 19 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 20 | # 21 | # Change Logs: 22 | # Date Author Notes 23 | # 2018-5-28 SummerGift Add copyright information 24 | # 2019-1-16 SummerGift Add chinese detection 25 | # 2020-4-13 SummerGift refactoring 26 | # 2025-1-27 bernard Add env.json for env information 27 | 28 | import os 29 | import sys 30 | import argparse 31 | import logging 32 | import platform 33 | import json 34 | 35 | script_path = os.path.abspath(__file__) 36 | mpath = os.path.dirname(script_path) 37 | sys.path.insert(0, mpath) 38 | 39 | from cmds import * 40 | from vars import Export 41 | 42 | __version__ = '' 43 | 44 | # try to read env.json to get information 45 | try: 46 | with open('env.json', 'r') as file: 47 | env_data = json.load(file) 48 | __version__ = env_data['name'] + ' '+ env_data['version'] 49 | except Exception as e: 50 | # use the default 'v2.0.1' 51 | __version__ = 'RT-Thread Env Tool v2.0.1' 52 | 53 | def show_version_warning(): 54 | rtt_ver = get_rtt_verion() 55 | 56 | if rtt_ver <= (5, 1, 0) and rtt_ver != (0, 0, 0): 57 | print('===================================================================') 58 | print('Welcome to %s' % __version__) 59 | print('===================================================================') 60 | # print('') 61 | print('env v2.0 has made the following important changes:') 62 | print('1. Upgrading Python version from v2 to v3') 63 | print('2. Replacing kconfig-frontends with Python kconfiglib') 64 | print('') 65 | print( 66 | 'env v2.0 require python kconfiglib (install by \033[4mpip install kconfiglib\033[0m),\n' 67 | 'but env v1.5.x confilt with kconfiglib (please run \033[4mpip uninstall kconfiglib\033[0m)' 68 | ) 69 | print('') 70 | print( 71 | '\033[1;31;40m** WARNING **\n' 72 | 'env v2.0 only FULL SUPPORT RT-Thread > v5.1.0 or master branch.\n' 73 | 'but you are working on RT-Thread V%d.%d.%d, please use env v1.5.x \033[0m' % rtt_ver, 74 | ) 75 | print('===================================================================') 76 | 77 | 78 | def init_argparse(): 79 | parser = argparse.ArgumentParser(description=__doc__) 80 | subs = parser.add_subparsers() 81 | 82 | parser.add_argument('-v', '--version', action='version', version=__version__) 83 | 84 | cmd_system.add_parser(subs) 85 | cmd_menuconfig.add_parser(subs) 86 | cmd_package.add_parser(subs) 87 | cmd_sdk.add_parser(subs) 88 | 89 | return parser 90 | 91 | 92 | def init_logger(env_root): 93 | log_format = "%(module)s %(lineno)d %(levelname)s %(message)s \n" 94 | date_format = '%Y-%m-%d %H:%M:%S %a ' 95 | logging.basicConfig( 96 | level=logging.WARNING, 97 | format=log_format, 98 | datefmt=date_format, 99 | # filename=log_name 100 | ) 101 | 102 | 103 | def get_rtt_verion(): 104 | import re 105 | 106 | rtt_root = get_rtt_root() 107 | 108 | if not rtt_root: 109 | return (0, 0, 0) 110 | 111 | if not os.path.isfile(os.path.join(rtt_root, "include", "rtdef.h")): 112 | return (0, 0, 0) 113 | 114 | major, minor, patch = 0, 0, 0 115 | with open(os.path.join(rtt_root, "include", 'rtdef.h')) as kconfig: 116 | lines = kconfig.readlines() 117 | for i in range(len(lines)): 118 | if "#define RT_VERSION_MAJOR" in lines[i]: 119 | major = int(re.split(r"\s+", lines[i].strip())[2]) 120 | if "#define RT_VERSION_MINOR" in lines[i]: 121 | minor = int(re.split(r"\s+", lines[i].strip())[2]) 122 | if "#define RT_VERSION_PATCH" in lines[i]: 123 | patch = int(re.split(r"\s+", lines[i].strip())[2]) 124 | 125 | return (major, minor, patch) 126 | 127 | 128 | def get_rtt_root(): 129 | bsp_root = get_bsp_root() 130 | 131 | # bsp/kconfig文件获取rtt_root 132 | if os.path.isfile(os.path.join(bsp_root, "Kconfig")): 133 | with open(os.path.join(bsp_root, 'Kconfig')) as kconfig: 134 | lines = kconfig.readlines() 135 | for i in range(len(lines)): 136 | if "config RTT_DIR" in lines[i]: 137 | rtt_root = lines[i + 3].strip().split(" ")[1].strip('"') 138 | if not os.path.isabs(rtt_root): 139 | rtt_root = os.path.join(bsp_root, rtt_root) 140 | return os.path.normpath(rtt_root) 141 | if "RTT_DIR :=" in lines[i]: 142 | rtt_root = lines[i].strip().split(":=")[1].strip() 143 | if not os.path.isabs(rtt_root): 144 | rtt_root = os.path.join(bsp_root, rtt_root) 145 | return os.path.normpath(rtt_root) 146 | 147 | if os.path.isfile(os.path.join("rt-thread", "include", "rtdef.h")): 148 | return os.path.normpath(os.path.join(bsp_root, "rt-thread")) 149 | 150 | if "bsp" in bsp_root: 151 | rtt_root = bsp_root.split("bsp")[0] 152 | if os.path.isfile(os.path.join(rtt_root, "include", "rtdef.h")): 153 | return os.path.normpath(rtt_root) 154 | 155 | return None 156 | 157 | 158 | def get_env_root(): 159 | env_root = os.getenv("ENV_ROOT") 160 | if env_root is None: 161 | if platform.system() != 'Windows': 162 | env_root = os.path.join(os.getenv('HOME'), '.env') 163 | else: 164 | env_root = os.path.join(os.getenv('USERPROFILE'), '.env') 165 | return env_root 166 | 167 | 168 | def get_package_root(): 169 | package_root = os.getenv("PKGS_ROOT") 170 | if package_root is None: 171 | package_root = os.path.join(get_env_root(), 'packages') 172 | return package_root 173 | 174 | 175 | def get_bsp_root(): 176 | bsp_root = os.getcwd() 177 | 178 | # noinspection PyBroadException 179 | try: 180 | bsp_root.encode('utf-8').decode("ascii") 181 | except Exception as e: 182 | if platform.system() == "Windows": 183 | os.system('chcp 65001 > nul') 184 | 185 | print("\n\033[1;31;40m警告:\033[0m") 186 | print("\033[1;31;40m当前路径不支持非英文字符,请修改当前路径为纯英文路径。\033[0m") 187 | print("\033[1;31;40mThe current path does not support non-English characters.\033[0m") 188 | print("\033[1;31;40mPlease modify the current path to a pure English path.\033[0m") 189 | 190 | if platform.system() == "Windows": 191 | os.system('chcp 437 > nul') 192 | 193 | exit(1) 194 | 195 | return bsp_root 196 | 197 | 198 | def export_environment_variable(): 199 | script_root = os.path.split(os.path.realpath(__file__))[0] 200 | sys.path = sys.path + [os.path.join(script_root)] 201 | env_root = get_env_root() 202 | pkgs_root = get_package_root() 203 | bsp_root = get_bsp_root() 204 | 205 | os.environ["ENV_ROOT"] = env_root 206 | os.environ['PKGS_ROOT'] = pkgs_root 207 | os.environ['PKGS_DIR'] = pkgs_root 208 | os.environ['BSP_DIR'] = bsp_root 209 | 210 | Export('env_root') 211 | Export('pkgs_root') 212 | Export('bsp_root') 213 | 214 | 215 | def exec_arg(arg): 216 | export_environment_variable() 217 | init_logger(get_env_root()) 218 | 219 | sys.argv.insert(1, arg) 220 | 221 | parser = init_argparse() 222 | args = parser.parse_args() 223 | args.func(args) 224 | 225 | 226 | def main(): 227 | show_version_warning() 228 | export_environment_variable() 229 | init_logger(get_env_root()) 230 | 231 | parser = init_argparse() 232 | args = parser.parse_args() 233 | 234 | if not vars(args): 235 | parser.print_help() 236 | else: 237 | args.func(args) 238 | 239 | 240 | def menuconfig(): 241 | show_version_warning() 242 | exec_arg('menuconfig') 243 | 244 | 245 | def pkgs(): 246 | show_version_warning() 247 | exec_arg('pkg') 248 | 249 | 250 | def sdk(): 251 | show_version_warning() 252 | exec_arg('sdk') 253 | 254 | 255 | def system(): 256 | show_version_warning() 257 | exec_arg('system') 258 | 259 | 260 | if __name__ == '__main__': 261 | main() 262 | -------------------------------------------------------------------------------- /env.sh: -------------------------------------------------------------------------------- 1 | export PATH=~/.env/tools/scripts:$PATH 2 | -------------------------------------------------------------------------------- /install_arch.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # 函数:从 AUR 安装 rt-thread-env-meta 包 4 | install_from_aur() { 5 | echo "正在从 AUR 安装 rt-thread-env-meta 包..." 6 | yay -Syu rt-thread-env-meta 7 | } 8 | 9 | # 函数:手动安装所需的包 10 | install_manually() { 11 | echo "正在手动安装所需的包..." 12 | 13 | # 安装基本依赖包 14 | sudo pacman -Syu python python-pip gcc git ncurses \ 15 | arm-none-eabi-gcc arm-none-eabi-gdb \ 16 | qemu-desktop qemu-system-arm-firmware scons \ 17 | python-requests python-tqdm python-kconfiglib 18 | 19 | # 提示用户安装 python-pyocd 及其插件 20 | echo " 21 | # python-pyocd 可以通过 AUR 安装或从 GitHub 获取: 22 | # https://github.com/taotieren/aur-repo 23 | yay -Syu python-pyocd python-pyocd-pemicro 24 | " 25 | 26 | # 询问用户是否要继续安装 python-pyocd 27 | read -p "是否现在安装 python-pyocd 和 python-pyocd-pemicro? (y/n) " choice 28 | case "$choice" in 29 | y | Y) 30 | yay -Syu python-pyocd python-pyocd-pemicro 31 | ;; 32 | n | N) 33 | echo "跳过安装 python-pyocd 和 python-pyocd-pemicro." 34 | ;; 35 | *) 36 | echo "无效输入,跳过安装 python-pyocd 和 python-pyocd-pemicro." 37 | ;; 38 | esac 39 | } 40 | 41 | # 显示菜单供用户选择 42 | echo "请选择安装方式:" 43 | echo "1. 从 AUR 安装 rt-thread-env-meta 包" 44 | echo "2. 手动安装所有所需包" 45 | read -p "请输入选项 [1 或 2]: " option 46 | 47 | case $option in 48 | 1) 49 | install_from_aur 50 | ;; 51 | 2) 52 | install_manually 53 | ;; 54 | *) 55 | echo "无效选项,退出安装程序。" 56 | exit 1 57 | ;; 58 | esac 59 | 60 | echo "安装完成。" 61 | 62 | url=https://raw.githubusercontent.com/RT-Thread/env/master/touch_env.sh 63 | if [ $1 ] && [ $1 = --gitee ]; then 64 | url=https://gitee.com/RT-Thread-Mirror/env/raw/master/touch_env.sh 65 | fi 66 | 67 | wget $url -O touch_env.sh 68 | chmod 777 touch_env.sh 69 | ./touch_env.sh $@ 70 | rm touch_env.sh 71 | -------------------------------------------------------------------------------- /install_macos.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | RTT_PYTHON=python 4 | 5 | for p_cmd in python3 python; do 6 | $p_cmd --version >/dev/null 2>&1 || continue 7 | RTT_PYTHON=$p_cmd 8 | break 9 | done 10 | 11 | $RTT_PYTHON --version 2 >/dev/null || { 12 | echo "Python not installed. Please install Python before running the installation script." 13 | exit 1 14 | } 15 | 16 | if ! [ -x "$(command -v brew)" ]; then 17 | echo "Installing Homebrew." 18 | /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" 19 | fi 20 | 21 | brew update 22 | brew upgrade 23 | 24 | if ! [ -x "$(command -v git)" ]; then 25 | echo "Installing git." 26 | brew install git 27 | fi 28 | 29 | brew list ncurses >/dev/null || { 30 | echo "Installing ncurses." 31 | brew install ncurses 32 | } 33 | 34 | $RTT_PYTHON -m pip list >/dev/null || { 35 | echo "Installing pip." 36 | $RTT_PYTHON -m ensurepip --upgrade 37 | } 38 | 39 | if ! [ -x "$(command -v scons)" ]; then 40 | echo "Installing scons." 41 | $RTT_PYTHON -m pip install scons 42 | fi 43 | 44 | if ! [ -x "$(command -v tqdm)" ]; then 45 | echo "Installing tqdm." 46 | $RTT_PYTHON -m pip install tqdm 47 | fi 48 | 49 | if ! [ -x "$(command -v kconfiglib)" ]; then 50 | echo "Installing kconfiglib." 51 | $RTT_PYTHON -m pip install kconfiglib 52 | fi 53 | 54 | if ! [ -x "$(command -v pyocd)" ]; then 55 | echo "Installing pyocd." 56 | $RTT_PYTHON -m pip install -U pyocd 57 | fi 58 | 59 | if ! [[ $($RTT_PYTHON -m pip list | grep requests) ]]; then 60 | echo "Installing requests." 61 | $RTT_PYTHON -m pip install requests 62 | fi 63 | 64 | if ! [ -x "$(command -v arm-none-eabi-gcc)" ]; then 65 | echo "Installing GNU Arm Embedded Toolchain." 66 | brew install gnu-arm-embedded 67 | fi 68 | 69 | url=https://raw.githubusercontent.com/RT-Thread/env/master/touch_env.sh 70 | if [ $1 ] && [ $1 = --gitee ]; then 71 | url=https://gitee.com/RT-Thread-Mirror/env/raw/master/touch_env.sh 72 | fi 73 | curl $url -o touch_env.sh 74 | chmod 777 touch_env.sh 75 | ./touch_env.sh $@ 76 | rm touch_env.sh 77 | -------------------------------------------------------------------------------- /install_suse.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | sudo zypper update -y 4 | 5 | sudo zypper install python3 python3-pip gcc git ncurses-devel cross-arm-none-gcc11-bootstrap cross-arm-binutils qemu qemu-arm qemu-extra -y 6 | python3 -m pip install scons requests tqdm kconfiglib 7 | python3 -m pip install -U pyocd 8 | 9 | url=https://raw.githubusercontent.com/RT-Thread/env/master/touch_env.sh 10 | if [ $1 ] && [ $1 = --gitee ]; then 11 | url=https://gitee.com/RT-Thread-Mirror/env/raw/master/touch_env.sh 12 | fi 13 | 14 | wget $url -O touch_env.sh 15 | chmod 777 touch_env.sh 16 | ./touch_env.sh $@ 17 | rm touch_env.sh 18 | -------------------------------------------------------------------------------- /install_ubuntu.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | sudo apt-get update 4 | sudo apt-get -qq install python3 python3-pip gcc git libncurses5-dev -y 5 | pip install scons requests tqdm kconfiglib pyyaml 6 | 7 | url=https://raw.githubusercontent.com/RT-Thread/env/master/touch_env.sh 8 | if [ $1 ] && [ $1 = --gitee ]; then 9 | url=https://gitee.com/RT-Thread-Mirror/env/raw/master/touch_env.sh 10 | fi 11 | 12 | wget $url -O touch_env.sh 13 | chmod 777 touch_env.sh 14 | ./touch_env.sh $@ 15 | rm touch_env.sh 16 | -------------------------------------------------------------------------------- /install_windows.ps1: -------------------------------------------------------------------------------- 1 | 2 | $RTT_PYTHON = "python" 3 | 4 | function Test-Command( [string] $CommandName ) { 5 | (Get-Command $CommandName -ErrorAction SilentlyContinue) -ne $null 6 | } 7 | 8 | foreach ($p_cmd in ("python3", "python", "py")) { 9 | cmd /c $p_cmd --version | findstr "Python" | Out-Null 10 | if (!$?) { continue } 11 | $RTT_PYTHON = $p_cmd 12 | break 13 | } 14 | 15 | cmd /c $RTT_PYTHON --version | findstr "Python" | Out-Null 16 | if (!$?) { 17 | echo "Python is not installed. Will install python 3.11.2." 18 | echo "Downloading Python." 19 | wget -O Python_setup.exe https://www.python.org/ftp/python/3.11.2/python-3.11.2.exe 20 | echo "Installing Python." 21 | if (Test-Path -Path "D:\") { 22 | cmd /c Python_setup.exe /quiet TargetDir=D:\Progrem\Python311 InstallAllUsers=1 PrependPath=1 Include_test=0 23 | } else { 24 | cmd /c Python_setup.exe /quiet PrependPath=1 Include_test=0 25 | } 26 | echo "Install Python done. please close the current terminal and run this script again." 27 | exit 28 | } else { 29 | echo "Python environment has installed. Jump this step." 30 | } 31 | 32 | $git_url = "https://github.com/git-for-windows/git/releases/download/v2.39.2.windows.1/Git-2.39.2-64-bit.exe" 33 | if ($args[0] -eq "--gitee") { 34 | echo "Use gitee mirror server!" 35 | $git_url = "https://registry.npmmirror.com/-/binary/git-for-windows/v2.39.2.windows.1/Git-2.39.2-64-bit.exe" 36 | } 37 | 38 | if (!(Test-Command git)) { 39 | echo "Git is not installed. Will install Git." 40 | echo "Installing git." 41 | winget install --id Git.Git -e --source winget 42 | if (!$?) { 43 | echo "Can't find winget cmd, Will install git 2.39.2." 44 | echo "downloading git." 45 | wget -O Git64.exe $git_url 46 | echo "Please install git. when install done, close the current terminal and run this script again." 47 | cmd /c Git64.exe /quiet PrependPath=1 48 | exit 49 | } 50 | } else { 51 | echo "Git environment has installed. Jump this step." 52 | } 53 | 54 | $PIP_SOURCE = "https://pypi.org/simple" 55 | $PIP_HOST = "pypi.org" 56 | if ($args[0] -eq "--gitee") { 57 | $PIP_SOURCE = "http://mirrors.aliyun.com/pypi/simple" 58 | $PIP_HOST = "mirrors.aliyun.com" 59 | } 60 | 61 | cmd /c $RTT_PYTHON -m pip list -i $PIP_SOURCE --trusted-host $PIP_HOST | Out-Null 62 | if (!$?) { 63 | echo "Installing pip." 64 | cmd /c $RTT_PYTHON -m ensurepip --upgrade 65 | } else { 66 | echo "Pip has installed. Jump this step." 67 | } 68 | 69 | cmd /c $RTT_PYTHON -m pip install --upgrade pip -i $PIP_SOURCE --trusted-host $PIP_HOST | Out-Null 70 | 71 | if (!(Test-Command scons)) { 72 | echo "Installing scons." 73 | cmd /c $RTT_PYTHON -m pip install scons -i $PIP_SOURCE --trusted-host $PIP_HOST 74 | } else { 75 | echo "scons has installed. Jump this step." 76 | } 77 | 78 | if (!(Test-Command pyocd)) { 79 | echo "Installing pyocd." 80 | cmd /c $RTT_PYTHON -m pip install -U pyocd -i $PIP_SOURCE --trusted-host $PIP_HOST 81 | } else { 82 | echo "pyocd has installed. Jump this step." 83 | } 84 | 85 | cmd /c $RTT_PYTHON -m pip list -i $PIP_SOURCE --trusted-host $PIP_HOST | findstr "tqdm" | Out-Null 86 | if (!$?) { 87 | echo "Installing tqdm module." 88 | cmd /c $RTT_PYTHON -m pip install tqdm -i $PIP_SOURCE --trusted-host $PIP_HOST 89 | } else { 90 | echo "tqdm module has installed. Jump this step." 91 | } 92 | 93 | cmd /c $RTT_PYTHON -m pip list -i $PIP_SOURCE --trusted-host $PIP_HOST | findstr "kconfiglib" | Out-Null 94 | if (!$?) { 95 | echo "Installing kconfiglib module." 96 | cmd /c $RTT_PYTHON -m pip install kconfiglib -i $PIP_SOURCE --trusted-host $PIP_HOST 97 | } else { 98 | echo "kconfiglib module has installed. Jump this step." 99 | } 100 | 101 | 102 | cmd /c $RTT_PYTHON -m pip list -i $PIP_SOURCE --trusted-host $PIP_HOST | findstr "requests" | Out-Null 103 | if (!$?) { 104 | echo "Installing requests module." 105 | cmd /c $RTT_PYTHON -m pip install requests -i $PIP_SOURCE --trusted-host $PIP_HOST 106 | } else { 107 | echo "requests module has installed. Jump this step." 108 | } 109 | 110 | cmd /c $RTT_PYTHON -m pip list -i $PIP_SOURCE --trusted-host $PIP_HOST | findstr "psutil" | Out-Null 111 | if (!$?) { 112 | echo "Installing psutil module." 113 | cmd /c $RTT_PYTHON -m pip install psutil -i $PIP_SOURCE --trusted-host $PIP_HOST 114 | } else { 115 | echo "psutil module has installed. Jump this step." 116 | } 117 | 118 | $url = "https://raw.githubusercontent.com/RT-Thread/env/master/touch_env.ps1" 119 | if ($args[0] -eq "--gitee") { 120 | $url = "https://gitee.com/RT-Thread-Mirror/env/raw/master/touch_env.ps1" 121 | } 122 | 123 | wget $url -O touch_env.ps1 124 | echo "run touch_env.ps1" 125 | ./touch_env.ps1 $args[0] 126 | Read-Host -Prompt "Windows Env environment installment has finished. Press any key to continue..." 127 | -------------------------------------------------------------------------------- /kconfig-mconf.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RT-Thread/env/501626f9a5ee4b2067fba084bb197d64e350aba0/kconfig-mconf.zip -------------------------------------------------------------------------------- /kconfig.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | # 3 | # File : kconfig.py 4 | # This file is part of RT-Thread RTOS 5 | # COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team 6 | # 7 | # This program is free software; you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation; either version 2 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # This program is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License along 18 | # with this program; if not, write to the Free Software Foundation, Inc., 19 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 20 | # 21 | # Change Logs: 22 | # Date Author Notes 23 | # 2018-5-28 SummerGift Add copyright information 24 | # 25 | 26 | 27 | def pkgs_path(pkgs, name, path): 28 | for pkg in pkgs: 29 | if 'name' in pkg and pkg['name'] == name: 30 | pkg['path'] = path 31 | return 32 | 33 | pkg = {} 34 | pkg['name'] = name 35 | pkg['path'] = path 36 | pkgs.append(pkg) 37 | 38 | 39 | def pkgs_ver(pkgs, name, ver): 40 | for pkg in pkgs: 41 | if 'name' in pkg and pkg['name'] == name: 42 | pkg['ver'] = ver 43 | return 44 | 45 | pkg = {} 46 | pkg['name'] = name 47 | pkg['ver'] = ver 48 | pkgs.append(pkg) 49 | 50 | 51 | def parse(filename): 52 | ret = [] 53 | 54 | # noinspection PyBroadException 55 | try: 56 | config = open(filename, "r") 57 | except Exception as e: 58 | print('open .config failed') 59 | return ret 60 | 61 | for line in config: 62 | line = line.lstrip(' ').replace('\n', '').replace('\r', '') 63 | 64 | if len(line) == 0: 65 | continue 66 | 67 | if line[0] == '#': 68 | continue 69 | else: 70 | setting = line.split('=', 1) 71 | if len(setting) >= 2: 72 | if setting[0].startswith('CONFIG_PKG_'): 73 | pkg_prefix = setting[0][11:] 74 | if pkg_prefix.startswith('USING_'): 75 | pkg_name = pkg_prefix[6:] 76 | else: 77 | if pkg_prefix.endswith('_PATH'): 78 | pkg_name = pkg_prefix[:-5] 79 | pkg_path = setting[1] 80 | if pkg_path.startswith('"'): 81 | pkg_path = pkg_path[1:] 82 | if pkg_path.endswith('"'): 83 | pkg_path = pkg_path[:-1] 84 | pkgs_path(ret, pkg_name, pkg_path) 85 | 86 | if pkg_prefix.endswith('_VER'): 87 | pkg_name = pkg_prefix[:-4] 88 | pkg_ver = setting[1] 89 | if pkg_ver.startswith('"'): 90 | pkg_ver = pkg_ver[1:] 91 | if pkg_ver.endswith('"'): 92 | pkg_ver = pkg_ver[:-1] 93 | pkgs_ver(ret, pkg_name, pkg_ver) 94 | 95 | config.close() 96 | return ret 97 | 98 | 99 | if __name__ == '__main__': 100 | parse('sample/.config') 101 | -------------------------------------------------------------------------------- /menuconfig: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | python3 ~/.env/tools/scripts/env.py menuconfig $* 4 | -------------------------------------------------------------------------------- /package.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | # 3 | # File : package.py 4 | # This file is part of RT-Thread RTOS 5 | # COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team 6 | # 7 | # This program is free software; you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation; either version 2 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # This program is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License along 18 | # with this program; if not, write to the Free Software Foundation, Inc., 19 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 20 | # 21 | # Change Logs: 22 | # Date Author Notes 23 | # 2018-5-28 SummerGift Add copyright information 24 | # 2018-12-28 Ernest Chen Add package information and enjoy package maker 25 | # 2020-4-7 SummerGift Code improvement 26 | # 27 | 28 | import json 29 | import logging 30 | import os 31 | import sys 32 | import requests 33 | import archive 34 | from tqdm import tqdm 35 | 36 | """Template for creating a new file""" 37 | 38 | Bridge_SConscript = '''import os 39 | from building import * 40 | 41 | objs = [] 42 | cwd = GetCurrentDir() 43 | list = os.listdir(cwd) 44 | 45 | for item in list: 46 | if os.path.isfile(os.path.join(cwd, item, 'SConscript')): 47 | objs = objs + SConscript(os.path.join(item, 'SConscript')) 48 | 49 | Return('objs') 50 | ''' 51 | 52 | Kconfig_file = ''' 53 | # Kconfig file for package ${lowercase_name} 54 | menuconfig PKG_USING_${name} 55 | bool "${description}" 56 | default n 57 | 58 | if PKG_USING_${name} 59 | 60 | config PKG_${name}_PATH 61 | string 62 | default "/packages/${pkgs_class}/${lowercase_name}" 63 | 64 | choice 65 | prompt "Version" 66 | help 67 | Select the package version 68 | 69 | config PKG_USING_${name}_V${version_standard} 70 | bool "v${version}" 71 | 72 | config PKG_USING_${name}_LATEST_VERSION 73 | bool "latest" 74 | endchoice 75 | 76 | config PKG_${name}_VER 77 | string 78 | default "v${version}" if PKG_USING_${name}_V${version_standard} 79 | default "latest" if PKG_USING_${name}_LATEST_VERSION 80 | 81 | endif 82 | 83 | ''' 84 | 85 | Package_json_file = '''{ 86 | "name": "${name}", 87 | "description": "${description}", 88 | "description_zh": "${description_zh}", 89 | "enable": "PKG_USING_${pkgs_using_name}", 90 | "keywords": [ 91 | "${keyword}" 92 | ], 93 | "category": "${pkgsclass}", 94 | "author": { 95 | "name": "${authorname}", 96 | "email": "${authoremail}", 97 | "github": "${authorname}" 98 | }, 99 | "license": "${license}", 100 | "repository": "${repository}", 101 | "icon": "unknown", 102 | "homepage": "${repository}#readme", 103 | "doc": "unknown", 104 | "site": [ 105 | { 106 | "version": "v${version}", 107 | "URL": "https://${name}-${version}.zip", 108 | "filename": "${name}-${version}.zip" 109 | }, 110 | { 111 | "version": "latest", 112 | "URL": "${repository}.git", 113 | "filename": "", 114 | "VER_SHA": "master" 115 | } 116 | ] 117 | } 118 | ''' 119 | 120 | import codecs 121 | 122 | 123 | class PackageOperation: 124 | pkg = None 125 | 126 | def parse(self, filename): 127 | with codecs.open(filename, "r", encoding='utf-8') as f: 128 | json_str = f.read() 129 | 130 | if json_str: 131 | self.pkg = json.loads(json_str) 132 | 133 | def get_name(self): 134 | return self.pkg['name'] 135 | 136 | def get_filename(self, ver): 137 | for item in self.pkg['site']: 138 | if item['version'].lower() == ver.lower(): 139 | return item['filename'] 140 | 141 | return None 142 | 143 | def get_url(self, ver): 144 | url = None 145 | for item in self.pkg['site']: 146 | if item['version'].lower() == ver.lower(): 147 | url = item['URL'] 148 | 149 | if not url: 150 | logging.warning("Can't find right url {0}, please check {1}".format(ver.lower(), self.pkg['site'])) 151 | 152 | return url 153 | 154 | def get_versha(self, ver): 155 | for item in self.pkg['site']: 156 | if item['version'].lower() == ver.lower(): 157 | return item['VER_SHA'] 158 | 159 | return None 160 | 161 | def get_site(self, ver): 162 | for item in self.pkg['site']: 163 | if item['version'].lower() == ver.lower(): 164 | return item 165 | 166 | return None 167 | 168 | def download(self, ver, path, url_from_srv): 169 | ret = True 170 | url = self.get_url(ver) 171 | site = self.get_site(ver) 172 | if site and 'filename' in site: 173 | filename = site['filename'] 174 | path = os.path.join(path, filename) 175 | else: 176 | basename = os.path.basename(url) 177 | path = os.path.join(path, basename) 178 | 179 | if os.path.isfile(path): 180 | if not os.path.getsize(path): 181 | os.remove(path) 182 | else: 183 | if archive.package_integrity_test(path): 184 | return True 185 | else: 186 | os.remove(path) 187 | 188 | retry_count = 0 189 | 190 | headers = {'Connection': 'keep-alive', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'User-Agent': 'curl/7.54.0'} 191 | 192 | print('downloading ' + filename + ' ...') 193 | 194 | while True: 195 | try: 196 | r = requests.get(url_from_srv, stream=True, headers=headers) 197 | total_size = int(r.headers.get('content-length', 0)) 198 | 199 | with open(path, 'wb') as f, tqdm(total=total_size, unit='B', unit_scale=True) as bar: 200 | # if the chunk_size is too large, the progress bar will not display 201 | for chunk in r.iter_content(chunk_size=1024): 202 | if chunk: 203 | f.write(chunk) 204 | bar.update(len(chunk)) 205 | 206 | retry_count = retry_count + 1 207 | 208 | if archive.package_integrity_test(path): # make sure the file is right 209 | ret = True 210 | break 211 | else: 212 | if os.path.isfile(path): 213 | os.remove(path) 214 | if retry_count > 5: 215 | print("error: Have tried downloading 5 times.\nstop Downloading file :%s" % path) 216 | if os.path.isfile(path): 217 | os.remove(path) 218 | ret = False 219 | break 220 | except Exception as e: 221 | print(url_from_srv) 222 | print('error message:%s\t' % e) 223 | retry_count = retry_count + 1 224 | if retry_count > 5: 225 | print('%s download fail!\n' % path.encode("utf-8")) 226 | if os.path.isfile(path): 227 | os.remove(path) 228 | return False 229 | return ret 230 | -------------------------------------------------------------------------------- /pkgs: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | python3 ~/.env/tools/scripts/env.py package $* 4 | -------------------------------------------------------------------------------- /pkgsdb.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | # 3 | # File : pkgsdb.py 4 | # This file is part of RT-Thread RTOS 5 | # COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team 6 | # 7 | # This program is free software; you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation; either version 2 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # This program is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License along 18 | # with this program; if not, write to the Free Software Foundation, Inc., 19 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 20 | # 21 | # Change Logs: 22 | # Date Author Notes 23 | # 2018-5-28 SummerGift Add copyright information 24 | # 2020-4-10 SummerGift Code clear up 25 | # 26 | 27 | import sqlite3 28 | import os 29 | import hashlib 30 | from cmds.cmd_package.cmd_package_utils import user_input 31 | from vars import Import 32 | 33 | SHOW_SQL = False 34 | 35 | 36 | def get_file_md5(filename): 37 | if not os.path.isfile(filename): 38 | return 39 | hash_value = hashlib.md5() 40 | f = open(filename, 'rb') 41 | while True: 42 | b = f.read(8096) 43 | if not b: 44 | break 45 | hash_value.update(b) 46 | f.close() 47 | return hash_value.hexdigest() 48 | 49 | 50 | def get_conn(path): 51 | conn = sqlite3.connect(path) 52 | if os.path.exists(path) and os.path.isfile(path): 53 | return conn 54 | else: 55 | print('on memory:[:memory:]') 56 | return sqlite3.connect(':memory:') 57 | 58 | 59 | def close_all(conn): 60 | if conn is not None: 61 | conn.close() 62 | 63 | 64 | def get_cursor(conn): 65 | if conn is not None: 66 | return conn.cursor() 67 | else: 68 | return get_conn('').cursor() 69 | 70 | 71 | def create_table(conn, sql): 72 | if sql is not None and sql != '': 73 | cu = get_cursor(conn) 74 | if SHOW_SQL: 75 | print('execute :[{}]'.format(sql)) 76 | cu.execute(sql) 77 | conn.commit() 78 | close_all(conn) 79 | else: 80 | print('the [{}] is empty or equal None!'.format(sql)) 81 | 82 | 83 | def save(conn, sql, data): 84 | """insert data to database""" 85 | if sql is not None and sql != '': 86 | if data is not None: 87 | cu = get_cursor(conn) 88 | for d in data: 89 | if SHOW_SQL: 90 | print('execute sql:[{}],arguments:[{}]'.format(sql, d)) 91 | cu.execute(sql, d) 92 | conn.commit() 93 | close_all(conn) 94 | else: 95 | print('the [{}] is empty or equal None!'.format(sql)) 96 | 97 | 98 | def isdataexist(pathname): 99 | ret = True 100 | dbfilename = Import('dbsqlite_pathname') 101 | 102 | conn = get_conn(dbfilename) 103 | c = get_cursor(conn) 104 | sql = 'SELECT md5 from packagefile where pathname = "' + pathname + '"' 105 | cursor = c.execute(sql) 106 | for row in cursor: 107 | dbmd5 = row[0] 108 | 109 | if dbmd5: 110 | ret = False 111 | conn.close() 112 | return ret 113 | 114 | 115 | # Add data to the database, if the data already exists, don't add again 116 | def save_to_database(pathname, package_pathname, before_change_name): 117 | db_pathname = Import('dbsqlite_pathname') 118 | bsp_root = Import('bsp_root') 119 | bsp_packages_path = os.path.join(bsp_root, 'packages') 120 | 121 | conn = get_conn(db_pathname) 122 | save_sql = '''insert into packagefile values (?, ?, ?)''' 123 | package = os.path.basename(package_pathname) 124 | md5pathname = os.path.join(bsp_packages_path, before_change_name) 125 | 126 | if not os.path.isfile(md5pathname): 127 | print("md5pathname is Invalid") 128 | 129 | md5 = get_file_md5(md5pathname) 130 | data = [(pathname, package, md5)] 131 | save(conn, save_sql, data) 132 | 133 | 134 | def dbdump(dbfilename): 135 | conn = get_conn(dbfilename) 136 | c = get_cursor(conn) 137 | cursor = c.execute("SELECT pathname, package, md5 from packagefile") 138 | for row in cursor: 139 | print("pathname = ", row[0]) 140 | print("package = ", row[1]) 141 | print("md5 = ", row[2], "\n") 142 | conn.close() 143 | 144 | 145 | def remove_unchanged_file(pathname, dbfilename, dbsqlname): 146 | """delete unchanged files""" 147 | flag = True 148 | 149 | conn = get_conn(dbfilename) 150 | c = get_cursor(conn) 151 | filemd5 = get_file_md5(pathname) 152 | dbmd5 = 0 153 | 154 | sql = 'SELECT md5 from packagefile where pathname = "' + dbsqlname + '"' 155 | # print sql 156 | cursor = c.execute(sql) 157 | for row in cursor: 158 | # fetch md5 from database 159 | dbmd5 = row[0] 160 | 161 | if dbmd5 == filemd5: 162 | # delete file info from database 163 | sql = "DELETE from packagefile where pathname = '" + dbsqlname + "'" 164 | conn.commit() 165 | os.remove(pathname) 166 | else: 167 | print("%s has been changed." % pathname) 168 | print('Are you sure you want to permanently delete the file: %s?' % os.path.basename(pathname)) 169 | print( 170 | 'If you choose to keep the changed file,you should copy the file to another folder. ' 171 | '\nbecaues it may be covered by the next update.' 172 | ) 173 | 174 | rc = user_input('Press the Y Key to delete the folder or just press Enter to keep it : ') 175 | if rc == 'y' or rc == 'Y': 176 | sql = "DELETE from packagefile where pathname = '" + dbsqlname + "'" 177 | conn.commit() 178 | os.remove(pathname) 179 | print("%s has been removed.\n" % pathname) 180 | else: 181 | flag = False 182 | conn.close() 183 | return flag 184 | 185 | 186 | # 删除一个包,如果有文件被改动,则提示(y/n)是否要删除,输入y则删除文件,输入其他字符则保留文件。 187 | # 如果没有文件被改动,直接删除文件夹,包文件夹被完全删除返回true,有被修改的文件没有被删除返回false 188 | def deletepackdir(dirpath, dbpathname): 189 | flag = getdirdisplay(dirpath, dbpathname) 190 | 191 | if flag: 192 | if os.path.exists(dirpath): 193 | for root, dirs, files in os.walk(dirpath, topdown=False): 194 | for name in files: 195 | os.remove(os.path.join(root, name)) 196 | for name in dirs: 197 | os.rmdir(os.path.join(root, name)) 198 | os.rmdir(dirpath) 199 | # print "the dir should be delete" 200 | return flag 201 | 202 | 203 | # walk through all files in filepath, include subfolder 204 | def displaydir(filepath, basepath, length, dbpathname): 205 | flag = True 206 | if os.path.isdir(filepath): 207 | files = os.listdir(filepath) 208 | for fi in files: 209 | fi_d = os.path.join(filepath, fi) 210 | if os.path.isdir(fi_d): 211 | displaydir(fi_d, basepath, length, dbpathname) 212 | else: 213 | pathname = os.path.join(filepath, fi_d) 214 | dbsqlname = basepath + os.path.join(filepath, fi_d)[length:] 215 | if not remove_unchanged_file(pathname, dbpathname, dbsqlname): 216 | flag = False 217 | return flag 218 | 219 | 220 | def getdirdisplay(filepath, dbpathname): 221 | display = filepath 222 | length = len(display) 223 | basepath = os.path.basename(filepath) 224 | flag = displaydir(filepath, basepath, length, dbpathname) 225 | return flag 226 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.black] 2 | line-length = 128 3 | skip-string-normalization = true 4 | # use-tabs = false 5 | -------------------------------------------------------------------------------- /sdk: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | python3 ~/.env/tools/scripts/env.py sdk $* 4 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | 3 | setup( 4 | name='env', 5 | version='2.0.1', 6 | description='RT-Thread Env', 7 | url='https://github.com/RT-Thread/env.git', 8 | author='RT-Thread Development Team', 9 | author_email='rt-thread@rt-thread.org', 10 | keywords='rt-thread', 11 | license='Apache License 2.0', 12 | project_urls={ 13 | 'Github repository': 'https:/github.com/rt-thread/env.git', 14 | 'User guide': 'https:/github.com/rt-thread/env.git', 15 | }, 16 | python_requires='>=3.6', 17 | install_requires=[ 18 | 'SCons>=4.0.0', 19 | 'requests', 20 | 'psutil', 21 | 'tqdm', 22 | 'kconfiglib', 23 | 'windows-curses; platform_system=="Windows"', 24 | ], 25 | packages=[ 26 | 'env', 27 | 'env.cmds', 28 | 'env.cmds.cmd_package', 29 | ], 30 | package_dir={ 31 | 'env': '.', 32 | 'env.cmds': 'cmds', 33 | 'env.cmds.cmd_package': 'cmds/cmd_package', 34 | }, 35 | package_data={'': ['*.*']}, 36 | exclude_package_data={'': ['MANIFEST.in']}, 37 | include_package_data=True, 38 | entry_points={ 39 | 'console_scripts': [ 40 | 'rt-env=env.env:main', 41 | 'menuconfig=env.env:menuconfig', 42 | 'pkgs=env.env:pkgs', 43 | 'sdk=env.env:sdk', 44 | 'system=env.env:system', 45 | ] 46 | }, 47 | ) 48 | -------------------------------------------------------------------------------- /statistics.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | # 3 | # File : vars.py 4 | # This file is part of RT-Thread RTOS 5 | # COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team 6 | # 7 | # This program is free software; you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation; either version 2 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # This program is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License along 18 | # with this program; if not, write to the Free Software Foundation, Inc., 19 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 20 | # 21 | # Change Logs: 22 | # Date Author Notes 23 | # 2022-5-6 WuGenSheng Add copyright information 24 | # 25 | import os 26 | import uuid 27 | 28 | import requests 29 | 30 | from vars import Import 31 | 32 | from cmds import * 33 | 34 | 35 | def get_mac_address(): 36 | mac = uuid.UUID(int=uuid.getnode()).hex[-12:] 37 | return ":".join([mac[e : e + 2] for e in range(0, 11, 2)]) 38 | 39 | 40 | def Information_statistics(): 41 | # get the .config file from env 42 | env_kconfig_path = os.path.join(os.getcwd(), 'tools', 'scripts', 'cmds') 43 | env_config_file = os.path.join(env_kconfig_path, '.config') 44 | 45 | mac_addr = get_mac_address() 46 | env_config_file = os.path.join(env_kconfig_path, '.config') 47 | 48 | if not os.path.isfile(env_config_file): 49 | try: 50 | response = requests.get( 51 | 'https://www.rt-thread.org/studio/statistics/api/envuse?userid=' 52 | + str(mac_addr) 53 | + '&username=' 54 | + str(mac_addr) 55 | + '&envversion=1.0&studioversion=2.0&ip=127.0.0.1' 56 | ) 57 | if response.status_code != 200: 58 | return 59 | except Exception as e: 60 | exit(0) 61 | elif os.path.isfile(env_config_file) and cmd_package.find_bool_macro_in_config( 62 | env_config_file, 'SYS_PKGS_NOT_USING_STATISTICS' 63 | ): 64 | return True 65 | 66 | 67 | if __name__ == '__main__': 68 | Information_statistics() 69 | -------------------------------------------------------------------------------- /touch_env.ps1: -------------------------------------------------------------------------------- 1 | $DEFAULT_RTT_PACKAGE_URL = "https://github.com/RT-Thread/packages.git" 2 | $ENV_URL = "https://github.com/RT-Thread/env.git" 3 | $SDK_URL = "https://github.com/RT-Thread/sdk.git" 4 | 5 | if ($args[0] -eq "--gitee") { 6 | echo "Using gitee service." 7 | $DEFAULT_RTT_PACKAGE_URL = "https://gitee.com/RT-Thread-Mirror/packages.git" 8 | $ENV_URL = "https://gitee.com/RT-Thread-Mirror/env.git" 9 | $SDK_URL = "https://gitee.com/RT-Thread-Mirror/sdk.git" 10 | } 11 | 12 | $env_dir = "$HOME\.env" 13 | 14 | if (Test-Path -Path $env_dir) { 15 | $option = Read-Host ".env directory already exists. Would you like to remove and recreate .env directory? (Y/N) " option 16 | } if (( $option -eq 'Y' ) -or ($option -eq 'y')) { 17 | Get-ChildItem $env_dir -Recurse | Remove-Item -Force -Recurse 18 | rm -r $env_dir 19 | } 20 | 21 | if (!(Test-Path -Path $env_dir)) { 22 | echo "creating .env folder!" 23 | $package_url = $DEFAULT_RTT_PACKAGE_URL 24 | mkdir $env_dir | Out-Null 25 | mkdir $env_dir\local_pkgs | Out-Null 26 | mkdir $env_dir\packages | Out-Null 27 | mkdir $env_dir\tools | Out-Null 28 | git clone $package_url $env_dir/packages/packages --depth=1 29 | echo 'source "$PKGS_DIR/packages/Kconfig"' | Out-File -FilePath $env_dir/packages/Kconfig -Encoding ASCII 30 | git clone $SDK_URL $env_dir/packages/sdk --depth=1 31 | git clone $ENV_URL $env_dir/tools/scripts --depth=1 32 | copy $env_dir/tools/scripts/env.ps1 $env_dir/env.ps1 33 | } else { 34 | echo ".env folder has exsited. Jump this step." 35 | } 36 | -------------------------------------------------------------------------------- /touch_env.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RT-Thread/env/501626f9a5ee4b2067fba084bb197d64e350aba0/touch_env.py -------------------------------------------------------------------------------- /touch_env.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | DEFAULT_RTT_PACKAGE_URL=https://github.com/RT-Thread/packages.git 4 | ENV_URL=https://github.com/RT-Thread/env.git 5 | SDK_URL="https://github.com/RT-Thread/sdk.git" 6 | 7 | if [ $1 ] && [ $1 = --gitee ]; then 8 | gitee=1 9 | DEFAULT_RTT_PACKAGE_URL=https://gitee.com/RT-Thread-Mirror/packages.git 10 | ENV_URL=https://gitee.com/RT-Thread-Mirror/env.git 11 | SDK_URL="https://gitee.com/RT-Thread-Mirror/sdk.git" 12 | fi 13 | 14 | env_dir=$HOME/.env 15 | if [ -d $env_dir ]; then 16 | read -p '.env directory already exists. Would you like to remove and recreate .env directory? (Y/N) ' option 17 | if [[ "$option" =~ [Yy*] ]]; then 18 | rm -rf $env_dir 19 | fi 20 | fi 21 | 22 | if ! [ -d $env_dir ]; then 23 | package_url=${RTT_PACKAGE_URL:-$DEFAULT_RTT_PACKAGE_URL} 24 | mkdir $env_dir 25 | mkdir $env_dir/local_pkgs 26 | mkdir $env_dir/packages 27 | mkdir $env_dir/tools 28 | git clone $package_url $env_dir/packages/packages --depth=1 29 | echo 'source "$PKGS_DIR/packages/Kconfig"' >$env_dir/packages/Kconfig 30 | git clone $SDK_URL $env_dir/packages/sdk --depth=1 31 | git clone $ENV_URL $env_dir/tools/scripts --depth=1 32 | echo -e 'export PATH=`python3 -m site --user-base`/bin:$HOME/.env/tools/scripts:$PATH\nexport RTT_EXEC_PATH=/usr/bin' >$env_dir/env.sh 33 | fi 34 | -------------------------------------------------------------------------------- /vars.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | # 3 | # File : vars.py 4 | # This file is part of RT-Thread RTOS 5 | # COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team 6 | # 7 | # This program is free software; you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation; either version 2 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # This program is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License along 18 | # with this program; if not, write to the Free Software Foundation, Inc., 19 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 20 | # 21 | # Change Logs: 22 | # Date Author Notes 23 | # 2018-5-28 SummerGift Add copyright information 24 | # 25 | 26 | import sys 27 | 28 | env_vars = {} 29 | 30 | 31 | def Export(var): 32 | f = sys._getframe(1).f_locals 33 | env_vars[var] = f[var] 34 | 35 | 36 | def Import(var): 37 | return env_vars[var] 38 | --------------------------------------------------------------------------------