frida 16.2.0 → 16.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (386) hide show
  1. package/BSDmakefile +6 -0
  2. package/Makefile +16 -0
  3. package/README.md +14 -11
  4. package/configure +18 -0
  5. package/configure.bat +22 -0
  6. package/dist/native.js +0 -8
  7. package/lib/application.ts +98 -0
  8. package/lib/authentication.ts +3 -0
  9. package/lib/build.py +50 -0
  10. package/lib/bus.ts +30 -0
  11. package/lib/cancellable.ts +33 -0
  12. package/lib/child.ts +15 -0
  13. package/lib/crash.ts +11 -0
  14. package/lib/device.ts +329 -0
  15. package/lib/device_manager.ts +69 -0
  16. package/lib/endpoint_parameters.ts +56 -0
  17. package/lib/icon.ts +15 -0
  18. package/lib/index.ts +311 -0
  19. package/lib/iostream.ts +78 -0
  20. package/lib/meson.build +53 -0
  21. package/lib/native.ts +9 -0
  22. package/lib/portal_membership.ts +10 -0
  23. package/lib/portal_service.ts +105 -0
  24. package/lib/process.ts +57 -0
  25. package/lib/relay.ts +44 -0
  26. package/lib/script.ts +352 -0
  27. package/lib/session.ts +113 -0
  28. package/lib/signals.ts +45 -0
  29. package/lib/socket_address.ts +35 -0
  30. package/lib/spawn.ts +4 -0
  31. package/lib/system_parameters.ts +78 -0
  32. package/make.bat +23 -0
  33. package/meson.build +160 -0
  34. package/meson.options +11 -0
  35. package/package.json +27 -6
  36. package/releng/deps.py +1133 -0
  37. package/releng/deps.toml +391 -0
  38. package/releng/devkit-assets/frida-core-example-unix.c +188 -0
  39. package/releng/devkit-assets/frida-core-example-windows.c +197 -0
  40. package/releng/devkit-assets/frida-core-example.sln +28 -0
  41. package/releng/devkit-assets/frida-core-example.vcxproj +157 -0
  42. package/releng/devkit-assets/frida-core-example.vcxproj.filters +27 -0
  43. package/releng/devkit-assets/frida-gum-example-unix.c +122 -0
  44. package/releng/devkit-assets/frida-gum-example-windows.c +132 -0
  45. package/releng/devkit-assets/frida-gum-example.sln +28 -0
  46. package/releng/devkit-assets/frida-gum-example.vcxproj +157 -0
  47. package/releng/devkit-assets/frida-gum-example.vcxproj.filters +27 -0
  48. package/releng/devkit-assets/frida-gumjs-example-unix.c +84 -0
  49. package/releng/devkit-assets/frida-gumjs-example-windows.c +91 -0
  50. package/releng/devkit-assets/frida-gumjs-example.sln +28 -0
  51. package/releng/devkit-assets/frida-gumjs-example.vcxproj +157 -0
  52. package/releng/devkit-assets/frida-gumjs-example.vcxproj.filters +27 -0
  53. package/releng/devkit.py +535 -0
  54. package/releng/env.py +420 -0
  55. package/releng/env_android.py +150 -0
  56. package/releng/env_apple.py +176 -0
  57. package/releng/env_generic.py +373 -0
  58. package/releng/frida_version.py +69 -0
  59. package/releng/machine_file.py +44 -0
  60. package/releng/machine_spec.py +290 -0
  61. package/releng/meson/meson.py +27 -0
  62. package/releng/meson/mesonbuild/__init__.py +0 -0
  63. package/releng/meson/mesonbuild/_pathlib.py +63 -0
  64. package/releng/meson/mesonbuild/_typing.py +69 -0
  65. package/releng/meson/mesonbuild/arglist.py +321 -0
  66. package/releng/meson/mesonbuild/ast/__init__.py +23 -0
  67. package/releng/meson/mesonbuild/ast/interpreter.py +441 -0
  68. package/releng/meson/mesonbuild/ast/introspection.py +374 -0
  69. package/releng/meson/mesonbuild/ast/postprocess.py +109 -0
  70. package/releng/meson/mesonbuild/ast/printer.py +620 -0
  71. package/releng/meson/mesonbuild/ast/visitor.py +161 -0
  72. package/releng/meson/mesonbuild/backend/__init__.py +0 -0
  73. package/releng/meson/mesonbuild/backend/backends.py +2047 -0
  74. package/releng/meson/mesonbuild/backend/ninjabackend.py +3808 -0
  75. package/releng/meson/mesonbuild/backend/nonebackend.py +26 -0
  76. package/releng/meson/mesonbuild/backend/vs2010backend.py +2078 -0
  77. package/releng/meson/mesonbuild/backend/vs2012backend.py +35 -0
  78. package/releng/meson/mesonbuild/backend/vs2013backend.py +34 -0
  79. package/releng/meson/mesonbuild/backend/vs2015backend.py +35 -0
  80. package/releng/meson/mesonbuild/backend/vs2017backend.py +59 -0
  81. package/releng/meson/mesonbuild/backend/vs2019backend.py +54 -0
  82. package/releng/meson/mesonbuild/backend/vs2022backend.py +54 -0
  83. package/releng/meson/mesonbuild/backend/xcodebackend.py +1781 -0
  84. package/releng/meson/mesonbuild/build.py +3249 -0
  85. package/releng/meson/mesonbuild/cargo/__init__.py +5 -0
  86. package/releng/meson/mesonbuild/cargo/builder.py +238 -0
  87. package/releng/meson/mesonbuild/cargo/cfg.py +274 -0
  88. package/releng/meson/mesonbuild/cargo/interpreter.py +733 -0
  89. package/releng/meson/mesonbuild/cargo/manifest.py +227 -0
  90. package/releng/meson/mesonbuild/cargo/version.py +95 -0
  91. package/releng/meson/mesonbuild/cmake/__init__.py +28 -0
  92. package/releng/meson/mesonbuild/cmake/common.py +331 -0
  93. package/releng/meson/mesonbuild/cmake/data/__init__.py +0 -0
  94. package/releng/meson/mesonbuild/cmake/data/preload.cmake +82 -0
  95. package/releng/meson/mesonbuild/cmake/executor.py +241 -0
  96. package/releng/meson/mesonbuild/cmake/fileapi.py +324 -0
  97. package/releng/meson/mesonbuild/cmake/generator.py +186 -0
  98. package/releng/meson/mesonbuild/cmake/interpreter.py +1267 -0
  99. package/releng/meson/mesonbuild/cmake/toolchain.py +248 -0
  100. package/releng/meson/mesonbuild/cmake/traceparser.py +814 -0
  101. package/releng/meson/mesonbuild/cmake/tracetargets.py +161 -0
  102. package/releng/meson/mesonbuild/compilers/__init__.py +86 -0
  103. package/releng/meson/mesonbuild/compilers/asm.py +307 -0
  104. package/releng/meson/mesonbuild/compilers/c.py +788 -0
  105. package/releng/meson/mesonbuild/compilers/c_function_attributes.py +143 -0
  106. package/releng/meson/mesonbuild/compilers/compilers.py +1388 -0
  107. package/releng/meson/mesonbuild/compilers/cpp.py +1035 -0
  108. package/releng/meson/mesonbuild/compilers/cs.py +136 -0
  109. package/releng/meson/mesonbuild/compilers/cuda.py +806 -0
  110. package/releng/meson/mesonbuild/compilers/cython.py +91 -0
  111. package/releng/meson/mesonbuild/compilers/d.py +861 -0
  112. package/releng/meson/mesonbuild/compilers/detect.py +1396 -0
  113. package/releng/meson/mesonbuild/compilers/fortran.py +523 -0
  114. package/releng/meson/mesonbuild/compilers/java.py +113 -0
  115. package/releng/meson/mesonbuild/compilers/mixins/__init__.py +0 -0
  116. package/releng/meson/mesonbuild/compilers/mixins/arm.py +167 -0
  117. package/releng/meson/mesonbuild/compilers/mixins/ccrx.py +113 -0
  118. package/releng/meson/mesonbuild/compilers/mixins/clang.py +170 -0
  119. package/releng/meson/mesonbuild/compilers/mixins/clike.py +1330 -0
  120. package/releng/meson/mesonbuild/compilers/mixins/compcert.py +117 -0
  121. package/releng/meson/mesonbuild/compilers/mixins/elbrus.py +93 -0
  122. package/releng/meson/mesonbuild/compilers/mixins/emscripten.py +89 -0
  123. package/releng/meson/mesonbuild/compilers/mixins/gnu.py +629 -0
  124. package/releng/meson/mesonbuild/compilers/mixins/intel.py +167 -0
  125. package/releng/meson/mesonbuild/compilers/mixins/islinker.py +120 -0
  126. package/releng/meson/mesonbuild/compilers/mixins/metrowerks.py +279 -0
  127. package/releng/meson/mesonbuild/compilers/mixins/pgi.py +88 -0
  128. package/releng/meson/mesonbuild/compilers/mixins/ti.py +130 -0
  129. package/releng/meson/mesonbuild/compilers/mixins/visualstudio.py +458 -0
  130. package/releng/meson/mesonbuild/compilers/mixins/xc16.py +111 -0
  131. package/releng/meson/mesonbuild/compilers/objc.py +120 -0
  132. package/releng/meson/mesonbuild/compilers/objcpp.py +102 -0
  133. package/releng/meson/mesonbuild/compilers/rust.py +230 -0
  134. package/releng/meson/mesonbuild/compilers/swift.py +131 -0
  135. package/releng/meson/mesonbuild/compilers/vala.py +121 -0
  136. package/releng/meson/mesonbuild/coredata.py +1532 -0
  137. package/releng/meson/mesonbuild/dependencies/__init__.py +252 -0
  138. package/releng/meson/mesonbuild/dependencies/base.py +663 -0
  139. package/releng/meson/mesonbuild/dependencies/boost.py +1083 -0
  140. package/releng/meson/mesonbuild/dependencies/cmake.py +656 -0
  141. package/releng/meson/mesonbuild/dependencies/coarrays.py +80 -0
  142. package/releng/meson/mesonbuild/dependencies/configtool.py +163 -0
  143. package/releng/meson/mesonbuild/dependencies/cuda.py +295 -0
  144. package/releng/meson/mesonbuild/dependencies/data/CMakeLists.txt +102 -0
  145. package/releng/meson/mesonbuild/dependencies/data/CMakeListsLLVM.txt +204 -0
  146. package/releng/meson/mesonbuild/dependencies/data/CMakePathInfo.txt +31 -0
  147. package/releng/meson/mesonbuild/dependencies/data/__init__.py +0 -0
  148. package/releng/meson/mesonbuild/dependencies/detect.py +225 -0
  149. package/releng/meson/mesonbuild/dependencies/dev.py +707 -0
  150. package/releng/meson/mesonbuild/dependencies/dub.py +424 -0
  151. package/releng/meson/mesonbuild/dependencies/factory.py +146 -0
  152. package/releng/meson/mesonbuild/dependencies/framework.py +111 -0
  153. package/releng/meson/mesonbuild/dependencies/hdf5.py +168 -0
  154. package/releng/meson/mesonbuild/dependencies/misc.py +618 -0
  155. package/releng/meson/mesonbuild/dependencies/mpi.py +231 -0
  156. package/releng/meson/mesonbuild/dependencies/pkgconfig.py +570 -0
  157. package/releng/meson/mesonbuild/dependencies/platform.py +52 -0
  158. package/releng/meson/mesonbuild/dependencies/python.py +431 -0
  159. package/releng/meson/mesonbuild/dependencies/qt.py +484 -0
  160. package/releng/meson/mesonbuild/dependencies/scalapack.py +142 -0
  161. package/releng/meson/mesonbuild/dependencies/ui.py +281 -0
  162. package/releng/meson/mesonbuild/depfile.py +82 -0
  163. package/releng/meson/mesonbuild/envconfig.py +480 -0
  164. package/releng/meson/mesonbuild/environment.py +987 -0
  165. package/releng/meson/mesonbuild/interpreter/__init__.py +47 -0
  166. package/releng/meson/mesonbuild/interpreter/compiler.py +900 -0
  167. package/releng/meson/mesonbuild/interpreter/dependencyfallbacks.py +386 -0
  168. package/releng/meson/mesonbuild/interpreter/interpreter.py +3595 -0
  169. package/releng/meson/mesonbuild/interpreter/interpreterobjects.py +1096 -0
  170. package/releng/meson/mesonbuild/interpreter/kwargs.py +479 -0
  171. package/releng/meson/mesonbuild/interpreter/mesonmain.py +487 -0
  172. package/releng/meson/mesonbuild/interpreter/primitives/__init__.py +29 -0
  173. package/releng/meson/mesonbuild/interpreter/primitives/array.py +108 -0
  174. package/releng/meson/mesonbuild/interpreter/primitives/boolean.py +52 -0
  175. package/releng/meson/mesonbuild/interpreter/primitives/dict.py +88 -0
  176. package/releng/meson/mesonbuild/interpreter/primitives/integer.py +86 -0
  177. package/releng/meson/mesonbuild/interpreter/primitives/range.py +38 -0
  178. package/releng/meson/mesonbuild/interpreter/primitives/string.py +247 -0
  179. package/releng/meson/mesonbuild/interpreter/type_checking.py +853 -0
  180. package/releng/meson/mesonbuild/interpreterbase/__init__.py +126 -0
  181. package/releng/meson/mesonbuild/interpreterbase/_unholder.py +25 -0
  182. package/releng/meson/mesonbuild/interpreterbase/baseobjects.py +174 -0
  183. package/releng/meson/mesonbuild/interpreterbase/decorators.py +806 -0
  184. package/releng/meson/mesonbuild/interpreterbase/disabler.py +35 -0
  185. package/releng/meson/mesonbuild/interpreterbase/exceptions.py +22 -0
  186. package/releng/meson/mesonbuild/interpreterbase/helpers.py +67 -0
  187. package/releng/meson/mesonbuild/interpreterbase/interpreterbase.py +665 -0
  188. package/releng/meson/mesonbuild/interpreterbase/operator.py +32 -0
  189. package/releng/meson/mesonbuild/linkers/__init__.py +20 -0
  190. package/releng/meson/mesonbuild/linkers/base.py +39 -0
  191. package/releng/meson/mesonbuild/linkers/detect.py +229 -0
  192. package/releng/meson/mesonbuild/linkers/linkers.py +1614 -0
  193. package/releng/meson/mesonbuild/mcompile.py +380 -0
  194. package/releng/meson/mesonbuild/mconf.py +368 -0
  195. package/releng/meson/mesonbuild/mdevenv.py +234 -0
  196. package/releng/meson/mesonbuild/mdist.py +376 -0
  197. package/releng/meson/mesonbuild/mesondata.py +38 -0
  198. package/releng/meson/mesonbuild/mesonlib.py +23 -0
  199. package/releng/meson/mesonbuild/mesonmain.py +289 -0
  200. package/releng/meson/mesonbuild/minit.py +204 -0
  201. package/releng/meson/mesonbuild/minstall.py +864 -0
  202. package/releng/meson/mesonbuild/mintro.py +667 -0
  203. package/releng/meson/mesonbuild/mlog.py +542 -0
  204. package/releng/meson/mesonbuild/modules/__init__.py +270 -0
  205. package/releng/meson/mesonbuild/modules/cmake.py +442 -0
  206. package/releng/meson/mesonbuild/modules/cuda.py +377 -0
  207. package/releng/meson/mesonbuild/modules/dlang.py +117 -0
  208. package/releng/meson/mesonbuild/modules/external_project.py +306 -0
  209. package/releng/meson/mesonbuild/modules/fs.py +323 -0
  210. package/releng/meson/mesonbuild/modules/gnome.py +2215 -0
  211. package/releng/meson/mesonbuild/modules/hotdoc.py +487 -0
  212. package/releng/meson/mesonbuild/modules/i18n.py +405 -0
  213. package/releng/meson/mesonbuild/modules/icestorm.py +123 -0
  214. package/releng/meson/mesonbuild/modules/java.py +112 -0
  215. package/releng/meson/mesonbuild/modules/keyval.py +65 -0
  216. package/releng/meson/mesonbuild/modules/modtest.py +33 -0
  217. package/releng/meson/mesonbuild/modules/pkgconfig.py +744 -0
  218. package/releng/meson/mesonbuild/modules/python.py +556 -0
  219. package/releng/meson/mesonbuild/modules/python3.py +85 -0
  220. package/releng/meson/mesonbuild/modules/qt.py +621 -0
  221. package/releng/meson/mesonbuild/modules/qt4.py +23 -0
  222. package/releng/meson/mesonbuild/modules/qt5.py +23 -0
  223. package/releng/meson/mesonbuild/modules/qt6.py +22 -0
  224. package/releng/meson/mesonbuild/modules/rust.py +355 -0
  225. package/releng/meson/mesonbuild/modules/simd.py +114 -0
  226. package/releng/meson/mesonbuild/modules/sourceset.py +291 -0
  227. package/releng/meson/mesonbuild/modules/wayland.py +151 -0
  228. package/releng/meson/mesonbuild/modules/windows.py +207 -0
  229. package/releng/meson/mesonbuild/mparser.py +1114 -0
  230. package/releng/meson/mesonbuild/msetup.py +365 -0
  231. package/releng/meson/mesonbuild/msubprojects.py +764 -0
  232. package/releng/meson/mesonbuild/mtest.py +2201 -0
  233. package/releng/meson/mesonbuild/munstable_coredata.py +107 -0
  234. package/releng/meson/mesonbuild/optinterpreter.py +276 -0
  235. package/releng/meson/mesonbuild/programs.py +367 -0
  236. package/releng/meson/mesonbuild/rewriter.py +1075 -0
  237. package/releng/meson/mesonbuild/scripts/__init__.py +10 -0
  238. package/releng/meson/mesonbuild/scripts/clangformat.py +55 -0
  239. package/releng/meson/mesonbuild/scripts/clangtidy.py +30 -0
  240. package/releng/meson/mesonbuild/scripts/cleantrees.py +35 -0
  241. package/releng/meson/mesonbuild/scripts/cmake_run_ctgt.py +103 -0
  242. package/releng/meson/mesonbuild/scripts/cmd_or_ps.ps1 +17 -0
  243. package/releng/meson/mesonbuild/scripts/copy.py +19 -0
  244. package/releng/meson/mesonbuild/scripts/coverage.py +214 -0
  245. package/releng/meson/mesonbuild/scripts/delwithsuffix.py +27 -0
  246. package/releng/meson/mesonbuild/scripts/depfixer.py +495 -0
  247. package/releng/meson/mesonbuild/scripts/depscan.py +198 -0
  248. package/releng/meson/mesonbuild/scripts/dirchanger.py +20 -0
  249. package/releng/meson/mesonbuild/scripts/env2mfile.py +402 -0
  250. package/releng/meson/mesonbuild/scripts/externalproject.py +106 -0
  251. package/releng/meson/mesonbuild/scripts/gettext.py +86 -0
  252. package/releng/meson/mesonbuild/scripts/gtkdochelper.py +286 -0
  253. package/releng/meson/mesonbuild/scripts/hotdochelper.py +40 -0
  254. package/releng/meson/mesonbuild/scripts/itstool.py +77 -0
  255. package/releng/meson/mesonbuild/scripts/meson_exe.py +115 -0
  256. package/releng/meson/mesonbuild/scripts/msgfmthelper.py +29 -0
  257. package/releng/meson/mesonbuild/scripts/pycompile.py +54 -0
  258. package/releng/meson/mesonbuild/scripts/python_info.py +121 -0
  259. package/releng/meson/mesonbuild/scripts/regen_checker.py +55 -0
  260. package/releng/meson/mesonbuild/scripts/run_tool.py +58 -0
  261. package/releng/meson/mesonbuild/scripts/scanbuild.py +57 -0
  262. package/releng/meson/mesonbuild/scripts/symbolextractor.py +322 -0
  263. package/releng/meson/mesonbuild/scripts/tags.py +44 -0
  264. package/releng/meson/mesonbuild/scripts/test_loaded_modules.py +14 -0
  265. package/releng/meson/mesonbuild/scripts/uninstall.py +41 -0
  266. package/releng/meson/mesonbuild/scripts/vcstagger.py +35 -0
  267. package/releng/meson/mesonbuild/scripts/yasm.py +24 -0
  268. package/releng/meson/mesonbuild/templates/__init__.py +0 -0
  269. package/releng/meson/mesonbuild/templates/cpptemplates.py +143 -0
  270. package/releng/meson/mesonbuild/templates/cstemplates.py +90 -0
  271. package/releng/meson/mesonbuild/templates/ctemplates.py +126 -0
  272. package/releng/meson/mesonbuild/templates/cudatemplates.py +143 -0
  273. package/releng/meson/mesonbuild/templates/dlangtemplates.py +109 -0
  274. package/releng/meson/mesonbuild/templates/fortrantemplates.py +101 -0
  275. package/releng/meson/mesonbuild/templates/javatemplates.py +94 -0
  276. package/releng/meson/mesonbuild/templates/mesontemplates.py +70 -0
  277. package/releng/meson/mesonbuild/templates/objcpptemplates.py +126 -0
  278. package/releng/meson/mesonbuild/templates/objctemplates.py +126 -0
  279. package/releng/meson/mesonbuild/templates/rusttemplates.py +79 -0
  280. package/releng/meson/mesonbuild/templates/samplefactory.py +41 -0
  281. package/releng/meson/mesonbuild/templates/sampleimpl.py +160 -0
  282. package/releng/meson/mesonbuild/templates/valatemplates.py +82 -0
  283. package/releng/meson/mesonbuild/utils/__init__.py +0 -0
  284. package/releng/meson/mesonbuild/utils/core.py +166 -0
  285. package/releng/meson/mesonbuild/utils/platform.py +27 -0
  286. package/releng/meson/mesonbuild/utils/posix.py +32 -0
  287. package/releng/meson/mesonbuild/utils/universal.py +2445 -0
  288. package/releng/meson/mesonbuild/utils/vsenv.py +126 -0
  289. package/releng/meson/mesonbuild/utils/win32.py +29 -0
  290. package/releng/meson/mesonbuild/wrap/__init__.py +59 -0
  291. package/releng/meson/mesonbuild/wrap/wrap.py +846 -0
  292. package/releng/meson/mesonbuild/wrap/wraptool.py +198 -0
  293. package/releng/meson-scripts/BSDmakefile +6 -0
  294. package/releng/meson-scripts/Makefile +16 -0
  295. package/releng/meson-scripts/configure +18 -0
  296. package/releng/meson-scripts/configure.bat +22 -0
  297. package/releng/meson-scripts/make.bat +23 -0
  298. package/releng/meson_configure.py +506 -0
  299. package/releng/meson_make.py +131 -0
  300. package/releng/mkdevkit.py +107 -0
  301. package/releng/mkfatmacho.py +54 -0
  302. package/releng/post-process-oabi.py +97 -0
  303. package/releng/progress.py +14 -0
  304. package/releng/sync-from-upstream.py +185 -0
  305. package/releng/tomlkit/tomlkit/__init__.py +59 -0
  306. package/releng/tomlkit/tomlkit/_compat.py +22 -0
  307. package/releng/tomlkit/tomlkit/_types.py +83 -0
  308. package/releng/tomlkit/tomlkit/_utils.py +158 -0
  309. package/releng/tomlkit/tomlkit/api.py +308 -0
  310. package/releng/tomlkit/tomlkit/container.py +875 -0
  311. package/releng/tomlkit/tomlkit/exceptions.py +227 -0
  312. package/releng/tomlkit/tomlkit/items.py +1967 -0
  313. package/releng/tomlkit/tomlkit/parser.py +1141 -0
  314. package/releng/tomlkit/tomlkit/py.typed +0 -0
  315. package/releng/tomlkit/tomlkit/source.py +180 -0
  316. package/releng/tomlkit/tomlkit/toml_char.py +52 -0
  317. package/releng/tomlkit/tomlkit/toml_document.py +7 -0
  318. package/releng/tomlkit/tomlkit/toml_file.py +58 -0
  319. package/releng/winenv.py +140 -0
  320. package/scripts/adjust-version.py +19 -0
  321. package/scripts/detect-version.py +40 -0
  322. package/scripts/fetch-abi-bits.py +343 -0
  323. package/scripts/install.js +23 -0
  324. package/scripts/package.py +15 -0
  325. package/src/addon.cc +76 -0
  326. package/src/application.cc +148 -0
  327. package/src/application.h +31 -0
  328. package/src/authentication.cc +174 -0
  329. package/src/authentication.h +24 -0
  330. package/src/bus.cc +167 -0
  331. package/src/bus.h +33 -0
  332. package/src/cancellable.cc +117 -0
  333. package/src/cancellable.h +31 -0
  334. package/src/child.cc +150 -0
  335. package/src/child.h +32 -0
  336. package/src/crash.cc +122 -0
  337. package/src/crash.h +30 -0
  338. package/src/device.cc +1302 -0
  339. package/src/device.h +55 -0
  340. package/src/device_manager.cc +362 -0
  341. package/src/device_manager.h +35 -0
  342. package/src/endpoint_parameters.cc +171 -0
  343. package/src/endpoint_parameters.h +28 -0
  344. package/src/glib_context.cc +62 -0
  345. package/src/glib_context.h +29 -0
  346. package/src/glib_object.cc +25 -0
  347. package/src/glib_object.h +37 -0
  348. package/src/iostream.cc +247 -0
  349. package/src/iostream.h +30 -0
  350. package/src/meson.build +26 -0
  351. package/src/operation.h +94 -0
  352. package/src/portal_membership.cc +100 -0
  353. package/src/portal_membership.h +26 -0
  354. package/src/portal_service.cc +401 -0
  355. package/src/portal_service.h +40 -0
  356. package/src/process.cc +135 -0
  357. package/src/process.h +30 -0
  358. package/src/relay.cc +139 -0
  359. package/src/relay.h +31 -0
  360. package/src/runtime.cc +443 -0
  361. package/src/runtime.h +64 -0
  362. package/src/script.cc +301 -0
  363. package/src/script.h +36 -0
  364. package/src/session.cc +860 -0
  365. package/src/session.h +42 -0
  366. package/src/signals.cc +334 -0
  367. package/src/signals.h +47 -0
  368. package/src/spawn.cc +95 -0
  369. package/src/spawn.h +27 -0
  370. package/src/usage_monitor.h +117 -0
  371. package/src/uv_context.cc +118 -0
  372. package/src/uv_context.h +40 -0
  373. package/src/win_delay_load_hook.cc +63 -0
  374. package/subprojects/frida-core.wrap +8 -0
  375. package/subprojects/nan.wrap +9 -0
  376. package/subprojects/packagefiles/nan.patch +13 -0
  377. package/test/data/index.ts +13 -0
  378. package/test/data/unixvictim-linux-x86 +0 -0
  379. package/test/data/unixvictim-linux-x86_64 +0 -0
  380. package/test/data/unixvictim-macos +0 -0
  381. package/test/device.ts +27 -0
  382. package/test/device_manager.ts +16 -0
  383. package/test/labrat.ts +32 -0
  384. package/test/script.ts +176 -0
  385. package/test/session.ts +73 -0
  386. package/tsconfig.json +18 -0
