env_utility.py 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488
  1. #! /usr/bin/env python
  2. # coding=utf-8
  3. #
  4. # Copyright (c) 2024, RT-Thread Development Team
  5. #
  6. # SPDX-License-Identifier: GPL-2.0
  7. #
  8. # Change Logs:
  9. # Date Author Notes
  10. # 2024-04-20 Bernard the first version
  11. import os
  12. import json
  13. import platform
  14. import re
  15. import sys
  16. import shutil
  17. import hashlib
  18. import operator
  19. def GetEnvPath():
  20. if "ENV_ROOT" in os.environ:
  21. return os.environ["ENV_ROOT"]
  22. if platform.system() == 'Windows':
  23. env_root = os.path.join(os.environ['USERPROFILE'], '.env')
  24. else:
  25. env_root = os.path.join(os.environ['HOME'], '.env')
  26. return env_root
  27. def GetPkgPath():
  28. if "PKGS_DIR" in os.environ:
  29. return os.environ["PKGS_DIR"]
  30. elif "PKGS_ROOT" in os.environ:
  31. return os.environ["PKGS_ROOT"]
  32. elif GetEnvPath():
  33. return os.path.join(GetEnvPath(), "packages")
  34. else:
  35. return None
  36. def GetSDKPackagePath():
  37. env = GetEnvPath()
  38. if env:
  39. return os.path.join(env, "tools", "scripts", "packages")
  40. return None
  41. # get SDK path based on name
  42. # for example, GetSDKPath('arm-none-eabi') = '.env/tools/scripts/packages/arm-none-eabi-gcc-v10.3'
  43. def GetSDKPath(name):
  44. sdk_pkgs = GetSDKPackagePath()
  45. if sdk_pkgs:
  46. # read env/tools/scripts/sdk_cfg.json for curstomized SDK path
  47. if os.path.exists(os.path.join(sdk_pkgs, '..', 'sdk_cfg.json')):
  48. with open(os.path.join(sdk_pkgs, '..', 'sdk_cfg.json'), 'r', encoding='utf-8') as f:
  49. sdk_cfg = json.load(f)
  50. for item in sdk_cfg:
  51. if item['name'] == name:
  52. sdk = os.path.join(sdk_pkgs, item['path'])
  53. return sdk
  54. # read packages.json under env/tools/scripts/packages
  55. with open(os.path.join(sdk_pkgs, 'pkgs.json'), 'r', encoding='utf-8') as f:
  56. # packages_json = f.read()
  57. packages = json.load(f)
  58. for item in packages:
  59. package_path = os.path.join(GetEnvPath(), 'packages', item['path'], 'package.json')
  60. # read package['path']/package.json under env/packages
  61. with open(package_path, 'r', encoding='utf-8') as f:
  62. # package_json = f.read()
  63. package = json.load(f)
  64. if package['name'] == name:
  65. sdk = os.path.join(sdk_pkgs, package['name'] + '-' + item['ver'])
  66. return sdk
  67. # not found named package
  68. return None
  69. def help_info():
  70. print(
  71. "**********************************************************************************\n"
  72. "* Help infomation:\n"
  73. "* Git tool install step.\n"
  74. "* If your system is linux, you can use command below to install git.\n"
  75. "* $ sudo yum install git\n"
  76. "* $ sudo apt-get install git\n"
  77. "* If your system is windows, you should download git software(msysGit).\n"
  78. "* Download path: http://git-scm.com/download/win\n"
  79. "* After you install it, be sure to add the git command execution PATH \n"
  80. "* to your system PATH.\n"
  81. "* Usually, git command PATH is $YOUR_INSTALL_DIR\\Git\\bin\n"
  82. "* If your system is OSX, please download git and install it.\n"
  83. "* Download path: http://git-scm.com/download/mac\n"
  84. "**********************************************************************************\n"
  85. )
  86. def touch_env(use_gitee=False):
  87. if sys.platform != 'win32':
  88. home_dir = os.environ['HOME']
  89. else:
  90. home_dir = os.environ['USERPROFILE']
  91. if use_gitee:
  92. # "Install RT-Thread Environment from Gitee"
  93. sdk_url = 'https://gitee.com/RT-Thread-Mirror/sdk.git'
  94. pkg_url = 'https://gitee.com/RT-Thread-Mirror/packages.git'
  95. env_url = 'https://gitee.com/RT-Thread-Mirror/env.git'
  96. else:
  97. pkg_url = 'https://github.com/RT-Thread/packages.git'
  98. sdk_url = 'https://github.com/RT-Thread/sdk.git'
  99. env_url = 'https://github.com/RT-Thread/env.git'
  100. pkg_url = os.getenv('RTT_PACKAGE_URL') or pkg_url
  101. sdk_url = os.getenv('RTT_SDK_URL') or sdk_url
  102. env_url = os.getenv('RTT_ENV_URL') or env_url
  103. # make .env and other directories
  104. env_dir = os.path.join(home_dir, '.env')
  105. if not os.path.exists(env_dir):
  106. os.mkdir(env_dir)
  107. os.mkdir(os.path.join(env_dir, 'local_pkgs'))
  108. os.mkdir(os.path.join(env_dir, 'packages'))
  109. os.mkdir(os.path.join(env_dir, 'tools'))
  110. kconfig = open(os.path.join(env_dir, 'packages', 'Kconfig'), 'w')
  111. kconfig.close()
  112. # git clone packages
  113. if not os.path.exists(os.path.join(env_dir, 'packages', 'packages')):
  114. try:
  115. ret = os.system('git clone %s %s' % (pkg_url, os.path.join(env_dir, 'packages', 'packages')))
  116. if ret != 0:
  117. shutil.rmtree(os.path.join(env_dir, 'packages', 'packages'))
  118. print(
  119. "********************************************************************************\n"
  120. "* Warnning:\n"
  121. "* Run command error for \"git clone https://github.com/RT-Thread/packages.git\".\n"
  122. "* This error may have been caused by not found a git tool or network error.\n"
  123. "* If the git tool is not installed, install the git tool first.\n"
  124. "* If the git utility is installed, check whether the git command is added to \n"
  125. "* the system PATH.\n"
  126. "* This error may cause the RT-Thread packages to not work properly.\n"
  127. "********************************************************************************\n"
  128. )
  129. help_info()
  130. else:
  131. kconfig = open(os.path.join(env_dir, 'packages', 'Kconfig'), 'w')
  132. kconfig.write('source "$PKGS_DIR/packages/Kconfig"')
  133. kconfig.close()
  134. except:
  135. print(
  136. "**********************************************************************************\n"
  137. "* Warnning:\n"
  138. "* Run command error for \"git clone https://github.com/RT-Thread/packages.git\". \n"
  139. "* This error may have been caused by not found a git tool or git tool not in \n"
  140. "* the system PATH. \n"
  141. "* This error may cause the RT-Thread packages to not work properly. \n"
  142. "**********************************************************************************\n"
  143. )
  144. help_info()
  145. # git clone env scripts
  146. if not os.path.exists(os.path.join(env_dir, 'tools', 'scripts')):
  147. try:
  148. ret = os.system('git clone %s %s' % (env_url, os.path.join(env_dir, 'tools', 'scripts')))
  149. if ret != 0:
  150. shutil.rmtree(os.path.join(env_dir, 'tools', 'scripts'))
  151. print(
  152. "********************************************************************************\n"
  153. "* Warnning:\n"
  154. "* Run command error for \"git clone https://github.com/RT-Thread/env.git\".\n"
  155. "* This error may have been caused by not found a git tool or network error.\n"
  156. "* If the git tool is not installed, install the git tool first.\n"
  157. "* If the git utility is installed, check whether the git command is added \n"
  158. "* to the system PATH.\n"
  159. "* This error may cause script tools to fail to work properly.\n"
  160. "********************************************************************************\n"
  161. )
  162. help_info()
  163. except:
  164. print(
  165. "********************************************************************************\n"
  166. "* Warnning:\n"
  167. "* Run command error for \"git clone https://github.com/RT-Thread/env.git\". \n"
  168. "* This error may have been caused by not found a git tool or git tool not in \n"
  169. "* the system PATH. \n"
  170. "* This error may cause script tools to fail to work properly. \n"
  171. "********************************************************************************\n"
  172. )
  173. help_info()
  174. # git clone sdk
  175. if not os.path.exists(os.path.join(env_dir, 'packages', 'sdk')):
  176. try:
  177. ret = os.system('git clone %s %s' % (sdk_url, os.path.join(env_dir, 'packages', 'sdk')))
  178. if ret != 0:
  179. shutil.rmtree(os.path.join(env_dir, 'packages', 'sdk'))
  180. print(
  181. "********************************************************************************\n"
  182. "* Warnning:\n"
  183. "* Run command error for \"git clone https://github.com/RT-Thread/sdk.git\".\n"
  184. "* This error may have been caused by not found a git tool or network error.\n"
  185. "* If the git tool is not installed, install the git tool first.\n"
  186. "* If the git utility is installed, check whether the git command is added \n"
  187. "* to the system PATH.\n"
  188. "* This error may cause the RT-Thread SDK to not work properly.\n"
  189. "********************************************************************************\n"
  190. )
  191. help_info()
  192. except:
  193. print(
  194. "********************************************************************************\n"
  195. "* Warnning:\n"
  196. "* Run command error for \"https://github.com/RT-Thread/sdk.git\".\n"
  197. "* This error may have been caused by not found a git tool or git tool not in \n"
  198. "* the system PATH. \n"
  199. "* This error may cause the RT-Thread SDK to not work properly. \n"
  200. "********************************************************************************\n"
  201. )
  202. help_info()
  203. # try to create an empty .config file
  204. if not os.path.exists(os.path.join(env_dir, 'tools', '.config')):
  205. kconfig = open(os.path.join(env_dir, 'tools', '.config'), 'w')
  206. kconfig.close()
  207. # copy env.sh or env.ps1, Kconfig
  208. shutil.copy(os.path.join(env_dir, 'tools', 'scripts', 'Kconfig'), os.path.join(home_dir, '.env', 'tools'))
  209. if sys.platform != 'win32':
  210. shutil.copy(os.path.join(env_dir, 'tools', 'scripts', 'env.sh'), os.path.join(home_dir, '.env', 'env.sh'))
  211. else:
  212. shutil.copy(os.path.join(env_dir, 'tools', 'scripts', 'env.ps1'), os.path.join(home_dir, '.env', 'env.ps1'))
  213. # unzip kconfig-mconf.zip
  214. # zip_file = os.path.join(env_dir, 'tools', 'scripts', 'kconfig-mconf.zip')
  215. # if os.path.exists(zip_file):
  216. # zip_file_dir = os.path.join(env_dir, 'tools', 'bin')
  217. # if os.path.exists(zip_file_dir):
  218. # shutil.rmtree(zip_file_dir)
  219. # zip_file_obj = zipfile.ZipFile(zip_file, 'r')
  220. # for file in zip_file_obj.namelist():
  221. # zip_file_obj.extract(file, zip_file_dir)
  222. # zip_file_obj.close()
  223. def is_pkg_special_config(config_str):
  224. '''judge if it's CONFIG_PKG_XX_PATH or CONFIG_PKG_XX_VER'''
  225. if type(config_str) == type('a'):
  226. if config_str.startswith("PKG_") and (config_str.endswith('_PATH') or config_str.endswith('_VER')):
  227. return True
  228. return False
  229. def mk_rtconfig(filename):
  230. try:
  231. config = open(filename, 'r')
  232. except:
  233. print('open config:%s failed' % filename)
  234. return
  235. rtconfig = open('rtconfig.h', 'w')
  236. rtconfig.write('#ifndef RT_CONFIG_H__\n')
  237. rtconfig.write('#define RT_CONFIG_H__\n\n')
  238. empty_line = 1
  239. for line in config:
  240. line = line.lstrip(' ').replace('\n', '').replace('\r', '')
  241. if len(line) == 0:
  242. continue
  243. if line[0] == '#':
  244. if len(line) == 1:
  245. if empty_line:
  246. continue
  247. rtconfig.write('\n')
  248. empty_line = 1
  249. continue
  250. if line.startswith('# CONFIG_'):
  251. line = ' ' + line[9:]
  252. else:
  253. line = line[1:]
  254. rtconfig.write('/*%s */\n' % line)
  255. empty_line = 0
  256. else:
  257. empty_line = 0
  258. setting = line.split('=')
  259. if len(setting) >= 2:
  260. if setting[0].startswith('CONFIG_'):
  261. setting[0] = setting[0][7:]
  262. # remove CONFIG_PKG_XX_PATH or CONFIG_PKG_XX_VER
  263. if is_pkg_special_config(setting[0]):
  264. continue
  265. if setting[1] == 'y':
  266. rtconfig.write('#define %s\n' % setting[0])
  267. else:
  268. rtconfig.write('#define %s %s\n' % (setting[0], re.findall(r"^.*?=(.*)$", line)[0]))
  269. if os.path.isfile('rtconfig_project.h'):
  270. rtconfig.write('#include "rtconfig_project.h"\n')
  271. rtconfig.write('\n')
  272. rtconfig.write('#endif\n')
  273. rtconfig.close()
  274. def get_file_md5(file):
  275. MD5 = hashlib.new('md5')
  276. with open(file, 'r') as fp:
  277. MD5.update(fp.read().encode('utf8'))
  278. fp_md5 = MD5.hexdigest()
  279. return fp_md5
  280. # Exclude utestcases
  281. def exclude_utestcases(RTT_ROOT):
  282. if os.path.isfile(os.path.join(RTT_ROOT, 'examples/utest/testcases/Kconfig')):
  283. return
  284. if not os.path.isfile(os.path.join(RTT_ROOT, 'Kconfig')):
  285. return
  286. with open(os.path.join(RTT_ROOT, 'Kconfig'), 'r') as f:
  287. data = f.readlines()
  288. with open(os.path.join(RTT_ROOT, 'Kconfig'), 'w') as f:
  289. for line in data:
  290. if line.find('examples/utest/testcases/Kconfig') == -1:
  291. f.write(line)
  292. # fix locale for kconfiglib
  293. def kconfiglib_fix_locale():
  294. import os
  295. import locale
  296. # Get the list of supported locales
  297. supported_locales = set(locale.locale_alias.keys())
  298. # Check if LANG is set and its value is not in the supported locales
  299. if 'LANG' in os.environ and os.environ['LANG'] not in supported_locales:
  300. os.environ['LANG'] = 'C'
  301. def kconfiglib_check_installed():
  302. try:
  303. import kconfiglib
  304. except ImportError as e:
  305. print("\033[1;31m**ERROR**: Failed to import kconfiglib, " + str(e))
  306. print("")
  307. print("You may need to install it using:")
  308. print(" pip install kconfiglib\033[0m")
  309. print("")
  310. sys.exit(1)
  311. # set PKGS_DIR envrionment
  312. pkg_dir = GetPkgPath()
  313. if os.path.exists(pkg_dir):
  314. os.environ["PKGS_DIR"] = pkg_dir
  315. elif sys.platform != 'win32':
  316. touch_env()
  317. os.environ["PKGS_DIR"] = GetPkgPath()
  318. else:
  319. print("\033[1;33m**WARNING**: PKGS_DIR not found, please install ENV tools\033[0m")
  320. # menuconfig for Linux and Windows
  321. def menuconfig(RTT_ROOT):
  322. kconfiglib_check_installed()
  323. import menuconfig
  324. # Exclude utestcases
  325. exclude_utestcases(RTT_ROOT)
  326. fn = '.config'
  327. fn_old = '.config.old'
  328. sys.argv = ['menuconfig', 'Kconfig']
  329. # fix vscode console
  330. kconfiglib_fix_locale()
  331. menuconfig._main()
  332. if os.path.isfile(fn):
  333. if os.path.isfile(fn_old):
  334. diff_eq = operator.eq(get_file_md5(fn), get_file_md5(fn_old))
  335. else:
  336. diff_eq = False
  337. else:
  338. sys.exit(-1)
  339. # make rtconfig.h
  340. if diff_eq == False:
  341. shutil.copyfile(fn, fn_old)
  342. mk_rtconfig(fn)
  343. # guiconfig for windows and linux
  344. def guiconfig(RTT_ROOT):
  345. kconfiglib_check_installed()
  346. import guiconfig
  347. # Exclude utestcases
  348. exclude_utestcases(RTT_ROOT)
  349. fn = '.config'
  350. fn_old = '.config.old'
  351. sys.argv = ['guiconfig', 'Kconfig']
  352. guiconfig._main()
  353. if os.path.isfile(fn):
  354. if os.path.isfile(fn_old):
  355. diff_eq = operator.eq(get_file_md5(fn), get_file_md5(fn_old))
  356. else:
  357. diff_eq = False
  358. else:
  359. sys.exit(-1)
  360. # make rtconfig.h
  361. if diff_eq == False:
  362. shutil.copyfile(fn, fn_old)
  363. mk_rtconfig(fn)
  364. # defconfig for windows and linux
  365. def defconfig(RTT_ROOT):
  366. kconfiglib_check_installed()
  367. import defconfig
  368. # Exclude utestcases
  369. exclude_utestcases(RTT_ROOT)
  370. fn = '.config'
  371. sys.argv = ['defconfig', '--kconfig', 'Kconfig', '.config']
  372. defconfig.main()
  373. # silent mode, force to make rtconfig.h
  374. mk_rtconfig(fn)
  375. def genconfig():
  376. from SCons.Script import SCons
  377. PreProcessor = SCons.cpp.PreProcessor()
  378. try:
  379. f = open('rtconfig.h', 'r')
  380. contents = f.read()
  381. f.close()
  382. except:
  383. print("Open rtconfig.h file failed.")
  384. PreProcessor.process_contents(contents)
  385. options = PreProcessor.cpp_namespace
  386. try:
  387. f = open('.config', 'w')
  388. for opt, value in options.items():
  389. if type(value) == type(1):
  390. f.write("CONFIG_%s=%d\n" % (opt, value))
  391. if type(value) == type('') and value == '':
  392. f.write("CONFIG_%s=y\n" % opt)
  393. elif type(value) == type('str'):
  394. f.write("CONFIG_%s=%s\n" % (opt, value))
  395. print("Generate .config done!")
  396. f.close()
  397. except:
  398. print("Generate .config file failed.")