@@ -0,0 +1,846 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ # Copyright 2015 The Meson development team
3
+
4
+ from __future__ import annotations
5
+
6
+ from .. import mlog
7
+ import contextlib
8
+ from dataclasses import dataclass
9
+ import urllib.request
10
+ import urllib.error
11
+ import urllib.parse
12
+ import os
13
+ import hashlib
14
+ import shutil
15
+ import tempfile
16
+ import stat
17
+ import subprocess
18
+ import sys
19
+ import configparser
20
+ import time
21
+ import typing as T
22
+ import textwrap
23
+ import json
24
+
25
+ from base64 import b64encode
26
+ from netrc import netrc
27
+ from pathlib import Path, PurePath
28
+ from functools import lru_cache
29
+
30
+ from . import WrapMode
31
+ from .. import coredata
32
+ from ..mesonlib import quiet_git, GIT, ProgressBar, MesonException, windows_proof_rmtree, Popen_safe
33
+ from ..interpreterbase import FeatureNew
34
+ from ..interpreterbase import SubProject
35
+ from .. import mesonlib
36
+
37
+ if T.TYPE_CHECKING:
38
+ import http.client
39
+ from typing_extensions import Literal
40
+
41
+ Method = Literal['meson', 'cmake', 'cargo']
42
+
43
+ try:
44
+ # Importing is just done to check if SSL exists, so all warnings
45
+ # regarding 'imported but unused' can be safely ignored
46
+ import ssl # noqa
47
+ has_ssl = True
48
+ except ImportError:
49
+ has_ssl = False
50
+
51
+ REQ_TIMEOUT = 30.0
52
+ WHITELIST_SUBDOMAIN = 'wrapdb.mesonbuild.com'
53
+
54
+ ALL_TYPES = ['file', 'git', 'hg', 'svn']
55
+
56
+ PATCH = shutil.which('patch')
57
+
58
+ def whitelist_wrapdb(urlstr: str) -> urllib.parse.ParseResult:
59
+ """ raises WrapException if not whitelisted subdomain """
60
+ url = urllib.parse.urlparse(urlstr)
61
+ if not url.hostname:
62
+ raise WrapException(f'{urlstr} is not a valid URL')
63
+ if not url.hostname.endswith(WHITELIST_SUBDOMAIN):
64
+ raise WrapException(f'{urlstr} is not a whitelisted WrapDB URL')
65
+ if has_ssl and not url.scheme == 'https':
66
+ raise WrapException(f'WrapDB did not have expected SSL https url, instead got {urlstr}')
67
+ return url
68
+
69
+ def open_wrapdburl(urlstring: str, allow_insecure: bool = False, have_opt: bool = False) -> 'http.client.HTTPResponse':
70
+ if have_opt:
71
+ insecure_msg = '\n\n To allow connecting anyway, pass `--allow-insecure`.'
72
+ else:
73
+ insecure_msg = ''
74
+
75
+ url = whitelist_wrapdb(urlstring)
76
+ if has_ssl:
77
+ try:
78
+ return T.cast('http.client.HTTPResponse', urllib.request.urlopen(urllib.parse.urlunparse(url), timeout=REQ_TIMEOUT))
79
+ except urllib.error.URLError as excp:
80
+ msg = f'WrapDB connection failed to {urlstring} with error {excp}.'
81
+ if isinstance(excp.reason, ssl.SSLCertVerificationError):
82
+ if allow_insecure:
83
+ mlog.warning(f'{msg}\n\n Proceeding without authentication.')
84
+ else:
85
+ raise WrapException(f'{msg}{insecure_msg}')
86
+ else:
87
+ raise WrapException(msg)
88
+ elif not allow_insecure:
89
+ raise WrapException(f'SSL module not available in {sys.executable}: Cannot contact the WrapDB.{insecure_msg}')
90
+ else:
91
+ # following code is only for those without Python SSL
92
+ mlog.warning(f'SSL module not available in {sys.executable}: WrapDB traffic not authenticated.', once=True)
93
+
94
+ # If we got this far, allow_insecure was manually passed
95
+ nossl_url = url._replace(scheme='http')
96
+ try:
97
+ return T.cast('http.client.HTTPResponse', urllib.request.urlopen(urllib.parse.urlunparse(nossl_url), timeout=REQ_TIMEOUT))
98
+ except urllib.error.URLError as excp:
99
+ raise WrapException(f'WrapDB connection failed to {urlstring} with error {excp}')
100
+
101
+ def get_releases_data(allow_insecure: bool) -> bytes:
102
+ url = open_wrapdburl('https://wrapdb.mesonbuild.com/v2/releases.json', allow_insecure, True)
103
+ return url.read()
104
+
105
+ @lru_cache(maxsize=None)
106
+ def get_releases(allow_insecure: bool) -> T.Dict[str, T.Any]:
107
+ data = get_releases_data(allow_insecure)
108
+ return T.cast('T.Dict[str, T.Any]', json.loads(data.decode()))
109
+
110
+ def update_wrap_file(wrapfile: str, name: str, new_version: str, new_revision: str, allow_insecure: bool) -> None:
111
+ url = open_wrapdburl(f'https://wrapdb.mesonbuild.com/v2/{name}_{new_version}-{new_revision}/{name}.wrap',
112
+ allow_insecure, True)
113
+ with open(wrapfile, 'wb') as f:
114
+ f.write(url.read())
115
+
116
+ def parse_patch_url(patch_url: str) -> T.Tuple[str, str]:
117
+ u = urllib.parse.urlparse(patch_url)
118
+ if u.netloc != 'wrapdb.mesonbuild.com':
119
+ raise WrapException(f'URL {patch_url} does not seems to be a wrapdb patch')
120
+ arr = u.path.strip('/').split('/')
121
+ if arr[0] == 'v1':
122
+ # e.g. https://wrapdb.mesonbuild.com/v1/projects/zlib/1.2.11/5/get_zip
123
+ return arr[-3], arr[-2]
124
+ elif arr[0] == 'v2':
125
+ # e.g. https://wrapdb.mesonbuild.com/v2/zlib_1.2.11-5/get_patch
126
+ tag = arr[-2]
127
+ _, version = tag.rsplit('_', 1)
128
+ version, revision = version.rsplit('-', 1)
129
+ return version, revision
130
+ else:
131
+ raise WrapException(f'Invalid wrapdb URL {patch_url}')
132
+
133
+ class WrapException(MesonException):
134
+ pass
135
+
136
+ class WrapNotFoundException(WrapException):
137
+ pass
138
+
139
+ class PackageDefinition:
140
+ def __init__(self, fname: str, subproject: str = ''):
141
+ self.filename = fname
142
+ self.subproject = SubProject(subproject)
143
+ self.type: T.Optional[str] = None
144
+ self.values: T.Dict[str, str] = {}
145
+ self.provided_deps: T.Dict[str, T.Optional[str]] = {}
146
+ self.provided_programs: T.List[str] = []
147
+ self.diff_files: T.List[Path] = []
148
+ self.basename = os.path.basename(fname)
149
+ self.has_wrap = self.basename.endswith('.wrap')
150
+ self.name = self.basename[:-5] if self.has_wrap else self.basename
151
+ # must be lowercase for consistency with dep=variable assignment
152
+ self.provided_deps[self.name.lower()] = None
153
+ # What the original file name was before redirection
154
+ self.original_filename = fname
155
+ self.redirected = False
156
+ if self.has_wrap:
157
+ self.parse_wrap()
158
+ with open(fname, 'r', encoding='utf-8') as file:
159
+ self.wrapfile_hash = hashlib.sha256(file.read().encode('utf-8')).hexdigest()
160
+ self.directory = self.values.get('directory', self.name)
161
+ if os.path.dirname(self.directory):
162
+ raise WrapException('Directory key must be a name and not a path')
163
+ if self.type and self.type not in ALL_TYPES:
164
+ raise WrapException(f'Unknown wrap type {self.type!r}')
165
+ self.filesdir = os.path.join(os.path.dirname(self.filename), 'packagefiles')
166
+
167
+ def parse_wrap(self) -> None:
168
+ try:
169
+ config = configparser.ConfigParser(interpolation=None)
170
+ config.read(self.filename, encoding='utf-8')
171
+ except configparser.Error as e:
172
+ raise WrapException(f'Failed to parse {self.basename}: {e!s}')
173
+ self.parse_wrap_section(config)
174
+ if self.type == 'redirect':
175
+ # [wrap-redirect] have a `filename` value pointing to the real wrap
176
+ # file we should parse instead. It must be relative to the current
177
+ # wrap file location and must be in the form foo/subprojects/bar.wrap.
178
+ dirname = Path(self.filename).parent
179
+ fname = Path(self.values['filename'])
180
+ for i, p in enumerate(fname.parts):
181
+ if i % 2 == 0:
182
+ if p == '..':
183
+ raise WrapException('wrap-redirect filename cannot contain ".."')
184
+ else:
185
+ if p != 'subprojects':
186
+ raise WrapException('wrap-redirect filename must be in the form foo/subprojects/bar.wrap')
187
+ if fname.suffix != '.wrap':
188
+ raise WrapException('wrap-redirect filename must be a .wrap file')
189
+ fname = dirname / fname
190
+ if not fname.is_file():
191
+ raise WrapException(f'wrap-redirect {fname} filename does not exist')
192
+ self.filename = str(fname)
193
+ self.parse_wrap()
194
+ self.redirected = True
195
+ else:
196
+ self.parse_provide_section(config)
197
+ if 'patch_directory' in self.values:
198
+ FeatureNew('Wrap files with patch_directory', '0.55.0').use(self.subproject)
199
+ for what in ['patch', 'source']:
200
+ if f'{what}_filename' in self.values and f'{what}_url' not in self.values:
201
+ FeatureNew(f'Local wrap patch files without {what}_url', '0.55.0').use(self.subproject)
202
+
203
+ def parse_wrap_section(self, config: configparser.ConfigParser) -> None:
204
+ if len(config.sections()) < 1:
205
+ raise WrapException(f'Missing sections in {self.basename}')
206
+ self.wrap_section = config.sections()[0]
207
+ if not self.wrap_section.startswith('wrap-'):
208
+ raise WrapException(f'{self.wrap_section!r} is not a valid first section in {self.basename}')
209
+ self.type = self.wrap_section[5:]
210
+ self.values = dict(config[self.wrap_section])
211
+ if 'diff_files' in self.values:
212
+ FeatureNew('Wrap files with diff_files', '0.63.0').use(self.subproject)
213
+ for s in self.values['diff_files'].split(','):
214
+ path = Path(s.strip())
215
+ if path.is_absolute():
216
+ raise WrapException('diff_files paths cannot be absolute')
217
+ if '..' in path.parts:
218
+ raise WrapException('diff_files paths cannot contain ".."')
219
+ self.diff_files.append(path)
220
+
221
+ def parse_provide_section(self, config: configparser.ConfigParser) -> None:
222
+ if config.has_section('provides'):
223
+ raise WrapException('Unexpected "[provides]" section, did you mean "[provide]"?')
224
+ if config.has_section('provide'):
225
+ for k, v in config['provide'].items():
226
+ if k == 'dependency_names':
227
+ # A comma separated list of dependency names that does not
228
+ # need a variable name; must be lowercase for consistency with
229
+ # dep=variable assignment
230
+ names_dict = {n.strip().lower(): None for n in v.split(',')}
231
+ self.provided_deps.update(names_dict)
232
+ continue
233
+ if k == 'program_names':
234
+ # A comma separated list of program names
235
+ names_list = [n.strip() for n in v.split(',')]
236
+ self.provided_programs += names_list
237
+ continue
238
+ if not v:
239
+ m = (f'Empty dependency variable name for {k!r} in {self.basename}. '
240
+ 'If the subproject uses meson.override_dependency() '
241
+ 'it can be added in the "dependency_names" special key.')
242
+ raise WrapException(m)
243
+ self.provided_deps[k] = v
244
+
245
+ def get(self, key: str) -> str:
246
+ try:
247
+ return self.values[key]
248
+ except KeyError:
249
+ raise WrapException(f'Missing key {key!r} in {self.basename}')
250
+
251
+ def get_hashfile(self, subproject_directory: str) -> str:
252
+ return os.path.join(subproject_directory, '.meson-subproject-wrap-hash.txt')
253
+
254
+ def update_hash_cache(self, subproject_directory: str) -> None:
255
+ if self.has_wrap:
256
+ with open(self.get_hashfile(subproject_directory), 'w', encoding='utf-8') as file:
257
+ file.write(self.wrapfile_hash + '\n')
258
+
259
+ def get_directory(subdir_root: str, packagename: str) -> str:
260
+ fname = os.path.join(subdir_root, packagename + '.wrap')
261
+ if os.path.isfile(fname):
262
+ wrap = PackageDefinition(fname)
263
+ return wrap.directory
264
+ return packagename
265
+
266
+ def verbose_git(cmd: T.List[str], workingdir: str, check: bool = False) -> bool:
267
+ '''
268
+ Wrapper to convert GitException to WrapException caught in interpreter.
269
+ '''
270
+ try:
271
+ return mesonlib.verbose_git(cmd, workingdir, check=check)
272
+ except mesonlib.GitException as e:
273
+ raise WrapException(str(e))
274
+
275
+ @dataclass(eq=False)
276
+ class Resolver:
277
+ source_dir: str
278
+ subdir: str
279
+ subproject: str = ''
280
+ wrap_mode: WrapMode = WrapMode.default
281
+ wrap_frontend: bool = False
282
+ allow_insecure: bool = False
283
+ silent: bool = False
284
+
285
+ def __post_init__(self) -> None:
286
+ self.subdir_root = os.path.join(self.source_dir, self.subdir)
287
+ self.cachedir = os.environ.get('MESON_PACKAGE_CACHE_DIR') or os.path.join(self.subdir_root, 'packagecache')
288
+ self.wraps: T.Dict[str, PackageDefinition] = {}
289
+ self.netrc: T.Optional[netrc] = None
290
+ self.provided_deps: T.Dict[str, PackageDefinition] = {}
291
+ self.provided_programs: T.Dict[str, PackageDefinition] = {}
292
+ self.wrapdb: T.Dict[str, T.Any] = {}
293
+ self.wrapdb_provided_deps: T.Dict[str, str] = {}
294
+ self.wrapdb_provided_programs: T.Dict[str, str] = {}
295
+ self.load_wraps()
296
+ self.load_netrc()
297
+ self.load_wrapdb()
298
+
299
+ def load_netrc(self) -> None:
300
+ try:
301
+ self.netrc = netrc()
302
+ except FileNotFoundError:
303
+ return
304
+ except Exception as e:
305
+ mlog.warning(f'failed to process netrc file: {e}.', fatal=False)
306
+
307
+ def load_wraps(self) -> None:
308
+ if not os.path.isdir(self.subdir_root):
309
+ return
310
+ root, dirs, files = next(os.walk(self.subdir_root))
311
+ ignore_dirs = {'packagecache', 'packagefiles'}
312
+ for i in files:
313
+ if not i.endswith('.wrap'):
314
+ continue
315
+ fname = os.path.join(self.subdir_root, i)
316
+ wrap = PackageDefinition(fname, self.subproject)
317
+ self.wraps[wrap.name] = wrap
318
+ ignore_dirs |= {wrap.directory, wrap.name}
319
+ # Add dummy package definition for directories not associated with a wrap file.
320
+ for i in dirs:
321
+ if i in ignore_dirs:
322
+ continue
323
+ fname = os.path.join(self.subdir_root, i)
324
+ wrap = PackageDefinition(fname, self.subproject)
325
+ self.wraps[wrap.name] = wrap
326
+
327
+ for wrap in self.wraps.values():
328
+ self.add_wrap(wrap)
329
+
330
+ def add_wrap(self, wrap: PackageDefinition) -> None:
331
+ for k in wrap.provided_deps.keys():
332
+ if k in self.provided_deps:
333
+ prev_wrap = self.provided_deps[k]
334
+ m = f'Multiple wrap files provide {k!r} dependency: {wrap.basename} and {prev_wrap.basename}'
335
+ raise WrapException(m)
336
+ self.provided_deps[k] = wrap
337
+ for k in wrap.provided_programs:
338
+ if k in self.provided_programs:
339
+ prev_wrap = self.provided_programs[k]
340
+ m = f'Multiple wrap files provide {k!r} program: {wrap.basename} and {prev_wrap.basename}'
341
+ raise WrapException(m)
342
+ self.provided_programs[k] = wrap
343
+
344
+ def load_wrapdb(self) -> None:
345
+ try:
346
+ with Path(self.subdir_root, 'wrapdb.json').open('r', encoding='utf-8') as f:
347
+ self.wrapdb = json.load(f)
348
+ except FileNotFoundError:
349
+ return
350
+ for name, info in self.wrapdb.items():
351
+ self.wrapdb_provided_deps.update({i: name for i in info.get('dependency_names', [])})
352
+ self.wrapdb_provided_programs.update({i: name for i in info.get('program_names', [])})
353
+
354
+ def get_from_wrapdb(self, subp_name: str) -> T.Optional[PackageDefinition]:
355
+ info = self.wrapdb.get(subp_name)
356
+ if not info:
357
+ return None
358
+ self.check_can_download()
359
+ latest_version = info['versions'][0]
360
+ version, revision = latest_version.rsplit('-', 1)
361
+ url = urllib.request.urlopen(f'https://wrapdb.mesonbuild.com/v2/{subp_name}_{version}-{revision}/{subp_name}.wrap')
362
+ fname = Path(self.subdir_root, f'{subp_name}.wrap')
363
+ with fname.open('wb') as f:
364
+ f.write(url.read())
365
+ mlog.log(f'Installed {subp_name} version {version} revision {revision}')
366
+ wrap = PackageDefinition(str(fname))
367
+ self.wraps[wrap.name] = wrap
368
+ self.add_wrap(wrap)
369
+ return wrap
370
+
371
+ def merge_wraps(self, other_resolver: 'Resolver') -> None:
372
+ for k, v in other_resolver.wraps.items():
373
+ self.wraps.setdefault(k, v)
374
+ for k, v in other_resolver.provided_deps.items():
375
+ self.provided_deps.setdefault(k, v)
376
+ for k, v in other_resolver.provided_programs.items():
377
+ self.provided_programs.setdefault(k, v)
378
+
379
+ def find_dep_provider(self, packagename: str) -> T.Tuple[T.Optional[str], T.Optional[str]]:
380
+ # Python's ini parser converts all key values to lowercase.
381
+ # Thus the query name must also be in lower case.
382
+ packagename = packagename.lower()
383
+ wrap = self.provided_deps.get(packagename)
384
+ if wrap:
385
+ dep_var = wrap.provided_deps.get(packagename)
386
+ return wrap.name, dep_var
387
+ wrap_name = self.wrapdb_provided_deps.get(packagename)
388
+ return wrap_name, None
389
+
390
+ def get_varname(self, subp_name: str, depname: str) -> T.Optional[str]:
391
+ wrap = self.wraps.get(subp_name)
392
+ return wrap.provided_deps.get(depname) if wrap else None
393
+
394
+ def find_program_provider(self, names: T.List[str]) -> T.Optional[str]:
395
+ for name in names:
396
+ wrap = self.provided_programs.get(name)
397
+ if wrap:
398
+ return wrap.name
399
+ wrap_name = self.wrapdb_provided_programs.get(name)
400
+ if wrap_name:
401
+ return wrap_name
402
+ return None
403
+
404
+ def resolve(self, packagename: str, force_method: T.Optional[Method] = None) -> T.Tuple[str, Method]:
405
+ wrap = self.wraps.get(packagename)
406
+ if wrap is None:
407
+ wrap = self.get_from_wrapdb(packagename)
408
+ if wrap is None:
409
+ raise WrapNotFoundException(f'Neither a subproject directory nor a {packagename}.wrap file was found.')
410
+ self.wrap = wrap
411
+ self.directory = self.wrap.directory
412
+
413
+ if self.wrap.has_wrap:
414
+ # We have a .wrap file, use directory relative to the location of
415
+ # the wrap file if it exists, otherwise source code will be placed
416
+ # into main project's subproject_dir even if the wrap file comes
417
+ # from another subproject.
418
+ self.dirname = os.path.join(os.path.dirname(self.wrap.filename), self.wrap.directory)
419
+ if not os.path.exists(self.dirname):
420
+ self.dirname = os.path.join(self.subdir_root, self.directory)
421
+ # Check if the wrap comes from the main project.
422
+ main_fname = os.path.join(self.subdir_root, self.wrap.basename)
423
+ if self.wrap.filename != main_fname:
424
+ rel = os.path.relpath(self.wrap.filename, self.source_dir)
425
+ mlog.log('Using', mlog.bold(rel))
426
+ # Write a dummy wrap file in main project that redirect to the
427
+ # wrap we picked.
428
+ with open(main_fname, 'w', encoding='utf-8') as f:
429
+ f.write(textwrap.dedent(f'''\
430
+ [wrap-redirect]
431
+ filename = {PurePath(os.path.relpath(self.wrap.filename, self.subdir_root)).as_posix()}
432
+ '''))
433
+ else:
434
+ # No wrap file, it's a dummy package definition for an existing
435
+ # directory. Use the source code in place.
436
+ self.dirname = self.wrap.filename
437
+ rel_path = os.path.relpath(self.dirname, self.source_dir)
438
+
439
+ # Map each supported method to a file that must exist at the root of source tree.
440
+ methods_map: T.Dict[Method, str] = {
441
+ 'meson': 'meson.build',
442
+ 'cmake': 'CMakeLists.txt',
443
+ 'cargo': 'Cargo.toml',
444
+ }
445
+
446
+ # Check if this wrap forces a specific method, use meson otherwise.
447
+ method = T.cast('T.Optional[Method]', self.wrap.values.get('method', force_method))
448
+ if method and method not in methods_map:
449
+ allowed_methods = ', '.join(methods_map.keys())
450
+ raise WrapException(f'Wrap method {method!r} is not supported, must be one of: {allowed_methods}')
451
+ if force_method and method != force_method:
452
+ raise WrapException(f'Wrap method is {method!r} but we are trying to configure it with {force_method}')
453
+ method = method or 'meson'
454
+
455
+ def has_buildfile() -> bool:
456
+ return os.path.exists(os.path.join(self.dirname, methods_map[method]))
457
+
458
+ # The directory is there and has meson.build? Great, use it.
459
+ if has_buildfile():
460
+ self.validate()
461
+ return rel_path, method
462
+
463
+ # Check if the subproject is a git submodule
464
+ self.resolve_git_submodule()
465
+
466
+ if os.path.exists(self.dirname):
467
+ if not os.path.isdir(self.dirname):
468
+ raise WrapException('Path already exists but is not a directory')
469
+ else:
470
+ # Check first if we have the extracted directory in our cache. This can
471
+ # happen for example when MESON_PACKAGE_CACHE_DIR=/usr/share/cargo/registry
472
+ # on distros that ships Rust source code.
473
+ # TODO: We don't currently clone git repositories into the cache
474
+ # directory, but we should to avoid cloning multiple times the same
475
+ # repository. In that case, we could do something smarter than
476
+ # copy_tree() here.
477
+ cached_directory = os.path.join(self.cachedir, self.directory)
478
+ if os.path.isdir(cached_directory):
479
+ self.copy_tree(cached_directory, self.dirname)
480
+ elif self.wrap.type == 'file':
481
+ self._get_file(packagename)
482
+ else:
483
+ self.check_can_download()
484
+ if self.wrap.type == 'git':
485
+ self._get_git(packagename)
486
+ elif self.wrap.type == "hg":
487
+ self._get_hg()
488
+ elif self.wrap.type == "svn":
489
+ self._get_svn()
490
+ else:
491
+ raise WrapException(f'Unknown wrap type {self.wrap.type!r}')
492
+ try:
493
+ self.apply_patch(packagename)
494
+ self.apply_diff_files()
495
+ except Exception:
496
+ windows_proof_rmtree(self.dirname)
497
+ raise
498
+
499
+ if not has_buildfile():
500
+ raise WrapException(f'Subproject exists but has no {methods_map[method]} file.')
501
+
502
+ # At this point, the subproject has been successfully resolved for the
503
+ # first time so save off the hash of the entire wrap file for future
504
+ # reference.
505
+ self.wrap.update_hash_cache(self.dirname)
506
+ return rel_path, method
507
+
508
+ def check_can_download(self) -> None:
509
+ # Don't download subproject data based on wrap file if requested.
510
+ # Git submodules are ok (see above)!
511
+ if self.wrap_mode is WrapMode.nodownload:
512
+ m = 'Automatic wrap-based subproject downloading is disabled'
513
+ raise WrapException(m)
514
+
515
+ def resolve_git_submodule(self) -> bool:
516
+ # Is git installed? If not, we're probably not in a git repository and
517
+ # definitely cannot try to conveniently set up a submodule.
518
+ if not GIT:
519
+ return False
520
+ # Does the directory exist? Even uninitialised submodules checkout an
521
+ # empty directory to work in
522
+ if not os.path.isdir(self.dirname):
523
+ return False
524
+ # Are we in a git repository?
525
+ ret, out = quiet_git(['rev-parse'], Path(self.dirname).parent)
526
+ if not ret:
527
+ return False
528
+ # Is `dirname` a submodule?
529
+ ret, out = quiet_git(['submodule', 'status', '.'], self.dirname)
530
+ if not ret:
531
+ return False
532
+ # Submodule has not been added, add it
533
+ if out.startswith('+'):
534
+ mlog.warning('git submodule might be out of date')
535
+ return True
536
+ elif out.startswith('U'):
537
+ raise WrapException('git submodule has merge conflicts')
538
+ # Submodule exists, but is deinitialized or wasn't initialized
539
+ elif out.startswith('-'):
540
+ if verbose_git(['submodule', 'update', '--init', '.'], self.dirname):
541
+ return True
542
+ raise WrapException('git submodule failed to init')
543
+ # Submodule looks fine, but maybe it wasn't populated properly. Do a checkout.
544
+ elif out.startswith(' '):
545
+ verbose_git(['submodule', 'update', '.'], self.dirname)
546
+ verbose_git(['checkout', '.'], self.dirname)
547
+ # Even if checkout failed, try building it anyway and let the user
548
+ # handle any problems manually.
549
+ return True
550
+ elif out == '':
551
+ # It is not a submodule, just a folder that exists in the main repository.
552
+ return False
553
+ raise WrapException(f'Unknown git submodule output: {out!r}')
554
+
555
+ def _get_file(self, packagename: str) -> None:
556
+ path = self._get_file_internal('source', packagename)
557
+ extract_dir = self.subdir_root
558
+ # Some upstreams ship packages that do not have a leading directory.
559
+ # Create one for them.
560
+ if 'lead_directory_missing' in self.wrap.values:
561
+ os.mkdir(self.dirname)
562
+ extract_dir = self.dirname
563
+ try:
564
+ shutil.unpack_archive(path, extract_dir)
565
+ except OSError as e:
566
+ raise WrapException(f'failed to unpack archive with error: {str(e)}') from e
567
+
568
+ def _get_git(self, packagename: str) -> None:
569
+ if not GIT:
570
+ raise WrapException(f'Git program not found, cannot download {packagename}.wrap via git.')
571
+ revno = self.wrap.get('revision')
572
+ checkout_cmd = ['-c', 'advice.detachedHead=false', 'checkout', revno, '--']
573
+ is_shallow = False
574
+ depth_option: T.List[str] = []
575
+ if self.wrap.values.get('depth', '') != '':
576
+ is_shallow = True
577
+ depth_option = ['--depth', self.wrap.values.get('depth')]
578
+ # for some reason git only allows commit ids to be shallowly fetched by fetch not with clone
579
+ if is_shallow and self.is_git_full_commit_id(revno):
580
+ # git doesn't support directly cloning shallowly for commits,
581
+ # so we follow https://stackoverflow.com/a/43136160
582
+ verbose_git(['-c', 'init.defaultBranch=meson-dummy-branch', 'init', self.directory], self.subdir_root, check=True)
583
+ verbose_git(['remote', 'add', 'origin', self.wrap.get('url')], self.dirname, check=True)
584
+ revno = self.wrap.get('revision')
585
+ verbose_git(['fetch', *depth_option, 'origin', revno], self.dirname, check=True)
586
+ verbose_git(checkout_cmd, self.dirname, check=True)
587
+ else:
588
+ if not is_shallow:
589
+ verbose_git(['clone', self.wrap.get('url'), self.directory], self.subdir_root, check=True)
590
+ if revno.lower() != 'head':
591
+ if not verbose_git(checkout_cmd, self.dirname):
592
+ verbose_git(['fetch', self.wrap.get('url'), revno], self.dirname, check=True)
593
+ verbose_git(checkout_cmd, self.dirname, check=True)
594
+ else:
595
+ args = ['-c', 'advice.detachedHead=false', 'clone', *depth_option]
596
+ if revno.lower() != 'head':
597
+ args += ['--branch', revno]
598
+ args += [self.wrap.get('url'), self.directory]
599
+ verbose_git(args, self.subdir_root, check=True)
600
+ if self.wrap.values.get('clone-recursive', '').lower() == 'true':
601
+ verbose_git(['submodule', 'update', '--init', '--checkout', '--recursive', *depth_option],
602
+ self.dirname, check=True)
603
+ push_url = self.wrap.values.get('push-url')
604
+ if push_url:
605
+ verbose_git(['remote', 'set-url', '--push', 'origin', push_url], self.dirname, check=True)
606
+
607
+ def validate(self) -> None:
608
+ # This check is only for subprojects with wraps.
609
+ if not self.wrap.has_wrap:
610
+ return
611
+
612
+ # Retrieve original hash, if it exists.
613
+ hashfile = self.wrap.get_hashfile(self.dirname)
614
+ if os.path.isfile(hashfile):
615
+ with open(hashfile, 'r', encoding='utf-8') as file:
616
+ expected_hash = file.read().strip()
617
+ else:
618
+ # If stored hash doesn't exist then don't warn.
619
+ return
620
+
621
+ actual_hash = self.wrap.wrapfile_hash
622
+
623
+ # Compare hashes and warn the user if they don't match.
624
+ if expected_hash != actual_hash:
625
+ mlog.warning(f'Subproject {self.wrap.name}\'s revision may be out of date; its wrap file has changed since it was first configured')
626
+
627
+ def is_git_full_commit_id(self, revno: str) -> bool:
628
+ result = False
629
+ if len(revno) in {40, 64}: # 40 for sha1, 64 for upcoming sha256
630
+ result = all(ch in '0123456789AaBbCcDdEeFf' for ch in revno)
631
+ return result
632
+
633
+ def _get_hg(self) -> None:
634
+ revno = self.wrap.get('revision')
635
+ hg = shutil.which('hg')
636
+ if not hg:
637
+ raise WrapException('Mercurial program not found.')
638
+ subprocess.check_call([hg, 'clone', self.wrap.get('url'),
639
+ self.directory], cwd=self.subdir_root)
640
+ if revno.lower() != 'tip':
641
+ subprocess.check_call([hg, 'checkout', revno],
642
+ cwd=self.dirname)
643
+
644
+ def _get_svn(self) -> None:
645
+ revno = self.wrap.get('revision')
646
+ svn = shutil.which('svn')
647
+ if not svn:
648
+ raise WrapException('SVN program not found.')
649
+ subprocess.check_call([svn, 'checkout', '-r', revno, self.wrap.get('url'),
650
+ self.directory], cwd=self.subdir_root)
651
+
652
+ def get_netrc_credentials(self, netloc: str) -> T.Optional[T.Tuple[str, str]]:
653
+ if self.netrc is None or netloc not in self.netrc.hosts:
654
+ return None
655
+
656
+ login, account, password = self.netrc.authenticators(netloc)
657
+ if account is not None:
658
+ login = account
659
+
660
+ return login, password
661
+
662
+ def get_data(self, urlstring: str) -> T.Tuple[str, str]:
663
+ blocksize = 10 * 1024
664
+ h = hashlib.sha256()
665
+ tmpfile = tempfile.NamedTemporaryFile(mode='wb', dir=self.cachedir, delete=False)
666
+ url = urllib.parse.urlparse(urlstring)
667
+ if url.hostname and url.hostname.endswith(WHITELIST_SUBDOMAIN):
668
+ resp = open_wrapdburl(urlstring, allow_insecure=self.allow_insecure, have_opt=self.wrap_frontend)
669
+ elif WHITELIST_SUBDOMAIN in urlstring:
670
+ raise WrapException(f'{urlstring} may be a WrapDB-impersonating URL')
671
+ else:
672
+ headers = {'User-Agent': f'mesonbuild/{coredata.version}'}
673
+ creds = self.get_netrc_credentials(url.netloc)
674
+
675
+ if creds is not None and '@' not in url.netloc:
676
+ login, password = creds
677
+ if url.scheme == 'https':
678
+ enc_creds = b64encode(f'{login}:{password}'.encode()).decode()
679
+ headers.update({'Authorization': f'Basic {enc_creds}'})
680
+ elif url.scheme == 'ftp':
681
+ urlstring = urllib.parse.urlunparse(url._replace(netloc=f'{login}:{password}@{url.netloc}'))
682
+ else:
683
+ mlog.warning('Meson is not going to use netrc credentials for protocols other than https/ftp',
684
+ fatal=False)
685
+
686
+ try:
687
+ req = urllib.request.Request(urlstring, headers=headers)
688
+ resp = urllib.request.urlopen(req, timeout=REQ_TIMEOUT)
689
+ except urllib.error.URLError as e:
690
+ mlog.log(str(e))
691
+ raise WrapException(f'could not get {urlstring} is the internet available?')
692
+ with contextlib.closing(resp) as resp, tmpfile as tmpfile:
693
+ try:
694
+ dlsize = int(resp.info()['Content-Length'])
695
+ except TypeError:
696
+ dlsize = None
697
+ if dlsize is None:
698
+ print('Downloading file of unknown size.')
699
+ while True:
700
+ block = resp.read(blocksize)
701
+ if block == b'':
702
+ break
703
+ h.update(block)
704
+ tmpfile.write(block)
705
+ hashvalue = h.hexdigest()
706
+ return hashvalue, tmpfile.name
707
+ sys.stdout.flush()
708
+ progress_bar = ProgressBar(bar_type='download', total=dlsize,
709
+ desc='Downloading',
710
+ disable=(self.silent or None))
711
+ while True:
712
+ block = resp.read(blocksize)
713
+ if block == b'':
714
+ break
715
+ h.update(block)
716
+ tmpfile.write(block)
717
+ progress_bar.update(len(block))
718
+ progress_bar.close()
719
+ hashvalue = h.hexdigest()
720
+ return hashvalue, tmpfile.name
721
+
722
+ def check_hash(self, what: str, path: str, hash_required: bool = True) -> None:
723
+ if what + '_hash' not in self.wrap.values and not hash_required:
724
+ return
725
+ expected = self.wrap.get(what + '_hash').lower()
726
+ h = hashlib.sha256()
727
+ with open(path, 'rb') as f:
728
+ h.update(f.read())
729
+ dhash = h.hexdigest()
730
+ if dhash != expected:
731
+ raise WrapException(f'Incorrect hash for {what}:\n {expected} expected\n {dhash} actual.')
732
+
733
+ def get_data_with_backoff(self, urlstring: str) -> T.Tuple[str, str]:
734
+ delays = [1, 2, 4, 8, 16]
735
+ for d in delays:
736
+ try:
737
+ return self.get_data(urlstring)
738
+ except Exception as e:
739
+ mlog.warning(f'failed to download with error: {e}. Trying after a delay...', fatal=False)
740
+ time.sleep(d)
741
+ return self.get_data(urlstring)
742
+
743
+ def _download(self, what: str, ofname: str, packagename: str, fallback: bool = False) -> None:
744
+ self.check_can_download()
745
+ srcurl = self.wrap.get(what + ('_fallback_url' if fallback else '_url'))
746
+ mlog.log('Downloading', mlog.bold(packagename), what, 'from', mlog.bold(srcurl))
747
+ try:
748
+ dhash, tmpfile = self.get_data_with_backoff(srcurl)
749
+ expected = self.wrap.get(what + '_hash').lower()
750
+ if dhash != expected:
751
+ os.remove(tmpfile)
752
+ raise WrapException(f'Incorrect hash for {what}:\n {expected} expected\n {dhash} actual.')
753
+ except WrapException:
754
+ if not fallback:
755
+ if what + '_fallback_url' in self.wrap.values:
756
+ return self._download(what, ofname, packagename, fallback=True)
757
+ mlog.log('A fallback URL could be specified using',
758
+ mlog.bold(what + '_fallback_url'), 'key in the wrap file')
759
+ raise
760
+ os.rename(tmpfile, ofname)
761
+
762
+ def _get_file_internal(self, what: str, packagename: str) -> str:
763
+ filename = self.wrap.get(what + '_filename')
764
+ if what + '_url' in self.wrap.values:
765
+ cache_path = os.path.join(self.cachedir, filename)
766
+
767
+ if os.path.exists(cache_path):
768
+ self.check_hash(what, cache_path)
769
+ mlog.log('Using', mlog.bold(packagename), what, 'from cache.')
770
+ return cache_path
771
+
772
+ os.makedirs(self.cachedir, exist_ok=True)
773
+ self._download(what, cache_path, packagename)
774
+ return cache_path
775
+ else:
776
+ path = Path(self.wrap.filesdir) / filename
777
+
778
+ if not path.exists():
779
+ raise WrapException(f'File "{path}" does not exist')
780
+ self.check_hash(what, path.as_posix(), hash_required=False)
781
+
782
+ return path.as_posix()
783
+
784
+ def apply_patch(self, packagename: str) -> None:
785
+ if 'patch_filename' in self.wrap.values and 'patch_directory' in self.wrap.values:
786
+ m = f'Wrap file {self.wrap.basename!r} must not have both "patch_filename" and "patch_directory"'
787
+ raise WrapException(m)
788
+ if 'patch_filename' in self.wrap.values:
789
+ path = self._get_file_internal('patch', packagename)
790
+ try:
791
+ shutil.unpack_archive(path, self.subdir_root)
792
+ except Exception:
793
+ with tempfile.TemporaryDirectory() as workdir:
794
+ shutil.unpack_archive(path, workdir)
795
+ self.copy_tree(workdir, self.subdir_root)
796
+ elif 'patch_directory' in self.wrap.values:
797
+ patch_dir = self.wrap.values['patch_directory']
798
+ src_dir = os.path.join(self.wrap.filesdir, patch_dir)
799
+ if not os.path.isdir(src_dir):
800
+ raise WrapException(f'patch directory does not exist: {patch_dir}')
801
+ self.copy_tree(src_dir, self.dirname)
802
+
803
+ def apply_diff_files(self) -> None:
804
+ for filename in self.wrap.diff_files:
805
+ mlog.log(f'Applying diff file "{filename}"')
806
+ path = Path(self.wrap.filesdir) / filename
807
+ if not path.exists():
808
+ raise WrapException(f'Diff file "{path}" does not exist')
809
+ relpath = os.path.relpath(str(path), self.dirname)
810
+ if PATCH:
811
+ # Always pass a POSIX path to patch, because on Windows it's MSYS
812
+ # Ignore whitespace when applying patches to workaround
813
+ # line-ending differences
814
+ cmd = [PATCH, '-l', '-f', '-p1', '-i', str(Path(relpath).as_posix())]
815
+ elif GIT:
816
+ # If the `patch` command is not available, fall back to `git
817
+ # apply`. The `--work-tree` is necessary in case we're inside a
818
+ # Git repository: by default, Git will try to apply the patch to
819
+ # the repository root.
820
+ cmd = [GIT, '--work-tree', '.', 'apply', '--ignore-whitespace', '-p1', relpath]
821
+ else:
822
+ raise WrapException('Missing "patch" or "git" commands to apply diff files')
823
+
824
+ p, out, _ = Popen_safe(cmd, cwd=self.dirname, stderr=subprocess.STDOUT)
825
+ if p.returncode != 0:
826
+ mlog.log(out.strip())
827
+ raise WrapException(f'Failed to apply diff file "{filename}"')
828
+
829
+ def copy_tree(self, root_src_dir: str, root_dst_dir: str) -> None:
830
+ """
831
+ Copy directory tree. Overwrites also read only files.
832
+ """
833
+ for src_dir, _, files in os.walk(root_src_dir):
834
+ dst_dir = src_dir.replace(root_src_dir, root_dst_dir, 1)
835
+ if not os.path.exists(dst_dir):
836
+ os.makedirs(dst_dir)
837
+ for file_ in files:
838
+ src_file = os.path.join(src_dir, file_)
839
+ dst_file = os.path.join(dst_dir, file_)
840
+ if os.path.exists(dst_file):
841
+ try:
842
+ os.remove(dst_file)
843
+ except PermissionError:
844
+ os.chmod(dst_file, stat.S_IWUSR)
845
+ os.remove(dst_file)
846
+ shutil.copy2(src_file, dst_dir)