Nuitka-winsvc 2.7.7__cp313-cp313-win_amd64.whl

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.

Potentially problematic release.


This version of Nuitka-winsvc might be problematic. Click here for more details.

Files changed (995) hide show
  1. nuitka/Builtins.py +259 -0
  2. nuitka/BytecodeCaching.py +184 -0
  3. nuitka/Bytecodes.py +109 -0
  4. nuitka/CacheCleanup.py +54 -0
  5. nuitka/Constants.py +425 -0
  6. nuitka/Errors.py +93 -0
  7. nuitka/HardImportRegistry.py +408 -0
  8. nuitka/MainControl.py +1201 -0
  9. nuitka/ModuleRegistry.py +364 -0
  10. nuitka/OptionParsing.py +2473 -0
  11. nuitka/Options.py +2948 -0
  12. nuitka/OutputDirectories.py +201 -0
  13. nuitka/PostProcessing.py +551 -0
  14. nuitka/Progress.py +252 -0
  15. nuitka/PythonFlavors.py +426 -0
  16. nuitka/PythonOperators.py +146 -0
  17. nuitka/PythonVersions.py +513 -0
  18. nuitka/Serialization.py +291 -0
  19. nuitka/SourceCodeReferences.py +176 -0
  20. nuitka/Tracing.py +579 -0
  21. nuitka/TreeXML.py +141 -0
  22. nuitka/Variables.py +515 -0
  23. nuitka/Version.py +88 -0
  24. nuitka/__init__.py +19 -0
  25. nuitka/__main__.py +224 -0
  26. nuitka/__past__.py +217 -0
  27. nuitka/build/Backend.scons +1111 -0
  28. nuitka/build/CCompilerVersion.scons +281 -0
  29. nuitka/build/DataComposerInterface.py +116 -0
  30. nuitka/build/Offsets.scons +626 -0
  31. nuitka/build/Onefile.scons +564 -0
  32. nuitka/build/SconsCaching.py +451 -0
  33. nuitka/build/SconsCompilerSettings.py +1133 -0
  34. nuitka/build/SconsHacks.py +215 -0
  35. nuitka/build/SconsInterface.py +664 -0
  36. nuitka/build/SconsProgress.py +100 -0
  37. nuitka/build/SconsSpawn.py +436 -0
  38. nuitka/build/SconsUtils.py +939 -0
  39. nuitka/build/__init__.py +19 -0
  40. nuitka/build/include/nuitka/allocator.h +450 -0
  41. nuitka/build/include/nuitka/builtins.h +97 -0
  42. nuitka/build/include/nuitka/calling.h +123 -0
  43. nuitka/build/include/nuitka/checkers.h +39 -0
  44. nuitka/build/include/nuitka/checksum_tools.h +28 -0
  45. nuitka/build/include/nuitka/compiled_asyncgen.h +281 -0
  46. nuitka/build/include/nuitka/compiled_cell.h +64 -0
  47. nuitka/build/include/nuitka/compiled_coroutine.h +271 -0
  48. nuitka/build/include/nuitka/compiled_frame.h +502 -0
  49. nuitka/build/include/nuitka/compiled_function.h +170 -0
  50. nuitka/build/include/nuitka/compiled_generator.h +287 -0
  51. nuitka/build/include/nuitka/compiled_method.h +54 -0
  52. nuitka/build/include/nuitka/constants.h +251 -0
  53. nuitka/build/include/nuitka/constants_blob.h +34 -0
  54. nuitka/build/include/nuitka/debug_settings.h +60 -0
  55. nuitka/build/include/nuitka/environment_variables.h +30 -0
  56. nuitka/build/include/nuitka/environment_variables_system.h +51 -0
  57. nuitka/build/include/nuitka/exception_groups.h +167 -0
  58. nuitka/build/include/nuitka/exceptions.h +1458 -0
  59. nuitka/build/include/nuitka/filesystem_paths.h +117 -0
  60. nuitka/build/include/nuitka/freelists.h +92 -0
  61. nuitka/build/include/nuitka/hedley.h +1774 -0
  62. nuitka/build/include/nuitka/helper/attributes.h +90 -0
  63. nuitka/build/include/nuitka/helper/boolean.h +86 -0
  64. nuitka/build/include/nuitka/helper/bytearrays.h +34 -0
  65. nuitka/build/include/nuitka/helper/bytes.h +28 -0
  66. nuitka/build/include/nuitka/helper/calling_generated.h +132 -0
  67. nuitka/build/include/nuitka/helper/comparisons_dual_eq.h +47 -0
  68. nuitka/build/include/nuitka/helper/comparisons_dual_ge.h +39 -0
  69. nuitka/build/include/nuitka/helper/comparisons_dual_gt.h +39 -0
  70. nuitka/build/include/nuitka/helper/comparisons_dual_le.h +47 -0
  71. nuitka/build/include/nuitka/helper/comparisons_dual_lt.h +47 -0
  72. nuitka/build/include/nuitka/helper/comparisons_dual_ne.h +39 -0
  73. nuitka/build/include/nuitka/helper/comparisons_eq.h +247 -0
  74. nuitka/build/include/nuitka/helper/comparisons_ge.h +197 -0
  75. nuitka/build/include/nuitka/helper/comparisons_gt.h +197 -0
  76. nuitka/build/include/nuitka/helper/comparisons_le.h +247 -0
  77. nuitka/build/include/nuitka/helper/comparisons_lt.h +247 -0
  78. nuitka/build/include/nuitka/helper/comparisons_ne.h +197 -0
  79. nuitka/build/include/nuitka/helper/complex.h +46 -0
  80. nuitka/build/include/nuitka/helper/dictionaries.h +481 -0
  81. nuitka/build/include/nuitka/helper/floats.h +32 -0
  82. nuitka/build/include/nuitka/helper/import_hard.h +121 -0
  83. nuitka/build/include/nuitka/helper/indexes.h +47 -0
  84. nuitka/build/include/nuitka/helper/ints.h +165 -0
  85. nuitka/build/include/nuitka/helper/iterators.h +376 -0
  86. nuitka/build/include/nuitka/helper/lists.h +94 -0
  87. nuitka/build/include/nuitka/helper/lists_generated.h +36 -0
  88. nuitka/build/include/nuitka/helper/mappings.h +39 -0
  89. nuitka/build/include/nuitka/helper/operations.h +114 -0
  90. nuitka/build/include/nuitka/helper/operations_binary_add.h +240 -0
  91. nuitka/build/include/nuitka/helper/operations_binary_bitand.h +108 -0
  92. nuitka/build/include/nuitka/helper/operations_binary_bitor.h +108 -0
  93. nuitka/build/include/nuitka/helper/operations_binary_bitxor.h +108 -0
  94. nuitka/build/include/nuitka/helper/operations_binary_divmod.h +103 -0
  95. nuitka/build/include/nuitka/helper/operations_binary_dual_add.h +34 -0
  96. nuitka/build/include/nuitka/helper/operations_binary_floordiv.h +103 -0
  97. nuitka/build/include/nuitka/helper/operations_binary_lshift.h +99 -0
  98. nuitka/build/include/nuitka/helper/operations_binary_matmult.h +60 -0
  99. nuitka/build/include/nuitka/helper/operations_binary_mod.h +304 -0
  100. nuitka/build/include/nuitka/helper/operations_binary_mult.h +247 -0
  101. nuitka/build/include/nuitka/helper/operations_binary_olddiv.h +125 -0
  102. nuitka/build/include/nuitka/helper/operations_binary_pow.h +90 -0
  103. nuitka/build/include/nuitka/helper/operations_binary_rshift.h +99 -0
  104. nuitka/build/include/nuitka/helper/operations_binary_sub.h +117 -0
  105. nuitka/build/include/nuitka/helper/operations_binary_truediv.h +103 -0
  106. nuitka/build/include/nuitka/helper/operations_builtin_types.h +247 -0
  107. nuitka/build/include/nuitka/helper/operations_inplace_add.h +173 -0
  108. nuitka/build/include/nuitka/helper/operations_inplace_bitand.h +76 -0
  109. nuitka/build/include/nuitka/helper/operations_inplace_bitor.h +76 -0
  110. nuitka/build/include/nuitka/helper/operations_inplace_bitxor.h +76 -0
  111. nuitka/build/include/nuitka/helper/operations_inplace_floordiv.h +95 -0
  112. nuitka/build/include/nuitka/helper/operations_inplace_lshift.h +62 -0
  113. nuitka/build/include/nuitka/helper/operations_inplace_matmult.h +60 -0
  114. nuitka/build/include/nuitka/helper/operations_inplace_mod.h +218 -0
  115. nuitka/build/include/nuitka/helper/operations_inplace_mult.h +184 -0
  116. nuitka/build/include/nuitka/helper/operations_inplace_olddiv.h +115 -0
  117. nuitka/build/include/nuitka/helper/operations_inplace_pow.h +87 -0
  118. nuitka/build/include/nuitka/helper/operations_inplace_rshift.h +62 -0
  119. nuitka/build/include/nuitka/helper/operations_inplace_sub.h +102 -0
  120. nuitka/build/include/nuitka/helper/operations_inplace_truediv.h +95 -0
  121. nuitka/build/include/nuitka/helper/raising.h +114 -0
  122. nuitka/build/include/nuitka/helper/rangeobjects.h +66 -0
  123. nuitka/build/include/nuitka/helper/richcomparisons.h +35 -0
  124. nuitka/build/include/nuitka/helper/sequences.h +33 -0
  125. nuitka/build/include/nuitka/helper/sets.h +25 -0
  126. nuitka/build/include/nuitka/helper/slices.h +314 -0
  127. nuitka/build/include/nuitka/helper/strings.h +30 -0
  128. nuitka/build/include/nuitka/helper/subscripts.h +390 -0
  129. nuitka/build/include/nuitka/helper/tuples.h +187 -0
  130. nuitka/build/include/nuitka/helpers.h +417 -0
  131. nuitka/build/include/nuitka/importing.h +149 -0
  132. nuitka/build/include/nuitka/incbin.h +402 -0
  133. nuitka/build/include/nuitka/jit_sources.h +25 -0
  134. nuitka/build/include/nuitka/prelude.h +626 -0
  135. nuitka/build/include/nuitka/printing.h +84 -0
  136. nuitka/build/include/nuitka/python_pgo.h +57 -0
  137. nuitka/build/include/nuitka/safe_string_ops.h +57 -0
  138. nuitka/build/include/nuitka/threading.h +142 -0
  139. nuitka/build/include/nuitka/tracing.h +82 -0
  140. nuitka/build/include/nuitka/type_aliases.h +30 -0
  141. nuitka/build/include/nuitka/unfreezing.h +91 -0
  142. nuitka/build/inline_copy/appdirs/LICENSE.txt +23 -0
  143. nuitka/build/inline_copy/appdirs/appdirs.py +611 -0
  144. nuitka/build/inline_copy/atomicwrites/LICENSE +19 -0
  145. nuitka/build/inline_copy/atomicwrites/atomicwrites.py +226 -0
  146. nuitka/build/inline_copy/bin/scons.py +58 -0
  147. nuitka/build/inline_copy/clcache/clcache/LICENSE +30 -0
  148. nuitka/build/inline_copy/clcache/clcache/__init__.py +4 -0
  149. nuitka/build/inline_copy/clcache/clcache/caching.py +2008 -0
  150. nuitka/build/inline_copy/colorama/LICENSE.txt +27 -0
  151. nuitka/build/inline_copy/colorama/colorama/__init__.py +6 -0
  152. nuitka/build/inline_copy/colorama/colorama/ansi.py +102 -0
  153. nuitka/build/inline_copy/colorama/colorama/ansitowin32.py +258 -0
  154. nuitka/build/inline_copy/colorama/colorama/initialise.py +80 -0
  155. nuitka/build/inline_copy/colorama/colorama/win32.py +152 -0
  156. nuitka/build/inline_copy/colorama/colorama/winterm.py +169 -0
  157. nuitka/build/inline_copy/glob2/LICENSE +27 -0
  158. nuitka/build/inline_copy/glob2/glob2/__init__.py +5 -0
  159. nuitka/build/inline_copy/glob2/glob2/compat.py +167 -0
  160. nuitka/build/inline_copy/glob2/glob2/fnmatch.py +141 -0
  161. nuitka/build/inline_copy/glob2/glob2/impl.py +216 -0
  162. nuitka/build/inline_copy/jinja2/LICENSE.rst +28 -0
  163. nuitka/build/inline_copy/jinja2/README.rst +2 -0
  164. nuitka/build/inline_copy/jinja2/jinja2/__init__.py +72 -0
  165. nuitka/build/inline_copy/jinja2/jinja2/_compat.py +105 -0
  166. nuitka/build/inline_copy/jinja2/jinja2/_identifier.py +2 -0
  167. nuitka/build/inline_copy/jinja2/jinja2/bccache.py +361 -0
  168. nuitka/build/inline_copy/jinja2/jinja2/compiler.py +1721 -0
  169. nuitka/build/inline_copy/jinja2/jinja2/constants.py +32 -0
  170. nuitka/build/inline_copy/jinja2/jinja2/debug.py +378 -0
  171. nuitka/build/inline_copy/jinja2/jinja2/defaults.py +56 -0
  172. nuitka/build/inline_copy/jinja2/jinja2/environment.py +1276 -0
  173. nuitka/build/inline_copy/jinja2/jinja2/exceptions.py +146 -0
  174. nuitka/build/inline_copy/jinja2/jinja2/ext.py +627 -0
  175. nuitka/build/inline_copy/jinja2/jinja2/filters.py +1190 -0
  176. nuitka/build/inline_copy/jinja2/jinja2/idtracking.py +286 -0
  177. nuitka/build/inline_copy/jinja2/jinja2/lexer.py +739 -0
  178. nuitka/build/inline_copy/jinja2/jinja2/loaders.py +483 -0
  179. nuitka/build/inline_copy/jinja2/jinja2/meta.py +106 -0
  180. nuitka/build/inline_copy/jinja2/jinja2/nativetypes.py +220 -0
  181. nuitka/build/inline_copy/jinja2/jinja2/nodes.py +999 -0
  182. nuitka/build/inline_copy/jinja2/jinja2/optimizer.py +49 -0
  183. nuitka/build/inline_copy/jinja2/jinja2/parser.py +903 -0
  184. nuitka/build/inline_copy/jinja2/jinja2/runtime.py +808 -0
  185. nuitka/build/inline_copy/jinja2/jinja2/sandbox.py +488 -0
  186. nuitka/build/inline_copy/jinja2/jinja2/tests.py +174 -0
  187. nuitka/build/inline_copy/jinja2/jinja2/utils.py +642 -0
  188. nuitka/build/inline_copy/jinja2/jinja2/visitor.py +87 -0
  189. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Action.py +1475 -0
  190. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Builder.py +905 -0
  191. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/CacheDir.py +314 -0
  192. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Conftest.py +805 -0
  193. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Debug.py +251 -0
  194. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Defaults.py +646 -0
  195. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Environment.py +2561 -0
  196. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/EnvironmentValues.py +119 -0
  197. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Errors.py +222 -0
  198. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Executor.py +660 -0
  199. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Job.py +439 -0
  200. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Memoize.py +242 -0
  201. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Node/Alias.py +176 -0
  202. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Node/FS.py +3861 -0
  203. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Node/Python.py +195 -0
  204. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Node/__init__.py +1784 -0
  205. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/PathList.py +224 -0
  206. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Platform/__init__.py +341 -0
  207. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Platform/aix.py +81 -0
  208. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Platform/cygwin.py +61 -0
  209. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Platform/darwin.py +70 -0
  210. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Platform/hpux.py +45 -0
  211. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Platform/irix.py +41 -0
  212. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Platform/mingw.py +33 -0
  213. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Platform/os2.py +55 -0
  214. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Platform/posix.py +124 -0
  215. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Platform/sunos.py +47 -0
  216. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Platform/virtualenv.py +115 -0
  217. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Platform/win32.py +429 -0
  218. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/SConf.py +1119 -0
  219. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/SConsign.py +453 -0
  220. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Scanner/C.py +226 -0
  221. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Scanner/Dir.py +131 -0
  222. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Scanner/Prog.py +114 -0
  223. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Scanner/RC.py +57 -0
  224. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Scanner/__init__.py +436 -0
  225. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Script/Interactive.py +372 -0
  226. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Script/Main.py +1469 -0
  227. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Script/SConsOptions.py +1071 -0
  228. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Script/SConscript.py +686 -0
  229. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Script/__init__.py +425 -0
  230. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Subst.py +979 -0
  231. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Taskmaster.py +1062 -0
  232. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/386asm.py +61 -0
  233. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/GettextCommon.py +429 -0
  234. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/MSCommon/__init__.py +52 -0
  235. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/MSCommon/arch.py +66 -0
  236. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/MSCommon/common.py +371 -0
  237. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/MSCommon/netframework.py +83 -0
  238. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/MSCommon/sdk.py +411 -0
  239. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/MSCommon/vc.py +994 -0
  240. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/MSCommon/vs.py +608 -0
  241. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/PharLapCommon.py +116 -0
  242. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/__init__.py +882 -0
  243. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/aixc++.py +43 -0
  244. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/aixcc.py +74 -0
  245. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/aixcxx.py +77 -0
  246. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/aixlink.py +78 -0
  247. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/applelink.py +209 -0
  248. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/ar.py +63 -0
  249. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/as.py +49 -0
  250. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/asm.py +78 -0
  251. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/bcc32.py +81 -0
  252. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/c++.py +44 -0
  253. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/cc.py +105 -0
  254. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/clang.py +91 -0
  255. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/clangCommon/__init__.py +18 -0
  256. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/clangxx.py +99 -0
  257. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/cxx.py +95 -0
  258. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/cyglink.py +212 -0
  259. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/default.py +50 -0
  260. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/filesystem.py +98 -0
  261. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/g++.py +45 -0
  262. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/gas.py +56 -0
  263. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/gcc.py +110 -0
  264. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/gettext_tool.py +69 -0
  265. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/gnulink.py +70 -0
  266. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/gxx.py +78 -0
  267. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/hpc++.py +45 -0
  268. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/hpcc.py +53 -0
  269. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/hpcxx.py +88 -0
  270. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/hplink.py +72 -0
  271. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/icc.py +59 -0
  272. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/icl.py +52 -0
  273. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/ilink.py +55 -0
  274. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/ilink32.py +60 -0
  275. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/install.py +510 -0
  276. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/intelc.py +617 -0
  277. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/link.py +72 -0
  278. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/linkCommon/LoadableModule.py +131 -0
  279. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/linkCommon/SharedLibrary.py +218 -0
  280. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/linkCommon/__init__.py +171 -0
  281. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/linkloc.py +112 -0
  282. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/m4.py +63 -0
  283. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/masm.py +77 -0
  284. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/mingw.py +232 -0
  285. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/msgfmt.py +132 -0
  286. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/msginit.py +137 -0
  287. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/msgmerge.py +125 -0
  288. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/mslib.py +73 -0
  289. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/mslink.py +339 -0
  290. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/mssdk.py +50 -0
  291. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/msvc.py +325 -0
  292. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/msvs.py +2116 -0
  293. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/mwcc.py +207 -0
  294. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/mwld.py +108 -0
  295. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/nasm.py +72 -0
  296. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/rmic.py +139 -0
  297. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/rpcgen.py +70 -0
  298. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/sgiar.py +68 -0
  299. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/sgic++.py +43 -0
  300. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/sgicc.py +53 -0
  301. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/sgicxx.py +61 -0
  302. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/sgilink.py +59 -0
  303. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/sunar.py +64 -0
  304. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/sunc++.py +45 -0
  305. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/suncc.py +58 -0
  306. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/suncxx.py +153 -0
  307. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/sunlink.py +79 -0
  308. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/tar.py +73 -0
  309. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/textfile.py +198 -0
  310. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/tlib.py +53 -0
  311. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/wix.py +104 -0
  312. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/xgettext.py +337 -0
  313. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Tool/zip.py +120 -0
  314. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Util.py +2134 -0
  315. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Utilities/ConfigureCache.py +171 -0
  316. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Utilities/__init__.py +0 -0
  317. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Utilities/sconsign.py +494 -0
  318. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Variables/BoolVariable.py +96 -0
  319. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Variables/EnumVariable.py +110 -0
  320. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Variables/ListVariable.py +152 -0
  321. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Variables/PackageVariable.py +107 -0
  322. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Variables/PathVariable.py +158 -0
  323. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Variables/__init__.py +334 -0
  324. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/Warnings.py +238 -0
  325. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/__init__.py +9 -0
  326. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/compat/__init__.py +104 -0
  327. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/compat/_scons_dbm.py +42 -0
  328. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/compat/win32.py +101 -0
  329. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/cpp.py +640 -0
  330. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/dblite.py +295 -0
  331. nuitka/build/inline_copy/lib/scons-4.3.0/SCons/exitfuncs.py +59 -0
  332. nuitka/build/inline_copy/markupsafe/LICENSE.rst +28 -0
  333. nuitka/build/inline_copy/markupsafe/markupsafe/__init__.py +327 -0
  334. nuitka/build/inline_copy/markupsafe/markupsafe/_compat.py +33 -0
  335. nuitka/build/inline_copy/markupsafe/markupsafe/_constants.py +264 -0
  336. nuitka/build/inline_copy/markupsafe/markupsafe/_native.py +69 -0
  337. nuitka/build/inline_copy/pefile/LICENSE.txt +21 -0
  338. nuitka/build/inline_copy/pefile/ordlookup/__init__.py +41 -0
  339. nuitka/build/inline_copy/pefile/ordlookup/oleaut32.py +400 -0
  340. nuitka/build/inline_copy/pefile/ordlookup/ws2_32.py +120 -0
  341. nuitka/build/inline_copy/pefile/pefile.py +8034 -0
  342. nuitka/build/inline_copy/pkg_resources/pkg_resources/__init__.py +3272 -0
  343. nuitka/build/inline_copy/pkg_resources/pkg_resources/py31compat.py +21 -0
  344. nuitka/build/inline_copy/python_hacl/LICENSE.txt +201 -0
  345. nuitka/build/inline_copy/python_hacl/hacl_312/Hacl_Hash_MD5.c +1430 -0
  346. nuitka/build/inline_copy/python_hacl/hacl_312/Hacl_Hash_MD5.h +66 -0
  347. nuitka/build/inline_copy/python_hacl/hacl_312/Hacl_Hash_SHA1.c +463 -0
  348. nuitka/build/inline_copy/python_hacl/hacl_312/Hacl_Hash_SHA1.h +66 -0
  349. nuitka/build/inline_copy/python_hacl/hacl_312/Hacl_Hash_SHA2.c +1273 -0
  350. nuitka/build/inline_copy/python_hacl/hacl_312/Hacl_Hash_SHA2.h +204 -0
  351. nuitka/build/inline_copy/python_hacl/hacl_312/Hacl_Hash_SHA3.c +734 -0
  352. nuitka/build/inline_copy/python_hacl/hacl_312/Hacl_Hash_SHA3.h +131 -0
  353. nuitka/build/inline_copy/python_hacl/hacl_312/Hacl_Streaming_Types.h +83 -0
  354. nuitka/build/inline_copy/python_hacl/hacl_312/include/krml/FStar_UInt128_Verified.h +346 -0
  355. nuitka/build/inline_copy/python_hacl/hacl_312/include/krml/FStar_UInt_8_16_32_64.h +107 -0
  356. nuitka/build/inline_copy/python_hacl/hacl_312/include/krml/fstar_uint128_struct_endianness.h +68 -0
  357. nuitka/build/inline_copy/python_hacl/hacl_312/include/krml/internal/target.h +293 -0
  358. nuitka/build/inline_copy/python_hacl/hacl_312/include/krml/lowstar_endianness.h +231 -0
  359. nuitka/build/inline_copy/python_hacl/hacl_312/include/krml/types.h +14 -0
  360. nuitka/build/inline_copy/python_hacl/hacl_312/internal/Hacl_Hash_MD5.h +56 -0
  361. nuitka/build/inline_copy/python_hacl/hacl_312/internal/Hacl_Hash_SHA1.h +56 -0
  362. nuitka/build/inline_copy/python_hacl/hacl_312/internal/Hacl_Hash_SHA2.h +164 -0
  363. nuitka/build/inline_copy/python_hacl/hacl_312/internal/Hacl_Hash_SHA3.h +65 -0
  364. nuitka/build/inline_copy/python_hacl/hacl_312/python_hacl_namespaces.h +89 -0
  365. nuitka/build/inline_copy/stubgen/astunparse.py +938 -0
  366. nuitka/build/inline_copy/stubgen/six.py +998 -0
  367. nuitka/build/inline_copy/stubgen/stubgen.py +484 -0
  368. nuitka/build/inline_copy/tqdm/tqdm/__init__.py +40 -0
  369. nuitka/build/inline_copy/tqdm/tqdm/_main.py +9 -0
  370. nuitka/build/inline_copy/tqdm/tqdm/_monitor.py +97 -0
  371. nuitka/build/inline_copy/tqdm/tqdm/_tqdm.py +9 -0
  372. nuitka/build/inline_copy/tqdm/tqdm/_tqdm_notebook.py +9 -0
  373. nuitka/build/inline_copy/tqdm/tqdm/_tqdm_pandas.py +24 -0
  374. nuitka/build/inline_copy/tqdm/tqdm/_utils.py +12 -0
  375. nuitka/build/inline_copy/tqdm/tqdm/auto.py +44 -0
  376. nuitka/build/inline_copy/tqdm/tqdm/autonotebook.py +28 -0
  377. nuitka/build/inline_copy/tqdm/tqdm/dask.py +46 -0
  378. nuitka/build/inline_copy/tqdm/tqdm/notebook.py +316 -0
  379. nuitka/build/inline_copy/tqdm/tqdm/std.py +1524 -0
  380. nuitka/build/inline_copy/tqdm/tqdm/tk.py +207 -0
  381. nuitka/build/inline_copy/tqdm/tqdm/utils.py +351 -0
  382. nuitka/build/inline_copy/tqdm/tqdm/version.py +2 -0
  383. nuitka/build/inline_copy/yaml/LICENSE +20 -0
  384. nuitka/build/inline_copy/yaml/yaml/__init__.py +427 -0
  385. nuitka/build/inline_copy/yaml/yaml/composer.py +139 -0
  386. nuitka/build/inline_copy/yaml/yaml/constructor.py +748 -0
  387. nuitka/build/inline_copy/yaml/yaml/cyaml.py +101 -0
  388. nuitka/build/inline_copy/yaml/yaml/dumper.py +62 -0
  389. nuitka/build/inline_copy/yaml/yaml/emitter.py +1137 -0
  390. nuitka/build/inline_copy/yaml/yaml/error.py +75 -0
  391. nuitka/build/inline_copy/yaml/yaml/events.py +86 -0
  392. nuitka/build/inline_copy/yaml/yaml/loader.py +63 -0
  393. nuitka/build/inline_copy/yaml/yaml/nodes.py +49 -0
  394. nuitka/build/inline_copy/yaml/yaml/parser.py +589 -0
  395. nuitka/build/inline_copy/yaml/yaml/reader.py +185 -0
  396. nuitka/build/inline_copy/yaml/yaml/representer.py +389 -0
  397. nuitka/build/inline_copy/yaml/yaml/resolver.py +227 -0
  398. nuitka/build/inline_copy/yaml/yaml/scanner.py +1435 -0
  399. nuitka/build/inline_copy/yaml/yaml/serializer.py +111 -0
  400. nuitka/build/inline_copy/yaml/yaml/tokens.py +104 -0
  401. nuitka/build/inline_copy/zlib/LICENSE +22 -0
  402. nuitka/build/inline_copy/zlib/crc32.c +1049 -0
  403. nuitka/build/inline_copy/zlib/crc32.h +9446 -0
  404. nuitka/build/inline_copy/zlib/zconf.h +551 -0
  405. nuitka/build/inline_copy/zlib/zlib.h +1938 -0
  406. nuitka/build/inline_copy/zlib/zutil.h +275 -0
  407. nuitka/build/inline_copy/zstd/LICENSE.txt +30 -0
  408. nuitka/build/inline_copy/zstd/common/bitstream.h +463 -0
  409. nuitka/build/inline_copy/zstd/common/compiler.h +288 -0
  410. nuitka/build/inline_copy/zstd/common/cpu.h +213 -0
  411. nuitka/build/inline_copy/zstd/common/debug.h +107 -0
  412. nuitka/build/inline_copy/zstd/common/entropy_common.c +360 -0
  413. nuitka/build/inline_copy/zstd/common/error_private.c +56 -0
  414. nuitka/build/inline_copy/zstd/common/error_private.h +80 -0
  415. nuitka/build/inline_copy/zstd/common/fse.h +715 -0
  416. nuitka/build/inline_copy/zstd/common/fse_decompress.c +393 -0
  417. nuitka/build/inline_copy/zstd/common/huf.h +361 -0
  418. nuitka/build/inline_copy/zstd/common/mem.h +426 -0
  419. nuitka/build/inline_copy/zstd/common/xxhash.c +826 -0
  420. nuitka/build/inline_copy/zstd/common/xxhash.h +285 -0
  421. nuitka/build/inline_copy/zstd/common/zstd_common.c +83 -0
  422. nuitka/build/inline_copy/zstd/common/zstd_deps.h +111 -0
  423. nuitka/build/inline_copy/zstd/common/zstd_errors.h +95 -0
  424. nuitka/build/inline_copy/zstd/common/zstd_internal.h +478 -0
  425. nuitka/build/inline_copy/zstd/decompress/huf_decompress.c +1350 -0
  426. nuitka/build/inline_copy/zstd/decompress/zstd_ddict.c +244 -0
  427. nuitka/build/inline_copy/zstd/decompress/zstd_ddict.h +44 -0
  428. nuitka/build/inline_copy/zstd/decompress/zstd_decompress.c +1930 -0
  429. nuitka/build/inline_copy/zstd/decompress/zstd_decompress_block.c +1540 -0
  430. nuitka/build/inline_copy/zstd/decompress/zstd_decompress_block.h +62 -0
  431. nuitka/build/inline_copy/zstd/decompress/zstd_decompress_internal.h +190 -0
  432. nuitka/build/inline_copy/zstd/zstd.h +2391 -0
  433. nuitka/build/static_src/CompiledAsyncgenType.c +2211 -0
  434. nuitka/build/static_src/CompiledCellType.c +300 -0
  435. nuitka/build/static_src/CompiledCodeHelpers.c +2160 -0
  436. nuitka/build/static_src/CompiledCoroutineType.c +1946 -0
  437. nuitka/build/static_src/CompiledFrameType.c +1337 -0
  438. nuitka/build/static_src/CompiledFunctionType.c +3320 -0
  439. nuitka/build/static_src/CompiledGeneratorType.c +1997 -0
  440. nuitka/build/static_src/CompiledGeneratorTypeUncompiledIntegration.c +2117 -0
  441. nuitka/build/static_src/CompiledMethodType.c +614 -0
  442. nuitka/build/static_src/GenerateHeadersMain.c +30 -0
  443. nuitka/build/static_src/HelpersAllocator.c +939 -0
  444. nuitka/build/static_src/HelpersAttributes.c +1241 -0
  445. nuitka/build/static_src/HelpersBuiltin.c +901 -0
  446. nuitka/build/static_src/HelpersBuiltinTypeMethods.c +3594 -0
  447. nuitka/build/static_src/HelpersBytes.c +107 -0
  448. nuitka/build/static_src/HelpersCalling.c +397 -0
  449. nuitka/build/static_src/HelpersCallingGenerated.c +14361 -0
  450. nuitka/build/static_src/HelpersChecksumTools.c +59 -0
  451. nuitka/build/static_src/HelpersClasses.c +91 -0
  452. nuitka/build/static_src/HelpersComparisonDualEq.c +183 -0
  453. nuitka/build/static_src/HelpersComparisonDualGe.c +121 -0
  454. nuitka/build/static_src/HelpersComparisonDualGt.c +121 -0
  455. nuitka/build/static_src/HelpersComparisonDualLe.c +183 -0
  456. nuitka/build/static_src/HelpersComparisonDualLt.c +183 -0
  457. nuitka/build/static_src/HelpersComparisonDualNe.c +121 -0
  458. nuitka/build/static_src/HelpersComparisonEq.c +12070 -0
  459. nuitka/build/static_src/HelpersComparisonEqUtils.c +169 -0
  460. nuitka/build/static_src/HelpersComparisonGe.c +11871 -0
  461. nuitka/build/static_src/HelpersComparisonGt.c +11855 -0
  462. nuitka/build/static_src/HelpersComparisonLe.c +11957 -0
  463. nuitka/build/static_src/HelpersComparisonLt.c +11941 -0
  464. nuitka/build/static_src/HelpersComparisonNe.c +11979 -0
  465. nuitka/build/static_src/HelpersConsole.c +124 -0
  466. nuitka/build/static_src/HelpersConstantsBlob.c +1487 -0
  467. nuitka/build/static_src/HelpersDeepcopy.c +636 -0
  468. nuitka/build/static_src/HelpersDictionaries.c +1739 -0
  469. nuitka/build/static_src/HelpersDictionariesGenerated.c +738 -0
  470. nuitka/build/static_src/HelpersDumpBacktraces.c +63 -0
  471. nuitka/build/static_src/HelpersEnvironmentVariables.c +65 -0
  472. nuitka/build/static_src/HelpersEnvironmentVariablesSystem.c +97 -0
  473. nuitka/build/static_src/HelpersExceptions.c +298 -0
  474. nuitka/build/static_src/HelpersFiles.c +353 -0
  475. nuitka/build/static_src/HelpersFilesystemPaths.c +1322 -0
  476. nuitka/build/static_src/HelpersFloats.c +92 -0
  477. nuitka/build/static_src/HelpersHeapStorage.c +68 -0
  478. nuitka/build/static_src/HelpersImport.c +506 -0
  479. nuitka/build/static_src/HelpersImportHard.c +526 -0
  480. nuitka/build/static_src/HelpersJitSources.c +48 -0
  481. nuitka/build/static_src/HelpersLists.c +899 -0
  482. nuitka/build/static_src/HelpersListsGenerated.c +564 -0
  483. nuitka/build/static_src/HelpersMappings.c +46 -0
  484. nuitka/build/static_src/HelpersMatching.c +192 -0
  485. nuitka/build/static_src/HelpersOperationBinaryAdd.c +6477 -0
  486. nuitka/build/static_src/HelpersOperationBinaryAddUtils.c +703 -0
  487. nuitka/build/static_src/HelpersOperationBinaryBitand.c +2738 -0
  488. nuitka/build/static_src/HelpersOperationBinaryBitor.c +2738 -0
  489. nuitka/build/static_src/HelpersOperationBinaryBitxor.c +2738 -0
  490. nuitka/build/static_src/HelpersOperationBinaryDivmod.c +2406 -0
  491. nuitka/build/static_src/HelpersOperationBinaryDivmodUtils.c +33 -0
  492. nuitka/build/static_src/HelpersOperationBinaryDualAdd.c +172 -0
  493. nuitka/build/static_src/HelpersOperationBinaryFloordiv.c +2422 -0
  494. nuitka/build/static_src/HelpersOperationBinaryInplaceAdd.c +220 -0
  495. nuitka/build/static_src/HelpersOperationBinaryLshift.c +2846 -0
  496. nuitka/build/static_src/HelpersOperationBinaryMatmult.c +453 -0
  497. nuitka/build/static_src/HelpersOperationBinaryMod.c +6549 -0
  498. nuitka/build/static_src/HelpersOperationBinaryMult.c +6438 -0
  499. nuitka/build/static_src/HelpersOperationBinaryMultUtils.c +125 -0
  500. nuitka/build/static_src/HelpersOperationBinaryOlddiv.c +2355 -0
  501. nuitka/build/static_src/HelpersOperationBinaryPow.c +2743 -0
  502. nuitka/build/static_src/HelpersOperationBinaryPowUtils.c +26 -0
  503. nuitka/build/static_src/HelpersOperationBinaryRshift.c +2706 -0
  504. nuitka/build/static_src/HelpersOperationBinarySub.c +2649 -0
  505. nuitka/build/static_src/HelpersOperationBinaryTruediv.c +2415 -0
  506. nuitka/build/static_src/HelpersOperationInplaceAdd.c +5211 -0
  507. nuitka/build/static_src/HelpersOperationInplaceAddUtils.c +144 -0
  508. nuitka/build/static_src/HelpersOperationInplaceBitand.c +1826 -0
  509. nuitka/build/static_src/HelpersOperationInplaceBitor.c +1826 -0
  510. nuitka/build/static_src/HelpersOperationInplaceBitxor.c +1826 -0
  511. nuitka/build/static_src/HelpersOperationInplaceFloordiv.c +2605 -0
  512. nuitka/build/static_src/HelpersOperationInplaceLshift.c +1594 -0
  513. nuitka/build/static_src/HelpersOperationInplaceMatmult.c +603 -0
  514. nuitka/build/static_src/HelpersOperationInplaceMod.c +4762 -0
  515. nuitka/build/static_src/HelpersOperationInplaceMult.c +4689 -0
  516. nuitka/build/static_src/HelpersOperationInplaceOlddiv.c +2553 -0
  517. nuitka/build/static_src/HelpersOperationInplacePow.c +2807 -0
  518. nuitka/build/static_src/HelpersOperationInplaceRshift.c +1534 -0
  519. nuitka/build/static_src/HelpersOperationInplaceSub.c +2894 -0
  520. nuitka/build/static_src/HelpersOperationInplaceTruediv.c +2612 -0
  521. nuitka/build/static_src/HelpersProfiling.c +104 -0
  522. nuitka/build/static_src/HelpersPythonPgo.c +113 -0
  523. nuitka/build/static_src/HelpersRaising.c +447 -0
  524. nuitka/build/static_src/HelpersSafeStrings.c +185 -0
  525. nuitka/build/static_src/HelpersSequences.c +134 -0
  526. nuitka/build/static_src/HelpersSlices.c +73 -0
  527. nuitka/build/static_src/HelpersStrings.c +998 -0
  528. nuitka/build/static_src/HelpersTuples.c +148 -0
  529. nuitka/build/static_src/HelpersTypes.c +329 -0
  530. nuitka/build/static_src/InspectPatcher.c +439 -0
  531. nuitka/build/static_src/MainProgram.c +2060 -0
  532. nuitka/build/static_src/MetaPathBasedLoader.c +2290 -0
  533. nuitka/build/static_src/MetaPathBasedLoaderImportlibMetadataDistribution.c +125 -0
  534. nuitka/build/static_src/MetaPathBasedLoaderResourceReader.c +158 -0
  535. nuitka/build/static_src/MetaPathBasedLoaderResourceReaderFiles.c +785 -0
  536. nuitka/build/static_src/OnefileBootstrap.c +1580 -0
  537. nuitka/build/static_src/OnefileSplashScreen.cpp +275 -0
  538. nuitka/code_generation/AsyncgenCodes.py +186 -0
  539. nuitka/code_generation/AttributeCodes.py +357 -0
  540. nuitka/code_generation/BinaryOperationHelperDefinitions.py +720 -0
  541. nuitka/code_generation/BranchCodes.py +67 -0
  542. nuitka/code_generation/BuiltinCodes.py +529 -0
  543. nuitka/code_generation/CallCodes.py +1186 -0
  544. nuitka/code_generation/ClassCodes.py +156 -0
  545. nuitka/code_generation/CodeGeneration.py +1078 -0
  546. nuitka/code_generation/CodeHelperSelection.py +81 -0
  547. nuitka/code_generation/CodeHelpers.py +455 -0
  548. nuitka/code_generation/CodeObjectCodes.py +165 -0
  549. nuitka/code_generation/ComparisonCodes.py +569 -0
  550. nuitka/code_generation/ComparisonHelperDefinitions.py +146 -0
  551. nuitka/code_generation/ConditionalCodes.py +236 -0
  552. nuitka/code_generation/ConstantCodes.py +243 -0
  553. nuitka/code_generation/Contexts.py +1248 -0
  554. nuitka/code_generation/CoroutineCodes.py +253 -0
  555. nuitka/code_generation/CtypesCodes.py +46 -0
  556. nuitka/code_generation/DictCodes.py +918 -0
  557. nuitka/code_generation/Emission.py +75 -0
  558. nuitka/code_generation/ErrorCodes.py +281 -0
  559. nuitka/code_generation/EvalCodes.py +444 -0
  560. nuitka/code_generation/ExceptionCodes.py +337 -0
  561. nuitka/code_generation/ExpressionCTypeSelectionHelpers.py +227 -0
  562. nuitka/code_generation/ExpressionCodes.py +61 -0
  563. nuitka/code_generation/FrameCodes.py +518 -0
  564. nuitka/code_generation/FunctionCodes.py +858 -0
  565. nuitka/code_generation/GeneratorCodes.py +218 -0
  566. nuitka/code_generation/GlobalConstants.py +249 -0
  567. nuitka/code_generation/GlobalsLocalsCodes.py +211 -0
  568. nuitka/code_generation/IdCodes.py +53 -0
  569. nuitka/code_generation/ImportCodes.py +468 -0
  570. nuitka/code_generation/Indentation.py +45 -0
  571. nuitka/code_generation/IndexCodes.py +50 -0
  572. nuitka/code_generation/InjectCCodes.py +28 -0
  573. nuitka/code_generation/IntegerCodes.py +110 -0
  574. nuitka/code_generation/IteratorCodes.py +378 -0
  575. nuitka/code_generation/JitCodes.py +44 -0
  576. nuitka/code_generation/LabelCodes.py +68 -0
  577. nuitka/code_generation/LineNumberCodes.py +91 -0
  578. nuitka/code_generation/ListCodes.py +502 -0
  579. nuitka/code_generation/LoaderCodes.py +193 -0
  580. nuitka/code_generation/LocalsDictCodes.py +359 -0
  581. nuitka/code_generation/LoopCodes.py +88 -0
  582. nuitka/code_generation/MatchCodes.py +67 -0
  583. nuitka/code_generation/ModuleCodes.py +247 -0
  584. nuitka/code_generation/Namify.py +260 -0
  585. nuitka/code_generation/NetworkxCodes.py +51 -0
  586. nuitka/code_generation/OperationCodes.py +398 -0
  587. nuitka/code_generation/PackageResourceCodes.py +986 -0
  588. nuitka/code_generation/PrintCodes.py +93 -0
  589. nuitka/code_generation/PythonAPICodes.py +215 -0
  590. nuitka/code_generation/RaisingCodes.py +481 -0
  591. nuitka/code_generation/Reports.py +115 -0
  592. nuitka/code_generation/ReturnCodes.py +143 -0
  593. nuitka/code_generation/SetCodes.py +196 -0
  594. nuitka/code_generation/SliceCodes.py +465 -0
  595. nuitka/code_generation/StringCodes.py +303 -0
  596. nuitka/code_generation/SubscriptCodes.py +263 -0
  597. nuitka/code_generation/TensorflowCodes.py +54 -0
  598. nuitka/code_generation/TryCodes.py +326 -0
  599. nuitka/code_generation/TupleCodes.py +115 -0
  600. nuitka/code_generation/TypeAliasCodes.py +120 -0
  601. nuitka/code_generation/VariableCodes.py +519 -0
  602. nuitka/code_generation/VariableDeclarations.py +279 -0
  603. nuitka/code_generation/YieldCodes.py +253 -0
  604. nuitka/code_generation/__init__.py +19 -0
  605. nuitka/code_generation/c_types/CTypeBases.py +177 -0
  606. nuitka/code_generation/c_types/CTypeBooleans.py +104 -0
  607. nuitka/code_generation/c_types/CTypeCFloats.py +57 -0
  608. nuitka/code_generation/c_types/CTypeCLongs.py +45 -0
  609. nuitka/code_generation/c_types/CTypeModuleDictVariables.py +109 -0
  610. nuitka/code_generation/c_types/CTypeNuitkaBooleans.py +150 -0
  611. nuitka/code_generation/c_types/CTypeNuitkaInts.py +200 -0
  612. nuitka/code_generation/c_types/CTypeNuitkaVoids.py +107 -0
  613. nuitka/code_generation/c_types/CTypePyObjectPointers.py +572 -0
  614. nuitka/code_generation/c_types/CTypeVoids.py +92 -0
  615. nuitka/code_generation/c_types/__init__.py +19 -0
  616. nuitka/code_generation/templates/CodeTemplatesAsyncgens.py +106 -0
  617. nuitka/code_generation/templates/CodeTemplatesConstants.py +296 -0
  618. nuitka/code_generation/templates/CodeTemplatesCoroutines.py +109 -0
  619. nuitka/code_generation/templates/CodeTemplatesExceptions.py +84 -0
  620. nuitka/code_generation/templates/CodeTemplatesFrames.py +235 -0
  621. nuitka/code_generation/templates/CodeTemplatesFunction.py +117 -0
  622. nuitka/code_generation/templates/CodeTemplatesGeneratorFunction.py +130 -0
  623. nuitka/code_generation/templates/CodeTemplatesIterators.py +40 -0
  624. nuitka/code_generation/templates/CodeTemplatesLoader.py +180 -0
  625. nuitka/code_generation/templates/CodeTemplatesModules.py +710 -0
  626. nuitka/code_generation/templates/CodeTemplatesVariables.py +388 -0
  627. nuitka/code_generation/templates/TemplateDebugWrapper.py +80 -0
  628. nuitka/code_generation/templates/__init__.py +19 -0
  629. nuitka/code_generation/templates_c/CodeTemplateCallsMethodPositional.c.j2 +321 -0
  630. nuitka/code_generation/templates_c/CodeTemplateCallsMixed.c.j2 +143 -0
  631. nuitka/code_generation/templates_c/CodeTemplateCallsPositional.c.j2 +677 -0
  632. nuitka/code_generation/templates_c/CodeTemplateCallsPositionalMethodDescr.c.j2 +165 -0
  633. nuitka/code_generation/templates_c/CodeTemplateMakeListHinted.c.j2 +38 -0
  634. nuitka/code_generation/templates_c/CodeTemplateMakeListSmall.c.j2 +41 -0
  635. nuitka/code_generation/templates_c/HelperBuiltinMethodOperation.c.j2 +53 -0
  636. nuitka/code_generation/templates_c/HelperDictionaryCopy.c.j2 +364 -0
  637. nuitka/code_generation/templates_c/HelperImportHard.c.j2 +37 -0
  638. nuitka/code_generation/templates_c/HelperLongTools.c.j2 +53 -0
  639. nuitka/code_generation/templates_c/HelperObjectTools.c.j2 +20 -0
  640. nuitka/code_generation/templates_c/HelperOperationBinary.c.j2 +148 -0
  641. nuitka/code_generation/templates_c/HelperOperationBinaryDual.c.j2 +115 -0
  642. nuitka/code_generation/templates_c/HelperOperationComparison.c.j2 +352 -0
  643. nuitka/code_generation/templates_c/HelperOperationComparisonBytes.c.j2 +115 -0
  644. nuitka/code_generation/templates_c/HelperOperationComparisonDual.c.j2 +86 -0
  645. nuitka/code_generation/templates_c/HelperOperationComparisonFloat.c.j2 +31 -0
  646. nuitka/code_generation/templates_c/HelperOperationComparisonInt.c.j2 +32 -0
  647. nuitka/code_generation/templates_c/HelperOperationComparisonList.c.j2 +112 -0
  648. nuitka/code_generation/templates_c/HelperOperationComparisonLong.c.j2 +157 -0
  649. nuitka/code_generation/templates_c/HelperOperationComparisonStr.c.j2 +115 -0
  650. nuitka/code_generation/templates_c/HelperOperationComparisonTuple.c.j2 +99 -0
  651. nuitka/code_generation/templates_c/HelperOperationComparisonUnicode.c.j2 +115 -0
  652. nuitka/code_generation/templates_c/HelperOperationInplace.c.j2 +281 -0
  653. nuitka/code_generation/templates_c/HelperSlotsBinary.c.j2 +420 -0
  654. nuitka/code_generation/templates_c/HelperSlotsBytes.c.j2 +51 -0
  655. nuitka/code_generation/templates_c/HelperSlotsCommon.c.j2 +71 -0
  656. nuitka/code_generation/templates_c/HelperSlotsFloat.c.j2 +327 -0
  657. nuitka/code_generation/templates_c/HelperSlotsInt.c.j2 +411 -0
  658. nuitka/code_generation/templates_c/HelperSlotsList.c.j2 +59 -0
  659. nuitka/code_generation/templates_c/HelperSlotsLong.c.j2 +229 -0
  660. nuitka/code_generation/templates_c/HelperSlotsSet.c.j2 +47 -0
  661. nuitka/code_generation/templates_c/HelperSlotsStr.c.j2 +55 -0
  662. nuitka/code_generation/templates_c/HelperSlotsTuple.c.j2 +58 -0
  663. nuitka/code_generation/templates_c/HelperSlotsUnicode.c.j2 +62 -0
  664. nuitka/containers/Namedtuples.py +51 -0
  665. nuitka/containers/OrderedDicts.py +191 -0
  666. nuitka/containers/OrderedSets.py +123 -0
  667. nuitka/containers/OrderedSetsFallback.py +139 -0
  668. nuitka/containers/__init__.py +19 -0
  669. nuitka/distutils/Build.py +76 -0
  670. nuitka/distutils/DistutilCommands.py +438 -0
  671. nuitka/distutils/__init__.py +19 -0
  672. nuitka/finalizations/Finalization.py +35 -0
  673. nuitka/finalizations/FinalizeMarkups.py +136 -0
  674. nuitka/finalizations/__init__.py +19 -0
  675. nuitka/freezer/DependsExe.py +257 -0
  676. nuitka/freezer/DllDependenciesCommon.py +97 -0
  677. nuitka/freezer/DllDependenciesMacOS.py +444 -0
  678. nuitka/freezer/DllDependenciesPosix.py +242 -0
  679. nuitka/freezer/DllDependenciesWin32.py +315 -0
  680. nuitka/freezer/ImportDetection.py +359 -0
  681. nuitka/freezer/IncludedDataFiles.py +689 -0
  682. nuitka/freezer/IncludedEntryPoints.py +376 -0
  683. nuitka/freezer/Onefile.py +296 -0
  684. nuitka/freezer/Standalone.py +520 -0
  685. nuitka/freezer/__init__.py +19 -0
  686. nuitka/importing/IgnoreListing.py +449 -0
  687. nuitka/importing/ImportCache.py +95 -0
  688. nuitka/importing/ImportResolving.py +186 -0
  689. nuitka/importing/Importing.py +1200 -0
  690. nuitka/importing/PreloadedPackages.py +164 -0
  691. nuitka/importing/Recursion.py +611 -0
  692. nuitka/importing/StandardLibrary.py +429 -0
  693. nuitka/importing/__init__.py +19 -0
  694. nuitka/nodes/AsyncgenNodes.py +107 -0
  695. nuitka/nodes/AttributeLookupNodes.py +124 -0
  696. nuitka/nodes/AttributeNodes.py +386 -0
  697. nuitka/nodes/AttributeNodesGenerated.py +10734 -0
  698. nuitka/nodes/BuiltinAllNodes.py +115 -0
  699. nuitka/nodes/BuiltinAnyNodes.py +124 -0
  700. nuitka/nodes/BuiltinComplexNodes.py +83 -0
  701. nuitka/nodes/BuiltinDecodingNodes.py +52 -0
  702. nuitka/nodes/BuiltinDecoratorNodes.py +85 -0
  703. nuitka/nodes/BuiltinDictNodes.py +140 -0
  704. nuitka/nodes/BuiltinFormatNodes.py +159 -0
  705. nuitka/nodes/BuiltinHashNodes.py +63 -0
  706. nuitka/nodes/BuiltinInputNodes.py +39 -0
  707. nuitka/nodes/BuiltinIntegerNodes.py +170 -0
  708. nuitka/nodes/BuiltinIteratorNodes.py +391 -0
  709. nuitka/nodes/BuiltinLenNodes.py +61 -0
  710. nuitka/nodes/BuiltinNextNodes.py +111 -0
  711. nuitka/nodes/BuiltinOpenNodes.py +148 -0
  712. nuitka/nodes/BuiltinOperationNodeBasesGenerated.py +7367 -0
  713. nuitka/nodes/BuiltinRangeNodes.py +690 -0
  714. nuitka/nodes/BuiltinRefNodes.py +314 -0
  715. nuitka/nodes/BuiltinSumNodes.py +104 -0
  716. nuitka/nodes/BuiltinTypeNodes.py +454 -0
  717. nuitka/nodes/BuiltinVarsNodes.py +44 -0
  718. nuitka/nodes/BytesNodes.py +829 -0
  719. nuitka/nodes/CallNodes.py +217 -0
  720. nuitka/nodes/Checkers.py +55 -0
  721. nuitka/nodes/ChildrenHavingMixins.py +21576 -0
  722. nuitka/nodes/ClassNodes.py +286 -0
  723. nuitka/nodes/CodeObjectSpecs.py +230 -0
  724. nuitka/nodes/ComparisonNodes.py +687 -0
  725. nuitka/nodes/ConditionalNodes.py +884 -0
  726. nuitka/nodes/ConstantRefNodes.py +1717 -0
  727. nuitka/nodes/ContainerMakingNodes.py +408 -0
  728. nuitka/nodes/ContainerOperationNodes.py +87 -0
  729. nuitka/nodes/CoroutineNodes.py +144 -0
  730. nuitka/nodes/CtypesNodes.py +51 -0
  731. nuitka/nodes/DictionaryNodes.py +1513 -0
  732. nuitka/nodes/ExceptionNodes.py +393 -0
  733. nuitka/nodes/ExecEvalNodes.py +229 -0
  734. nuitka/nodes/ExpressionBases.py +1301 -0
  735. nuitka/nodes/ExpressionBasesGenerated.py +2103 -0
  736. nuitka/nodes/ExpressionShapeMixins.py +886 -0
  737. nuitka/nodes/FrameNodes.py +413 -0
  738. nuitka/nodes/FunctionAttributeNodes.py +102 -0
  739. nuitka/nodes/FunctionNodes.py +1303 -0
  740. nuitka/nodes/FutureSpecs.py +224 -0
  741. nuitka/nodes/GeneratorNodes.py +201 -0
  742. nuitka/nodes/GlobalsLocalsNodes.py +209 -0
  743. nuitka/nodes/HardImportNodesGenerated.py +3599 -0
  744. nuitka/nodes/ImportHardNodes.py +185 -0
  745. nuitka/nodes/ImportNodes.py +1366 -0
  746. nuitka/nodes/IndicatorMixins.py +79 -0
  747. nuitka/nodes/InjectCNodes.py +51 -0
  748. nuitka/nodes/IterationHandles.py +407 -0
  749. nuitka/nodes/KeyValuePairNodes.py +378 -0
  750. nuitka/nodes/ListOperationNodes.py +525 -0
  751. nuitka/nodes/LocalsDictNodes.py +717 -0
  752. nuitka/nodes/LocalsScopes.py +505 -0
  753. nuitka/nodes/LoopNodes.py +445 -0
  754. nuitka/nodes/MatchNodes.py +60 -0
  755. nuitka/nodes/ModuleAttributeNodes.py +180 -0
  756. nuitka/nodes/ModuleNodes.py +1137 -0
  757. nuitka/nodes/NetworkxNodes.py +45 -0
  758. nuitka/nodes/NodeBases.py +890 -0
  759. nuitka/nodes/NodeMakingHelpers.py +481 -0
  760. nuitka/nodes/NodeMetaClasses.py +172 -0
  761. nuitka/nodes/OperatorNodes.py +944 -0
  762. nuitka/nodes/OperatorNodesUnary.py +403 -0
  763. nuitka/nodes/OsSysNodes.py +215 -0
  764. nuitka/nodes/OutlineNodes.py +372 -0
  765. nuitka/nodes/PackageMetadataNodes.py +982 -0
  766. nuitka/nodes/PackageResourceNodes.py +424 -0
  767. nuitka/nodes/PrintNodes.py +105 -0
  768. nuitka/nodes/ReturnNodes.py +255 -0
  769. nuitka/nodes/SideEffectNodes.py +139 -0
  770. nuitka/nodes/SliceNodes.py +386 -0
  771. nuitka/nodes/StatementBasesGenerated.py +3419 -0
  772. nuitka/nodes/StatementNodes.py +316 -0
  773. nuitka/nodes/StrNodes.py +919 -0
  774. nuitka/nodes/StringConcatenationNodes.py +103 -0
  775. nuitka/nodes/SubscriptNodes.py +245 -0
  776. nuitka/nodes/TensorflowNodes.py +38 -0
  777. nuitka/nodes/TryNodes.py +519 -0
  778. nuitka/nodes/TypeMatchNodes.py +65 -0
  779. nuitka/nodes/TypeNodes.py +390 -0
  780. nuitka/nodes/VariableAssignNodes.py +1177 -0
  781. nuitka/nodes/VariableDelNodes.py +320 -0
  782. nuitka/nodes/VariableNameNodes.py +153 -0
  783. nuitka/nodes/VariableRefNodes.py +895 -0
  784. nuitka/nodes/VariableReleaseNodes.py +153 -0
  785. nuitka/nodes/YieldNodes.py +121 -0
  786. nuitka/nodes/__init__.py +19 -0
  787. nuitka/nodes/shapes/BuiltinTypeShapes.py +4290 -0
  788. nuitka/nodes/shapes/ControlFlowDescriptions.py +199 -0
  789. nuitka/nodes/shapes/IteratorShapes.py +71 -0
  790. nuitka/nodes/shapes/ShapeMixins.py +255 -0
  791. nuitka/nodes/shapes/StandardShapes.py +1384 -0
  792. nuitka/nodes/shapes/__init__.py +19 -0
  793. nuitka/optimizations/BytecodeDemotion.py +105 -0
  794. nuitka/optimizations/FunctionInlining.py +110 -0
  795. nuitka/optimizations/Graphs.py +70 -0
  796. nuitka/optimizations/Optimization.py +363 -0
  797. nuitka/optimizations/OptimizeBuiltinCalls.py +1582 -0
  798. nuitka/optimizations/Tags.py +76 -0
  799. nuitka/optimizations/TraceCollections.py +1257 -0
  800. nuitka/optimizations/ValueTraces.py +980 -0
  801. nuitka/optimizations/__init__.py +19 -0
  802. nuitka/pgo/PGO.py +160 -0
  803. nuitka/pgo/__init__.py +19 -0
  804. nuitka/plugins/PluginBase.py +1924 -0
  805. nuitka/plugins/Plugins.py +2007 -0
  806. nuitka/plugins/YamlPluginBase.py +121 -0
  807. nuitka/plugins/__init__.py +19 -0
  808. nuitka/plugins/standard/AntiBloatPlugin.py +1024 -0
  809. nuitka/plugins/standard/ConsiderPyLintAnnotationsPlugin.py +95 -0
  810. nuitka/plugins/standard/DataFilesPlugin.py +311 -0
  811. nuitka/plugins/standard/DelvewheelPlugin.py +150 -0
  812. nuitka/plugins/standard/DillPlugin/DillPlugin.c +37 -0
  813. nuitka/plugins/standard/DillPlugin/cloudpickle-postLoad.py +67 -0
  814. nuitka/plugins/standard/DillPlugin/dill-postLoad.py +223 -0
  815. nuitka/plugins/standard/DillPlugin.py +137 -0
  816. nuitka/plugins/standard/DllFilesPlugin.py +527 -0
  817. nuitka/plugins/standard/EnumPlugin.py +64 -0
  818. nuitka/plugins/standard/EventletPlugin.py +57 -0
  819. nuitka/plugins/standard/GeventPlugin.py +64 -0
  820. nuitka/plugins/standard/GiPlugin.py +118 -0
  821. nuitka/plugins/standard/GlfwPlugin.py +138 -0
  822. nuitka/plugins/standard/ImplicitImports.py +845 -0
  823. nuitka/plugins/standard/KivyPlugin.py +141 -0
  824. nuitka/plugins/standard/MatplotlibPlugin.py +256 -0
  825. nuitka/plugins/standard/MultiprocessingPlugin.py +199 -0
  826. nuitka/plugins/standard/NumpyPlugin.py +35 -0
  827. nuitka/plugins/standard/OptionsNannyPlugin.py +158 -0
  828. nuitka/plugins/standard/PbrPlugin.py +62 -0
  829. nuitka/plugins/standard/PkgResourcesPlugin.py +162 -0
  830. nuitka/plugins/standard/PlaywrightPlugin.py +179 -0
  831. nuitka/plugins/standard/PmwPlugin.py +248 -0
  832. nuitka/plugins/standard/PySidePyQtPlugin.py +1666 -0
  833. nuitka/plugins/standard/PywebViewPlugin.py +81 -0
  834. nuitka/plugins/standard/SpacyPlugin.py +137 -0
  835. nuitka/plugins/standard/TensorflowPlugin.py +35 -0
  836. nuitka/plugins/standard/TkinterPlugin.py +416 -0
  837. nuitka/plugins/standard/TorchPlugin.py +35 -0
  838. nuitka/plugins/standard/TransformersPlugin.py +121 -0
  839. nuitka/plugins/standard/TrioPlugin.py +33 -0
  840. nuitka/plugins/standard/UpxPlugin.py +174 -0
  841. nuitka/plugins/standard/__init__.py +19 -0
  842. nuitka/plugins/standard/standard.nuitka-package.config.yml +9313 -0
  843. nuitka/plugins/standard/stdlib2.nuitka-package.config.yml +78 -0
  844. nuitka/plugins/standard/stdlib3.nuitka-package.config.yml +468 -0
  845. nuitka/reports/CompilationReportReader.py +83 -0
  846. nuitka/reports/LicenseReport.rst.j2 +41 -0
  847. nuitka/reports/Reports.py +961 -0
  848. nuitka/reports/__init__.py +19 -0
  849. nuitka/specs/BuiltinBytesOperationSpecs.py +180 -0
  850. nuitka/specs/BuiltinDictOperationSpecs.py +82 -0
  851. nuitka/specs/BuiltinListOperationSpecs.py +80 -0
  852. nuitka/specs/BuiltinParameterSpecs.py +831 -0
  853. nuitka/specs/BuiltinStrOperationSpecs.py +181 -0
  854. nuitka/specs/BuiltinTypeOperationSpecs.py +34 -0
  855. nuitka/specs/BuiltinUnicodeOperationSpecs.py +123 -0
  856. nuitka/specs/HardImportSpecs.py +236 -0
  857. nuitka/specs/ParameterSpecs.py +630 -0
  858. nuitka/specs/__init__.py +19 -0
  859. nuitka/tools/Basics.py +55 -0
  860. nuitka/tools/__init__.py +19 -0
  861. nuitka/tools/commercial/__init__.py +21 -0
  862. nuitka/tools/data_composer/DataComposer.py +593 -0
  863. nuitka/tools/data_composer/__init__.py +19 -0
  864. nuitka/tools/data_composer/__main__.py +41 -0
  865. nuitka/tools/environments/CreateEnvironment.py +69 -0
  866. nuitka/tools/environments/Virtualenv.py +158 -0
  867. nuitka/tools/environments/__init__.py +19 -0
  868. nuitka/tools/general/__init__.py +19 -0
  869. nuitka/tools/general/dll_report/__init__.py +19 -0
  870. nuitka/tools/general/dll_report/__main__.py +83 -0
  871. nuitka/tools/general/find_module/FindModuleCode.py +127 -0
  872. nuitka/tools/general/find_module/__init__.py +19 -0
  873. nuitka/tools/general/generate_header/GenerateHeader.py +73 -0
  874. nuitka/tools/general/generate_header/__init__.py +19 -0
  875. nuitka/tools/onefile_compressor/OnefileCompressor.py +390 -0
  876. nuitka/tools/onefile_compressor/__init__.py +19 -0
  877. nuitka/tools/onefile_compressor/__main__.py +41 -0
  878. nuitka/tools/podman/Podman.py +55 -0
  879. nuitka/tools/podman/__init__.py +19 -0
  880. nuitka/tools/podman/__main__.py +425 -0
  881. nuitka/tools/profiler/__init__.py +19 -0
  882. nuitka/tools/profiler/__main__.py +93 -0
  883. nuitka/tools/scanning/DisplayDistributions.py +39 -0
  884. nuitka/tools/scanning/DisplayPackageDLLs.py +151 -0
  885. nuitka/tools/scanning/DisplayPackageData.py +73 -0
  886. nuitka/tools/scanning/__init__.py +19 -0
  887. nuitka/tools/specialize/CTypeDescriptions.py +1928 -0
  888. nuitka/tools/specialize/Common.py +380 -0
  889. nuitka/tools/specialize/SpecializeC.py +1483 -0
  890. nuitka/tools/specialize/SpecializePython.py +1151 -0
  891. nuitka/tools/specialize/__init__.py +19 -0
  892. nuitka/tools/testing/Common.py +2007 -0
  893. nuitka/tools/testing/Constructs.py +53 -0
  894. nuitka/tools/testing/DocTests.py +156 -0
  895. nuitka/tools/testing/OutputComparison.py +313 -0
  896. nuitka/tools/testing/Pythons.py +34 -0
  897. nuitka/tools/testing/RuntimeTracing.py +260 -0
  898. nuitka/tools/testing/SearchModes.py +208 -0
  899. nuitka/tools/testing/Valgrind.py +103 -0
  900. nuitka/tools/testing/__init__.py +19 -0
  901. nuitka/tools/testing/check_reference_counts/__init__.py +19 -0
  902. nuitka/tools/testing/check_reference_counts/__main__.py +107 -0
  903. nuitka/tools/testing/compare_with_cpython/__init__.py +19 -0
  904. nuitka/tools/testing/compare_with_cpython/__main__.py +942 -0
  905. nuitka/tools/testing/find_sxs_modules/__init__.py +19 -0
  906. nuitka/tools/testing/find_sxs_modules/__main__.py +73 -0
  907. nuitka/tools/testing/measure_construct_performance/__init__.py +19 -0
  908. nuitka/tools/testing/measure_construct_performance/__main__.py +288 -0
  909. nuitka/tools/testing/run_nuitka_tests/__init__.py +19 -0
  910. nuitka/tools/testing/run_nuitka_tests/__main__.py +1091 -0
  911. nuitka/tools/watch/AutoStage.py +145 -0
  912. nuitka/tools/watch/Common.py +55 -0
  913. nuitka/tools/watch/Conda.py +125 -0
  914. nuitka/tools/watch/GitHub.py +113 -0
  915. nuitka/tools/watch/Pacman.py +73 -0
  916. nuitka/tools/watch/Pipenv.py +145 -0
  917. nuitka/tools/watch/__init__.py +19 -0
  918. nuitka/tools/watch/__main__.py +615 -0
  919. nuitka/tree/Building.py +1459 -0
  920. nuitka/tree/ComplexCallHelperFunctions.py +2150 -0
  921. nuitka/tree/Extractions.py +48 -0
  922. nuitka/tree/FutureSpecState.py +71 -0
  923. nuitka/tree/InternalModule.py +96 -0
  924. nuitka/tree/Operations.py +45 -0
  925. nuitka/tree/ReformulationAssertStatements.py +97 -0
  926. nuitka/tree/ReformulationAssignmentStatements.py +1260 -0
  927. nuitka/tree/ReformulationBooleanExpressions.py +97 -0
  928. nuitka/tree/ReformulationCallExpressions.py +314 -0
  929. nuitka/tree/ReformulationClasses.py +407 -0
  930. nuitka/tree/ReformulationClasses3.py +1149 -0
  931. nuitka/tree/ReformulationComparisonExpressions.py +174 -0
  932. nuitka/tree/ReformulationContractionExpressions.py +676 -0
  933. nuitka/tree/ReformulationDictionaryCreation.py +304 -0
  934. nuitka/tree/ReformulationExecStatements.py +386 -0
  935. nuitka/tree/ReformulationForLoopStatements.py +215 -0
  936. nuitka/tree/ReformulationFunctionStatements.py +931 -0
  937. nuitka/tree/ReformulationImportStatements.py +333 -0
  938. nuitka/tree/ReformulationLambdaExpressions.py +185 -0
  939. nuitka/tree/ReformulationMatchStatements.py +797 -0
  940. nuitka/tree/ReformulationMultidist.py +80 -0
  941. nuitka/tree/ReformulationNamespacePackages.py +239 -0
  942. nuitka/tree/ReformulationPrintStatements.py +127 -0
  943. nuitka/tree/ReformulationSequenceCreation.py +438 -0
  944. nuitka/tree/ReformulationSubscriptExpressions.py +123 -0
  945. nuitka/tree/ReformulationTryExceptStatements.py +418 -0
  946. nuitka/tree/ReformulationTryFinallyStatements.py +239 -0
  947. nuitka/tree/ReformulationWhileLoopStatements.py +160 -0
  948. nuitka/tree/ReformulationWithStatements.py +382 -0
  949. nuitka/tree/ReformulationYieldExpressions.py +133 -0
  950. nuitka/tree/SourceHandling.py +476 -0
  951. nuitka/tree/SyntaxErrors.py +143 -0
  952. nuitka/tree/TreeHelpers.py +720 -0
  953. nuitka/tree/VariableClosure.py +483 -0
  954. nuitka/tree/__init__.py +19 -0
  955. nuitka/utils/AppDirs.py +104 -0
  956. nuitka/utils/CStrings.py +208 -0
  957. nuitka/utils/CommandLineOptions.py +207 -0
  958. nuitka/utils/Distributions.py +728 -0
  959. nuitka/utils/Download.py +217 -0
  960. nuitka/utils/Execution.py +517 -0
  961. nuitka/utils/FileOperations.py +1587 -0
  962. nuitka/utils/Hashing.py +137 -0
  963. nuitka/utils/Images.py +79 -0
  964. nuitka/utils/Importing.py +335 -0
  965. nuitka/utils/InlineCopies.py +52 -0
  966. nuitka/utils/InstalledPythons.py +254 -0
  967. nuitka/utils/InstanceCounters.py +86 -0
  968. nuitka/utils/Jinja2.py +158 -0
  969. nuitka/utils/Json.py +40 -0
  970. nuitka/utils/MacOSApp.py +134 -0
  971. nuitka/utils/MemoryUsage.py +165 -0
  972. nuitka/utils/ModuleNames.py +317 -0
  973. nuitka/utils/PackageResources.py +44 -0
  974. nuitka/utils/ReExecute.py +152 -0
  975. nuitka/utils/Rest.py +60 -0
  976. nuitka/utils/SharedLibraries.py +1014 -0
  977. nuitka/utils/Shebang.py +113 -0
  978. nuitka/utils/Signing.py +144 -0
  979. nuitka/utils/SlotMetaClasses.py +57 -0
  980. nuitka/utils/StaticLibraries.py +260 -0
  981. nuitka/utils/ThreadedExecutor.py +87 -0
  982. nuitka/utils/Timing.py +102 -0
  983. nuitka/utils/Utils.py +483 -0
  984. nuitka/utils/WindowsFileUsage.py +337 -0
  985. nuitka/utils/WindowsResources.py +652 -0
  986. nuitka/utils/Yaml.py +247 -0
  987. nuitka/utils/__init__.py +19 -0
  988. nuitka_winsvc-2.7.7.data/scripts/nuitka-run.cmd +24 -0
  989. nuitka_winsvc-2.7.7.data/scripts/nuitka.cmd +30 -0
  990. nuitka_winsvc-2.7.7.dist-info/METADATA +115 -0
  991. nuitka_winsvc-2.7.7.dist-info/RECORD +995 -0
  992. nuitka_winsvc-2.7.7.dist-info/WHEEL +5 -0
  993. nuitka_winsvc-2.7.7.dist-info/entry_points.txt +7 -0
  994. nuitka_winsvc-2.7.7.dist-info/licenses/LICENSE.txt +202 -0
  995. nuitka_winsvc-2.7.7.dist-info/top_level.txt +1 -0
@@ -0,0 +1,3861 @@
1
+ # MIT License
2
+ #
3
+ # Copyright The SCons Foundation
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining
6
+ # a copy of this software and associated documentation files (the
7
+ # "Software"), to deal in the Software without restriction, including
8
+ # without limitation the rights to use, copy, modify, merge, publish,
9
+ # distribute, sublicense, and/or sell copies of the Software, and to
10
+ # permit persons to whom the Software is furnished to do so, subject to
11
+ # the following conditions:
12
+ #
13
+ # The above copyright notice and this permission notice shall be included
14
+ # in all copies or substantial portions of the Software.
15
+ #
16
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
17
+ # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
18
+ # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
+
24
+ """File system nodes.
25
+
26
+ These Nodes represent the canonical external objects that people think
27
+ of when they think of building software: files and directories.
28
+
29
+ This holds a "default_fs" variable that should be initialized with an FS
30
+ that can be used by scripts or modules looking for the canonical default.
31
+ """
32
+
33
+ import codecs
34
+ import fnmatch
35
+ import importlib.util
36
+ import os
37
+ import re
38
+ import shutil
39
+ import stat
40
+ import sys
41
+ import time
42
+ from itertools import chain
43
+ from typing import Optional
44
+
45
+ import SCons.Action
46
+ import SCons.Debug
47
+ import SCons.Errors
48
+ import SCons.Memoize
49
+ import SCons.Node
50
+ import SCons.Node.Alias
51
+ import SCons.Subst
52
+ import SCons.Util
53
+ import SCons.Warnings
54
+ from SCons.Debug import logInstanceCreation, Trace
55
+ from SCons.Util import hash_signature, hash_file_signature, hash_collect
56
+
57
+ print_duplicate = 0
58
+
59
+ MD5_TIMESTAMP_DEBUG = False
60
+
61
+
62
+ def sconsign_none(node):
63
+ raise NotImplementedError
64
+
65
+ def sconsign_dir(node):
66
+ """Return the .sconsign file info for this directory,
67
+ creating it first if necessary."""
68
+ if not node._sconsign:
69
+ import SCons.SConsign
70
+ node._sconsign = SCons.SConsign.ForDirectory(node)
71
+ return node._sconsign
72
+
73
+ _sconsign_map = {0 : sconsign_none,
74
+ 1 : sconsign_dir}
75
+
76
+ class FileBuildInfoFileToCsigMappingError(Exception):
77
+ pass
78
+
79
+ class EntryProxyAttributeError(AttributeError):
80
+ """
81
+ An AttributeError subclass for recording and displaying the name
82
+ of the underlying Entry involved in an AttributeError exception.
83
+ """
84
+ def __init__(self, entry_proxy, attribute):
85
+ AttributeError.__init__(self)
86
+ self.entry_proxy = entry_proxy
87
+ self.attribute = attribute
88
+ def __str__(self):
89
+ entry = self.entry_proxy.get()
90
+ fmt = "%s instance %s has no attribute %s"
91
+ return fmt % (entry.__class__.__name__,
92
+ repr(entry.name),
93
+ repr(self.attribute))
94
+
95
+ # The max_drift value: by default, use a cached signature value for
96
+ # any file that's been untouched for more than two days.
97
+ default_max_drift = 2*24*60*60
98
+
99
+ #
100
+ # We stringify these file system Nodes a lot. Turning a file system Node
101
+ # into a string is non-trivial, because the final string representation
102
+ # can depend on a lot of factors: whether it's a derived target or not,
103
+ # whether it's linked to a repository or source directory, and whether
104
+ # there's duplication going on. The normal technique for optimizing
105
+ # calculations like this is to memoize (cache) the string value, so you
106
+ # only have to do the calculation once.
107
+ #
108
+ # A number of the above factors, however, can be set after we've already
109
+ # been asked to return a string for a Node, because a Repository() or
110
+ # VariantDir() call or the like may not occur until later in SConscript
111
+ # files. So this variable controls whether we bother trying to save
112
+ # string values for Nodes. The wrapper interface can set this whenever
113
+ # they're done mucking with Repository and VariantDir and the other stuff,
114
+ # to let this module know it can start returning saved string values
115
+ # for Nodes.
116
+ #
117
+ Save_Strings = None
118
+
119
+ def save_strings(val):
120
+ global Save_Strings
121
+ Save_Strings = val
122
+
123
+ #
124
+ # Avoid unnecessary function calls by recording a Boolean value that
125
+ # tells us whether or not os.path.splitdrive() actually does anything
126
+ # on this system, and therefore whether we need to bother calling it
127
+ # when looking up path names in various methods below.
128
+ #
129
+
130
+ do_splitdrive = None
131
+ _my_splitdrive =None
132
+
133
+ def initialize_do_splitdrive():
134
+ global do_splitdrive
135
+ global has_unc
136
+ drive, path = os.path.splitdrive('X:/foo')
137
+ # splitunc is removed from python 3.7 and newer
138
+ # so we can also just test if splitdrive works with UNC
139
+ has_unc = (hasattr(os.path, 'splitunc')
140
+ or os.path.splitdrive(r'\\split\drive\test')[0] == r'\\split\drive')
141
+
142
+ do_splitdrive = not not drive or has_unc
143
+
144
+ global _my_splitdrive
145
+ if has_unc:
146
+ def splitdrive(p):
147
+ if p[1:2] == ':':
148
+ return p[:2], p[2:]
149
+ if p[0:2] == '//':
150
+ # Note that we leave a leading slash in the path
151
+ # because UNC paths are always absolute.
152
+ return '//', p[1:]
153
+ return '', p
154
+ else:
155
+ def splitdrive(p):
156
+ if p[1:2] == ':':
157
+ return p[:2], p[2:]
158
+ return '', p
159
+ _my_splitdrive = splitdrive
160
+
161
+ # Keep some commonly used values in global variables to skip to
162
+ # module look-up costs.
163
+ global OS_SEP
164
+ global UNC_PREFIX
165
+ global os_sep_is_slash
166
+
167
+ OS_SEP = os.sep
168
+ UNC_PREFIX = OS_SEP + OS_SEP
169
+ os_sep_is_slash = OS_SEP == '/'
170
+
171
+ initialize_do_splitdrive()
172
+
173
+ # Used to avoid invoking os.path.normpath if not necessary.
174
+ needs_normpath_check = re.compile(
175
+ r'''
176
+ # We need to renormalize the path if it contains any consecutive
177
+ # '/' characters.
178
+ .*// |
179
+
180
+ # We need to renormalize the path if it contains a '..' directory.
181
+ # Note that we check for all the following cases:
182
+ #
183
+ # a) The path is a single '..'
184
+ # b) The path starts with '..'. E.g. '../' or '../moredirs'
185
+ # but we not match '..abc/'.
186
+ # c) The path ends with '..'. E.g. '/..' or 'dirs/..'
187
+ # d) The path contains a '..' in the middle.
188
+ # E.g. dirs/../moredirs
189
+
190
+ (.*/)?\.\.(?:/|$) |
191
+
192
+ # We need to renormalize the path if it contains a '.'
193
+ # directory, but NOT if it is a single '.' '/' characters. We
194
+ # do not want to match a single '.' because this case is checked
195
+ # for explicitly since this is common enough case.
196
+ #
197
+ # Note that we check for all the following cases:
198
+ #
199
+ # a) We don't match a single '.'
200
+ # b) We match if the path starts with '.'. E.g. './' or
201
+ # './moredirs' but we not match '.abc/'.
202
+ # c) We match if the path ends with '.'. E.g. '/.' or
203
+ # 'dirs/.'
204
+ # d) We match if the path contains a '.' in the middle.
205
+ # E.g. dirs/./moredirs
206
+
207
+ \./|.*/\.(?:/|$)
208
+
209
+ ''',
210
+ re.VERBOSE
211
+ )
212
+ needs_normpath_match = needs_normpath_check.match
213
+
214
+ #
215
+ # SCons.Action objects for interacting with the outside world.
216
+ #
217
+ # The Node.FS methods in this module should use these actions to
218
+ # create and/or remove files and directories; they should *not* use
219
+ # os.{link,symlink,unlink,mkdir}(), etc., directly.
220
+ #
221
+ # Using these SCons.Action objects ensures that descriptions of these
222
+ # external activities are properly displayed, that the displays are
223
+ # suppressed when the -s (silent) option is used, and (most importantly)
224
+ # the actions are disabled when the the -n option is used, in which case
225
+ # there should be *no* changes to the external file system(s)...
226
+ #
227
+
228
+ # For Now disable hard & softlinks for win32
229
+ # PY3 supports them, but the rest of SCons is not ready for this
230
+ # in some cases user permissions may be required.
231
+ # TODO: See if theres a reasonable way to enable using links on win32/64
232
+
233
+ if hasattr(os, 'link') and sys.platform != 'win32':
234
+ def _hardlink_func(fs, src, dst):
235
+ # If the source is a symlink, we can't just hard-link to it
236
+ # because a relative symlink may point somewhere completely
237
+ # different. We must disambiguate the symlink and then
238
+ # hard-link the final destination file.
239
+ while fs.islink(src):
240
+ link = fs.readlink(src)
241
+ if not os.path.isabs(link):
242
+ src = link
243
+ else:
244
+ src = os.path.join(os.path.dirname(src), link)
245
+ fs.link(src, dst)
246
+ else:
247
+ _hardlink_func = None
248
+
249
+ if hasattr(os, 'symlink') and sys.platform != 'win32':
250
+ def _softlink_func(fs, src, dst):
251
+ fs.symlink(src, dst)
252
+ else:
253
+ _softlink_func = None
254
+
255
+ def _copy_func(fs, src, dest):
256
+ shutil.copy2(src, dest)
257
+ st = fs.stat(src)
258
+ fs.chmod(dest, stat.S_IMODE(st[stat.ST_MODE]) | stat.S_IWRITE)
259
+
260
+
261
+ Valid_Duplicates = ['hard-soft-copy', 'soft-hard-copy',
262
+ 'hard-copy', 'soft-copy', 'copy']
263
+
264
+ Link_Funcs = [] # contains the callables of the specified duplication style
265
+
266
+ def set_duplicate(duplicate):
267
+ # Fill in the Link_Funcs list according to the argument
268
+ # (discarding those not available on the platform).
269
+
270
+ # Set up the dictionary that maps the argument names to the
271
+ # underlying implementations. We do this inside this function,
272
+ # not in the top-level module code, so that we can remap os.link
273
+ # and os.symlink for testing purposes.
274
+ link_dict = {
275
+ 'hard' : _hardlink_func,
276
+ 'soft' : _softlink_func,
277
+ 'copy' : _copy_func
278
+ }
279
+
280
+ if duplicate not in Valid_Duplicates:
281
+ raise SCons.Errors.InternalError("The argument of set_duplicate "
282
+ "should be in Valid_Duplicates")
283
+ global Link_Funcs
284
+ Link_Funcs = []
285
+ for func in duplicate.split('-'):
286
+ if link_dict[func]:
287
+ Link_Funcs.append(link_dict[func])
288
+
289
+ def LinkFunc(target, source, env):
290
+ """
291
+ Relative paths cause problems with symbolic links, so
292
+ we use absolute paths, which may be a problem for people
293
+ who want to move their soft-linked src-trees around. Those
294
+ people should use the 'hard-copy' mode, softlinks cannot be
295
+ used for that; at least I have no idea how ...
296
+ """
297
+ src = source[0].get_abspath()
298
+ dest = target[0].get_abspath()
299
+ dir, file = os.path.split(dest)
300
+ if dir and not target[0].fs.isdir(dir):
301
+ os.makedirs(dir)
302
+ if not Link_Funcs:
303
+ # Set a default order of link functions.
304
+ set_duplicate('hard-soft-copy')
305
+ fs = source[0].fs
306
+ # Now link the files with the previously specified order.
307
+ for func in Link_Funcs:
308
+ try:
309
+ func(fs, src, dest)
310
+ break
311
+ except (IOError, OSError):
312
+ # An OSError indicates something happened like a permissions
313
+ # problem or an attempt to symlink across file-system
314
+ # boundaries. An IOError indicates something like the file
315
+ # not existing. In either case, keeping trying additional
316
+ # functions in the list and only raise an error if the last
317
+ # one failed.
318
+ if func == Link_Funcs[-1]:
319
+ # exception of the last link method (copy) are fatal
320
+ raise
321
+ return 0
322
+
323
+ Link = SCons.Action.Action(LinkFunc, None)
324
+ def LocalString(target, source, env):
325
+ return 'Local copy of %s from %s' % (target[0], source[0])
326
+
327
+ LocalCopy = SCons.Action.Action(LinkFunc, LocalString)
328
+
329
+ def UnlinkFunc(target, source, env):
330
+ t = target[0]
331
+ t.fs.unlink(t.get_abspath())
332
+ return 0
333
+
334
+ Unlink = SCons.Action.Action(UnlinkFunc, None)
335
+
336
+ def MkdirFunc(target, source, env):
337
+ t = target[0]
338
+ # This os.path.exists test looks redundant, but it's possible
339
+ # when using Install() to install multiple dirs outside the
340
+ # source tree to get a case where t.exists() is true but
341
+ # the path does already exist, so this prevents spurious
342
+ # build failures in that case. See test/Install/multi-dir.
343
+ if not t.exists() and not os.path.exists(t.get_abspath()):
344
+ t.fs.mkdir(t.get_abspath())
345
+ return 0
346
+
347
+ Mkdir = SCons.Action.Action(MkdirFunc, None, presub=None)
348
+
349
+ MkdirBuilder = None
350
+
351
+ def get_MkdirBuilder():
352
+ global MkdirBuilder
353
+ if MkdirBuilder is None:
354
+ import SCons.Builder
355
+ import SCons.Defaults
356
+ # "env" will get filled in by Executor.get_build_env()
357
+ # calling SCons.Defaults.DefaultEnvironment() when necessary.
358
+ MkdirBuilder = SCons.Builder.Builder(action = Mkdir,
359
+ env = None,
360
+ explain = None,
361
+ is_explicit = None,
362
+ target_scanner = SCons.Defaults.DirEntryScanner,
363
+ name = "MkdirBuilder")
364
+ return MkdirBuilder
365
+
366
+ class _Null:
367
+ pass
368
+
369
+ _null = _Null()
370
+
371
+ # Cygwin's os.path.normcase pretends it's on a case-sensitive filesystem.
372
+ _is_cygwin = sys.platform == "cygwin"
373
+ if os.path.normcase("TeSt") == os.path.normpath("TeSt") and not _is_cygwin:
374
+ def _my_normcase(x):
375
+ return x
376
+ else:
377
+ def _my_normcase(x):
378
+ return x.upper()
379
+
380
+
381
+
382
+ class DiskChecker:
383
+ def __init__(self, type, do, ignore):
384
+ self.type = type
385
+ self.do = do
386
+ self.ignore = ignore
387
+ self.func = do
388
+ def __call__(self, *args, **kw):
389
+ return self.func(*args, **kw)
390
+ def set(self, list):
391
+ if self.type in list:
392
+ self.func = self.do
393
+ else:
394
+ self.func = self.ignore
395
+
396
+ def do_diskcheck_match(node, predicate, errorfmt):
397
+ result = predicate()
398
+ try:
399
+ # If calling the predicate() cached a None value from stat(),
400
+ # remove it so it doesn't interfere with later attempts to
401
+ # build this Node as we walk the DAG. (This isn't a great way
402
+ # to do this, we're reaching into an interface that doesn't
403
+ # really belong to us, but it's all about performance, so
404
+ # for now we'll just document the dependency...)
405
+ if node._memo['stat'] is None:
406
+ del node._memo['stat']
407
+ except (AttributeError, KeyError):
408
+ pass
409
+ if result:
410
+ raise TypeError(errorfmt % node.get_abspath())
411
+
412
+ def ignore_diskcheck_match(node, predicate, errorfmt):
413
+ pass
414
+
415
+
416
+
417
+ diskcheck_match = DiskChecker('match', do_diskcheck_match, ignore_diskcheck_match)
418
+
419
+ diskcheckers = [
420
+ diskcheck_match,
421
+ ]
422
+
423
+ def set_diskcheck(list):
424
+ for dc in diskcheckers:
425
+ dc.set(list)
426
+
427
+ def diskcheck_types():
428
+ return [dc.type for dc in diskcheckers]
429
+
430
+
431
+
432
+ class EntryProxy(SCons.Util.Proxy):
433
+
434
+ __str__ = SCons.Util.Delegate('__str__')
435
+
436
+ # In PY3 if a class defines __eq__, then it must explicitly provide
437
+ # __hash__. Since SCons.Util.Proxy provides __eq__ we need the following
438
+ # see: https://docs.python.org/3/reference/datamodel.html#object.__hash__
439
+ __hash__ = SCons.Util.Delegate('__hash__')
440
+
441
+ def __get_abspath(self):
442
+ entry = self.get()
443
+ return SCons.Subst.SpecialAttrWrapper(entry.get_abspath(),
444
+ entry.name + "_abspath")
445
+
446
+ def __get_relpath(self):
447
+ entry = self.get()
448
+ return SCons.Subst.SpecialAttrWrapper(entry.get_relpath(),
449
+ entry.name + "_relpath")
450
+
451
+ def __get_filebase(self):
452
+ name = self.get().name
453
+ return SCons.Subst.SpecialAttrWrapper(SCons.Util.splitext(name)[0],
454
+ name + "_filebase")
455
+
456
+ def __get_suffix(self):
457
+ name = self.get().name
458
+ return SCons.Subst.SpecialAttrWrapper(SCons.Util.splitext(name)[1],
459
+ name + "_suffix")
460
+
461
+ def __get_file(self):
462
+ name = self.get().name
463
+ return SCons.Subst.SpecialAttrWrapper(name, name + "_file")
464
+
465
+ def __get_base_path(self):
466
+ """Return the file's directory and file name, with the
467
+ suffix stripped."""
468
+ entry = self.get()
469
+ return SCons.Subst.SpecialAttrWrapper(SCons.Util.splitext(entry.get_path())[0],
470
+ entry.name + "_base")
471
+
472
+ def __get_posix_path(self):
473
+ """Return the path with / as the path separator,
474
+ regardless of platform."""
475
+ if os_sep_is_slash:
476
+ return self
477
+ else:
478
+ entry = self.get()
479
+ r = entry.get_path().replace(OS_SEP, '/')
480
+ return SCons.Subst.SpecialAttrWrapper(r, entry.name + "_posix")
481
+
482
+ def __get_windows_path(self):
483
+ r"""Return the path with \ as the path separator,
484
+ regardless of platform."""
485
+ if OS_SEP == '\\':
486
+ return self
487
+ else:
488
+ entry = self.get()
489
+ r = entry.get_path().replace(OS_SEP, '\\')
490
+ return SCons.Subst.SpecialAttrWrapper(r, entry.name + "_windows")
491
+
492
+ def __get_srcnode(self):
493
+ return EntryProxy(self.get().srcnode())
494
+
495
+ def __get_srcdir(self):
496
+ """Returns the directory containing the source node linked to this
497
+ node via VariantDir(), or the directory of this node if not linked."""
498
+ return EntryProxy(self.get().srcnode().dir)
499
+
500
+ def __get_rsrcnode(self):
501
+ return EntryProxy(self.get().srcnode().rfile())
502
+
503
+ def __get_rsrcdir(self):
504
+ """Returns the directory containing the source node linked to this
505
+ node via VariantDir(), or the directory of this node if not linked."""
506
+ return EntryProxy(self.get().srcnode().rfile().dir)
507
+
508
+ def __get_dir(self):
509
+ return EntryProxy(self.get().dir)
510
+
511
+ dictSpecialAttrs = { "base" : __get_base_path,
512
+ "posix" : __get_posix_path,
513
+ "windows" : __get_windows_path,
514
+ "win32" : __get_windows_path,
515
+ "srcpath" : __get_srcnode,
516
+ "srcdir" : __get_srcdir,
517
+ "dir" : __get_dir,
518
+ "abspath" : __get_abspath,
519
+ "relpath" : __get_relpath,
520
+ "filebase" : __get_filebase,
521
+ "suffix" : __get_suffix,
522
+ "file" : __get_file,
523
+ "rsrcpath" : __get_rsrcnode,
524
+ "rsrcdir" : __get_rsrcdir,
525
+ }
526
+
527
+ def __getattr__(self, name):
528
+ # This is how we implement the "special" attributes
529
+ # such as base, posix, srcdir, etc.
530
+ try:
531
+ attr_function = self.dictSpecialAttrs[name]
532
+ except KeyError:
533
+ try:
534
+ attr = SCons.Util.Proxy.__getattr__(self, name)
535
+ except AttributeError:
536
+ # Raise our own AttributeError subclass with an
537
+ # overridden __str__() method that identifies the
538
+ # name of the entry that caused the exception.
539
+ raise EntryProxyAttributeError(self, name)
540
+ return attr
541
+ else:
542
+ return attr_function(self)
543
+
544
+
545
+ class Base(SCons.Node.Node):
546
+ """A generic class for file system entries. This class is for
547
+ when we don't know yet whether the entry being looked up is a file
548
+ or a directory. Instances of this class can morph into either
549
+ Dir or File objects by a later, more precise lookup.
550
+
551
+ Note: this class does not define __cmp__ and __hash__ for
552
+ efficiency reasons. SCons does a lot of comparing of
553
+ Node.FS.{Base,Entry,File,Dir} objects, so those operations must be
554
+ as fast as possible, which means we want to use Python's built-in
555
+ object identity comparisons.
556
+ """
557
+
558
+ __slots__ = ['name',
559
+ 'fs',
560
+ '_abspath',
561
+ '_labspath',
562
+ '_path',
563
+ '_tpath',
564
+ '_path_elements',
565
+ 'dir',
566
+ 'cwd',
567
+ 'duplicate',
568
+ '_local',
569
+ 'sbuilder',
570
+ '_proxy',
571
+ '_func_sconsign']
572
+
573
+ def __init__(self, name, directory, fs):
574
+ """Initialize a generic Node.FS.Base object.
575
+
576
+ Call the superclass initialization, take care of setting up
577
+ our relative and absolute paths, identify our parent
578
+ directory, and indicate that this node should use
579
+ signatures."""
580
+
581
+ if SCons.Debug.track_instances: logInstanceCreation(self, 'Node.FS.Base')
582
+ SCons.Node.Node.__init__(self)
583
+
584
+ # Filenames and paths are probably reused and are intern'ed to save some memory.
585
+ # Filename with extension as it was specified when the object was
586
+ # created; to obtain filesystem path, use Python str() function
587
+ self.name = SCons.Util.silent_intern(name)
588
+ self.fs = fs #: Reference to parent Node.FS object
589
+
590
+ assert directory, "A directory must be provided"
591
+
592
+ self._abspath = None
593
+ self._labspath = None
594
+ self._path = None
595
+ self._tpath = None
596
+ self._path_elements = None
597
+
598
+ self.dir = directory
599
+ self.cwd = None # will hold the SConscript directory for target nodes
600
+ self.duplicate = directory.duplicate
601
+ self.changed_since_last_build = 2
602
+ self._func_sconsign = 0
603
+ self._func_exists = 2
604
+ self._func_rexists = 2
605
+ self._func_get_contents = 0
606
+ self._func_target_from_source = 1
607
+ self.store_info = 1
608
+
609
+ def str_for_display(self):
610
+ return '"' + self.__str__() + '"'
611
+
612
+ def must_be_same(self, klass):
613
+ """
614
+ This node, which already existed, is being looked up as the
615
+ specified klass. Raise an exception if it isn't.
616
+ """
617
+ if isinstance(self, klass) or klass is Entry:
618
+ return
619
+ raise TypeError("Tried to lookup %s '%s' as a %s." %\
620
+ (self.__class__.__name__, self.get_internal_path(), klass.__name__))
621
+
622
+ def get_dir(self):
623
+ return self.dir
624
+
625
+ def get_suffix(self):
626
+ return SCons.Util.splitext(self.name)[1]
627
+
628
+ def rfile(self):
629
+ return self
630
+
631
+ def __getattr__(self, attr):
632
+ """ Together with the node_bwcomp dict defined below,
633
+ this method provides a simple backward compatibility
634
+ layer for the Node attributes 'abspath', 'labspath',
635
+ 'path', 'tpath', 'suffix' and 'path_elements'. These Node
636
+ attributes used to be directly available in v2.3 and earlier, but
637
+ have been replaced by getter methods that initialize the
638
+ single variables lazily when required, in order to save memory.
639
+ The redirection to the getters lets older Tools and
640
+ SConstruct continue to work without any additional changes,
641
+ fully transparent to the user.
642
+ Note, that __getattr__ is only called as fallback when the
643
+ requested attribute can't be found, so there should be no
644
+ speed performance penalty involved for standard builds.
645
+ """
646
+ if attr in node_bwcomp:
647
+ return node_bwcomp[attr](self)
648
+
649
+ raise AttributeError("%r object has no attribute %r" %
650
+ (self.__class__, attr))
651
+
652
+ def __str__(self):
653
+ """A Node.FS.Base object's string representation is its path
654
+ name."""
655
+ global Save_Strings
656
+ if Save_Strings:
657
+ return self._save_str()
658
+ return self._get_str()
659
+
660
+ def __lt__(self, other):
661
+ """ less than operator used by sorting on py3"""
662
+ return str(self) < str(other)
663
+
664
+ @SCons.Memoize.CountMethodCall
665
+ def _save_str(self):
666
+ try:
667
+ return self._memo['_save_str']
668
+ except KeyError:
669
+ pass
670
+ result = SCons.Util.silent_intern(self._get_str())
671
+ self._memo['_save_str'] = result
672
+ return result
673
+
674
+ def _get_str(self):
675
+ global Save_Strings
676
+ if self.duplicate or self.is_derived():
677
+ return self.get_path()
678
+ srcnode = self.srcnode()
679
+ if srcnode.stat() is None and self.stat() is not None:
680
+ result = self.get_path()
681
+ else:
682
+ result = srcnode.get_path()
683
+ if not Save_Strings:
684
+ # We're not at the point where we're saving the string
685
+ # representations of FS Nodes (because we haven't finished
686
+ # reading the SConscript files and need to have str() return
687
+ # things relative to them). That also means we can't yet
688
+ # cache values returned (or not returned) by stat(), since
689
+ # Python code in the SConscript files might still create
690
+ # or otherwise affect the on-disk file. So get rid of the
691
+ # values that the underlying stat() method saved.
692
+ try: del self._memo['stat']
693
+ except KeyError: pass
694
+ if self is not srcnode:
695
+ try: del srcnode._memo['stat']
696
+ except KeyError: pass
697
+ return result
698
+
699
+ rstr = __str__
700
+
701
+ @SCons.Memoize.CountMethodCall
702
+ def stat(self):
703
+ try:
704
+ return self._memo['stat']
705
+ except KeyError:
706
+ pass
707
+ try:
708
+ result = self.fs.stat(self.get_abspath())
709
+ except os.error:
710
+ result = None
711
+
712
+ self._memo['stat'] = result
713
+ return result
714
+
715
+ @SCons.Memoize.CountMethodCall
716
+ def lstat(self):
717
+ try:
718
+ return self._memo['lstat']
719
+ except KeyError:
720
+ pass
721
+ try:
722
+ result = self.fs.lstat(self.get_abspath())
723
+ except os.error:
724
+ result = None
725
+
726
+ self._memo['lstat'] = result
727
+ return result
728
+
729
+ def exists(self):
730
+ return SCons.Node._exists_map[self._func_exists](self)
731
+
732
+ def rexists(self):
733
+ return SCons.Node._rexists_map[self._func_rexists](self)
734
+
735
+ def getmtime(self):
736
+ if self.islink():
737
+ st = self.lstat()
738
+ else:
739
+ st = self.stat()
740
+
741
+ if st:
742
+ return st[stat.ST_MTIME]
743
+ else:
744
+ return None
745
+
746
+ def getsize(self):
747
+ if self.islink():
748
+ st = self.lstat()
749
+ else:
750
+ st = self.stat()
751
+
752
+ if st:
753
+ return st[stat.ST_SIZE]
754
+ else:
755
+ return None
756
+
757
+ def isdir(self):
758
+ st = self.stat()
759
+ return st is not None and stat.S_ISDIR(st[stat.ST_MODE])
760
+
761
+ def isfile(self):
762
+ st = self.stat()
763
+ return st is not None and stat.S_ISREG(st[stat.ST_MODE])
764
+
765
+ if hasattr(os, 'symlink'):
766
+ def islink(self):
767
+ st = self.lstat()
768
+ return st is not None and stat.S_ISLNK(st[stat.ST_MODE])
769
+ else:
770
+ def islink(self):
771
+ return False # no symlinks
772
+
773
+ def is_under(self, dir):
774
+ if self is dir:
775
+ return 1
776
+ else:
777
+ return self.dir.is_under(dir)
778
+
779
+ def set_local(self):
780
+ self._local = 1
781
+
782
+ def srcnode(self):
783
+ """If this node is in a build path, return the node
784
+ corresponding to its source file. Otherwise, return
785
+ ourself.
786
+ """
787
+ srcdir_list = self.dir.srcdir_list()
788
+ if srcdir_list:
789
+ srcnode = srcdir_list[0].Entry(self.name)
790
+ srcnode.must_be_same(self.__class__)
791
+ return srcnode
792
+ return self
793
+
794
+ def get_path(self, dir=None):
795
+ """Return path relative to the current working directory of the
796
+ Node.FS.Base object that owns us."""
797
+ if not dir:
798
+ dir = self.fs.getcwd()
799
+ if self == dir:
800
+ return '.'
801
+ path_elems = self.get_path_elements()
802
+ pathname = ''
803
+ try: i = path_elems.index(dir)
804
+ except ValueError:
805
+ for p in path_elems[:-1]:
806
+ pathname += p.dirname
807
+ else:
808
+ for p in path_elems[i+1:-1]:
809
+ pathname += p.dirname
810
+ return pathname + path_elems[-1].name
811
+
812
+ def set_src_builder(self, builder):
813
+ """Set the source code builder for this node."""
814
+ self.sbuilder = builder
815
+ if not self.has_builder():
816
+ self.builder_set(builder)
817
+
818
+ def src_builder(self):
819
+ """Fetch the source code builder for this node.
820
+
821
+ If there isn't one, we cache the source code builder specified
822
+ for the directory (which in turn will cache the value from its
823
+ parent directory, and so on up to the file system root).
824
+ """
825
+ try:
826
+ scb = self.sbuilder
827
+ except AttributeError:
828
+ scb = self.dir.src_builder()
829
+ self.sbuilder = scb
830
+ return scb
831
+
832
+ def get_abspath(self):
833
+ """Get the absolute path of the file."""
834
+ return self.dir.entry_abspath(self.name)
835
+
836
+ def get_labspath(self):
837
+ """Get the absolute path of the file."""
838
+ return self.dir.entry_labspath(self.name)
839
+
840
+ def get_relpath(self):
841
+ """Get the path of the file relative to the root SConstruct file's directory."""
842
+ return os.path.relpath(self.dir.entry_abspath(self.name), self.fs.SConstruct_dir.get_abspath())
843
+
844
+ def get_internal_path(self):
845
+ if self.dir._path == '.':
846
+ return self.name
847
+ else:
848
+ return self.dir.entry_path(self.name)
849
+
850
+ def get_tpath(self):
851
+ if self.dir._tpath == '.':
852
+ return self.name
853
+ else:
854
+ return self.dir.entry_tpath(self.name)
855
+
856
+ def get_path_elements(self):
857
+ return self.dir._path_elements + [self]
858
+
859
+ def for_signature(self):
860
+ # Return just our name. Even an absolute path would not work,
861
+ # because that can change thanks to symlinks or remapped network
862
+ # paths.
863
+ return self.name
864
+
865
+ def get_subst_proxy(self):
866
+ try:
867
+ return self._proxy
868
+ except AttributeError:
869
+ ret = EntryProxy(self)
870
+ self._proxy = ret
871
+ return ret
872
+
873
+ def target_from_source(self, prefix, suffix, splitext=SCons.Util.splitext):
874
+ """
875
+
876
+ Generates a target entry that corresponds to this entry (usually
877
+ a source file) with the specified prefix and suffix.
878
+
879
+ Note that this method can be overridden dynamically for generated
880
+ files that need different behavior. See Tool/swig.py for
881
+ an example.
882
+ """
883
+ return SCons.Node._target_from_source_map[self._func_target_from_source](self, prefix, suffix, splitext)
884
+
885
+ def _Rfindalldirs_key(self, pathlist):
886
+ return pathlist
887
+
888
+ @SCons.Memoize.CountDictCall(_Rfindalldirs_key)
889
+ def Rfindalldirs(self, pathlist):
890
+ """
891
+ Return all of the directories for a given path list, including
892
+ corresponding "backing" directories in any repositories.
893
+
894
+ The Node lookups are relative to this Node (typically a
895
+ directory), so memoizing result saves cycles from looking
896
+ up the same path for each target in a given directory.
897
+ """
898
+ try:
899
+ memo_dict = self._memo['Rfindalldirs']
900
+ except KeyError:
901
+ memo_dict = {}
902
+ self._memo['Rfindalldirs'] = memo_dict
903
+ else:
904
+ try:
905
+ return memo_dict[pathlist]
906
+ except KeyError:
907
+ pass
908
+
909
+ create_dir_relative_to_self = self.Dir
910
+ result = []
911
+ for path in pathlist:
912
+ if isinstance(path, SCons.Node.Node):
913
+ result.append(path)
914
+ else:
915
+ dir = create_dir_relative_to_self(path)
916
+ result.extend(dir.get_all_rdirs())
917
+
918
+ memo_dict[pathlist] = result
919
+
920
+ return result
921
+
922
+ def RDirs(self, pathlist):
923
+ """Search for a list of directories in the Repository list."""
924
+ cwd = self.cwd or self.fs._cwd
925
+ return cwd.Rfindalldirs(pathlist)
926
+
927
+ @SCons.Memoize.CountMethodCall
928
+ def rentry(self):
929
+ try:
930
+ return self._memo['rentry']
931
+ except KeyError:
932
+ pass
933
+ result = self
934
+ if not self.exists():
935
+ norm_name = _my_normcase(self.name)
936
+ for dir in self.dir.get_all_rdirs():
937
+ try:
938
+ node = dir.entries[norm_name]
939
+ except KeyError:
940
+ if dir.entry_exists_on_disk(self.name):
941
+ result = dir.Entry(self.name)
942
+ break
943
+ self._memo['rentry'] = result
944
+ return result
945
+
946
+ def _glob1(self, pattern, ondisk=True, source=False, strings=False):
947
+ return []
948
+
949
+ # Dict that provides a simple backward compatibility
950
+ # layer for the Node attributes 'abspath', 'labspath',
951
+ # 'relpath', 'path', 'tpath' and 'path_elements'.
952
+ # @see Base.__getattr__ above
953
+ node_bwcomp = {'abspath' : Base.get_abspath,
954
+ 'labspath' : Base.get_labspath,
955
+ 'relpath' : Base.get_relpath,
956
+ 'path' : Base.get_internal_path,
957
+ 'tpath' : Base.get_tpath,
958
+ 'path_elements' : Base.get_path_elements,
959
+ 'suffix' : Base.get_suffix}
960
+
961
+ class Entry(Base):
962
+ """This is the class for generic Node.FS entries--that is, things
963
+ that could be a File or a Dir, but we're just not sure yet.
964
+ Consequently, the methods in this class really exist just to
965
+ transform their associated object into the right class when the
966
+ time comes, and then call the same-named method in the transformed
967
+ class."""
968
+
969
+ __slots__ = ['scanner_paths',
970
+ 'cachedir_csig',
971
+ 'cachesig',
972
+ 'repositories',
973
+ 'srcdir',
974
+ 'entries',
975
+ 'searched',
976
+ '_sconsign',
977
+ 'variant_dirs',
978
+ 'root',
979
+ 'dirname',
980
+ 'on_disk_entries',
981
+ 'released_target_info',
982
+ 'contentsig']
983
+
984
+ def __init__(self, name, directory, fs):
985
+ Base.__init__(self, name, directory, fs)
986
+ self._func_exists = 3
987
+ self._func_get_contents = 1
988
+
989
+ def diskcheck_match(self):
990
+ pass
991
+
992
+ def disambiguate(self, must_exist=None):
993
+ """
994
+ """
995
+ if self.isfile():
996
+ self.__class__ = File
997
+ self._morph()
998
+ self.clear()
999
+ elif self.isdir():
1000
+ self.__class__ = Dir
1001
+ self._morph()
1002
+ else:
1003
+ # There was nothing on-disk at this location, so look in
1004
+ # the src directory.
1005
+ #
1006
+ # We can't just use self.srcnode() straight away because
1007
+ # that would create an actual Node for this file in the src
1008
+ # directory, and there might not be one. Instead, use the
1009
+ # dir_on_disk() method to see if there's something on-disk
1010
+ # with that name, in which case we can go ahead and call
1011
+ # self.srcnode() to create the right type of entry.
1012
+ srcdir = self.dir.srcnode()
1013
+ if srcdir != self.dir and \
1014
+ srcdir.entry_exists_on_disk(self.name) and \
1015
+ self.srcnode().isdir():
1016
+ self.__class__ = Dir
1017
+ self._morph()
1018
+ elif must_exist:
1019
+ msg = "No such file or directory: '%s'" % self.get_abspath()
1020
+ raise SCons.Errors.UserError(msg)
1021
+ else:
1022
+ self.__class__ = File
1023
+ self._morph()
1024
+ self.clear()
1025
+ return self
1026
+
1027
+ def rfile(self):
1028
+ """We're a generic Entry, but the caller is actually looking for
1029
+ a File at this point, so morph into one."""
1030
+ self.__class__ = File
1031
+ self._morph()
1032
+ self.clear()
1033
+ return File.rfile(self)
1034
+
1035
+ def scanner_key(self):
1036
+ return self.get_suffix()
1037
+
1038
+ def get_contents(self):
1039
+ """Fetch the contents of the entry. Returns the exact binary
1040
+ contents of the file."""
1041
+ return SCons.Node._get_contents_map[self._func_get_contents](self)
1042
+
1043
+ def get_text_contents(self):
1044
+ """Fetch the decoded text contents of a Unicode encoded Entry.
1045
+
1046
+ Since this should return the text contents from the file
1047
+ system, we check to see into what sort of subclass we should
1048
+ morph this Entry."""
1049
+ try:
1050
+ self = self.disambiguate(must_exist=1)
1051
+ except SCons.Errors.UserError:
1052
+ # There was nothing on disk with which to disambiguate
1053
+ # this entry. Leave it as an Entry, but return a null
1054
+ # string so calls to get_text_contents() in emitters and
1055
+ # the like (e.g. in qt.py) don't have to disambiguate by
1056
+ # hand or catch the exception.
1057
+ return ''
1058
+ else:
1059
+ return self.get_text_contents()
1060
+
1061
+ def must_be_same(self, klass):
1062
+ """Called to make sure a Node is a Dir. Since we're an
1063
+ Entry, we can morph into one."""
1064
+ if self.__class__ is not klass:
1065
+ self.__class__ = klass
1066
+ self._morph()
1067
+ self.clear()
1068
+
1069
+ # The following methods can get called before the Taskmaster has
1070
+ # had a chance to call disambiguate() directly to see if this Entry
1071
+ # should really be a Dir or a File. We therefore use these to call
1072
+ # disambiguate() transparently (from our caller's point of view).
1073
+ #
1074
+ # Right now, this minimal set of methods has been derived by just
1075
+ # looking at some of the methods that will obviously be called early
1076
+ # in any of the various Taskmasters' calling sequences, and then
1077
+ # empirically figuring out which additional methods are necessary
1078
+ # to make various tests pass.
1079
+
1080
+ def exists(self):
1081
+ return SCons.Node._exists_map[self._func_exists](self)
1082
+
1083
+ def rel_path(self, other):
1084
+ d = self.disambiguate()
1085
+ if d.__class__ is Entry:
1086
+ raise Exception("rel_path() could not disambiguate File/Dir")
1087
+ return d.rel_path(other)
1088
+
1089
+ def new_ninfo(self):
1090
+ return self.disambiguate().new_ninfo()
1091
+
1092
+ def _glob1(self, pattern, ondisk=True, source=False, strings=False):
1093
+ return self.disambiguate()._glob1(pattern, ondisk, source, strings)
1094
+
1095
+ def get_subst_proxy(self):
1096
+ return self.disambiguate().get_subst_proxy()
1097
+
1098
+ # This is for later so we can differentiate between Entry the class and Entry
1099
+ # the method of the FS class.
1100
+ _classEntry = Entry
1101
+
1102
+
1103
+ class LocalFS:
1104
+ """
1105
+ This class implements an abstraction layer for operations involving
1106
+ a local file system. Essentially, this wraps any function in
1107
+ the os, os.path or shutil modules that we use to actually go do
1108
+ anything with or to the local file system.
1109
+
1110
+ Note that there's a very good chance we'll refactor this part of
1111
+ the architecture in some way as we really implement the interface(s)
1112
+ for remote file system Nodes. For example, the right architecture
1113
+ might be to have this be a subclass instead of a base class.
1114
+ Nevertheless, we're using this as a first step in that direction.
1115
+
1116
+ We're not using chdir() yet because the calling subclass method
1117
+ needs to use os.chdir() directly to avoid recursion. Will we
1118
+ really need this one?
1119
+ """
1120
+
1121
+ def chmod(self, path, mode):
1122
+ return os.chmod(path, mode)
1123
+
1124
+ def copy(self, src, dst):
1125
+ return shutil.copy(src, dst)
1126
+
1127
+ def copy2(self, src, dst):
1128
+ return shutil.copy2(src, dst)
1129
+
1130
+ def exists(self, path):
1131
+ return os.path.exists(path)
1132
+
1133
+ def getmtime(self, path):
1134
+ return os.path.getmtime(path)
1135
+
1136
+ def getsize(self, path):
1137
+ return os.path.getsize(path)
1138
+
1139
+ def isdir(self, path):
1140
+ return os.path.isdir(path)
1141
+
1142
+ def isfile(self, path):
1143
+ return os.path.isfile(path)
1144
+
1145
+ def link(self, src, dst):
1146
+ return os.link(src, dst)
1147
+
1148
+ def lstat(self, path):
1149
+ return os.lstat(path)
1150
+
1151
+ def listdir(self, path):
1152
+ return os.listdir(path)
1153
+
1154
+ def scandir(self, path):
1155
+ return os.scandir(path)
1156
+
1157
+ def makedirs(self, path, mode=0o777, exist_ok=False):
1158
+ return os.makedirs(path, mode=mode, exist_ok=exist_ok)
1159
+
1160
+ def mkdir(self, path, mode=0o777):
1161
+ return os.mkdir(path, mode=mode)
1162
+
1163
+ def rename(self, old, new):
1164
+ return os.rename(old, new)
1165
+
1166
+ def stat(self, path):
1167
+ return os.stat(path)
1168
+
1169
+ def symlink(self, src, dst):
1170
+ return os.symlink(src, dst)
1171
+
1172
+ def open(self, path):
1173
+ return open(path)
1174
+
1175
+ def unlink(self, path):
1176
+ return os.unlink(path)
1177
+
1178
+ if hasattr(os, 'symlink'):
1179
+
1180
+ def islink(self, path):
1181
+ return os.path.islink(path)
1182
+
1183
+ else:
1184
+
1185
+ def islink(self, path):
1186
+ return False # no symlinks
1187
+
1188
+ if hasattr(os, 'readlink'):
1189
+
1190
+ def readlink(self, file):
1191
+ return os.readlink(file)
1192
+
1193
+ else:
1194
+
1195
+ def readlink(self, file):
1196
+ return ''
1197
+
1198
+
1199
+ class FS(LocalFS):
1200
+
1201
+ def __init__(self, path = None):
1202
+ """Initialize the Node.FS subsystem.
1203
+
1204
+ The supplied path is the top of the source tree, where we
1205
+ expect to find the top-level build file. If no path is
1206
+ supplied, the current directory is the default.
1207
+
1208
+ The path argument must be a valid absolute path.
1209
+ """
1210
+ if SCons.Debug.track_instances: logInstanceCreation(self, 'Node.FS')
1211
+
1212
+ self._memo = {}
1213
+
1214
+ self.Root = {}
1215
+ self.SConstruct_dir = None
1216
+ self.max_drift = default_max_drift
1217
+
1218
+ self.Top = None
1219
+ if path is None:
1220
+ self.pathTop = os.getcwd()
1221
+ else:
1222
+ self.pathTop = path
1223
+ self.defaultDrive = _my_normcase(_my_splitdrive(self.pathTop)[0])
1224
+
1225
+ self.Top = self.Dir(self.pathTop)
1226
+ self.Top._path = '.'
1227
+ self.Top._tpath = '.'
1228
+ self._cwd = self.Top
1229
+
1230
+ DirNodeInfo.fs = self
1231
+ FileNodeInfo.fs = self
1232
+
1233
+ def set_SConstruct_dir(self, dir):
1234
+ self.SConstruct_dir = dir
1235
+
1236
+ def get_max_drift(self):
1237
+ return self.max_drift
1238
+
1239
+ def set_max_drift(self, max_drift):
1240
+ self.max_drift = max_drift
1241
+
1242
+ def getcwd(self):
1243
+ if hasattr(self, "_cwd"):
1244
+ return self._cwd
1245
+ else:
1246
+ return "<no cwd>"
1247
+
1248
+ def chdir(self, dir, change_os_dir=0):
1249
+ """Change the current working directory for lookups.
1250
+ If change_os_dir is true, we will also change the "real" cwd
1251
+ to match.
1252
+ """
1253
+ curr=self._cwd
1254
+ try:
1255
+ if dir is not None:
1256
+ self._cwd = dir
1257
+ if change_os_dir:
1258
+ os.chdir(dir.get_abspath())
1259
+ except OSError:
1260
+ self._cwd = curr
1261
+ raise
1262
+
1263
+ def get_root(self, drive):
1264
+ """
1265
+ Returns the root directory for the specified drive, creating
1266
+ it if necessary.
1267
+ """
1268
+ drive = _my_normcase(drive)
1269
+ try:
1270
+ return self.Root[drive]
1271
+ except KeyError:
1272
+ root = RootDir(drive, self)
1273
+ self.Root[drive] = root
1274
+ if not drive:
1275
+ self.Root[self.defaultDrive] = root
1276
+ elif drive == self.defaultDrive:
1277
+ self.Root[''] = root
1278
+ return root
1279
+
1280
+ def _lookup(self, p, directory, fsclass, create=1):
1281
+ """
1282
+ The generic entry point for Node lookup with user-supplied data.
1283
+
1284
+ This translates arbitrary input into a canonical Node.FS object
1285
+ of the specified fsclass. The general approach for strings is
1286
+ to turn it into a fully normalized absolute path and then call
1287
+ the root directory's lookup_abs() method for the heavy lifting.
1288
+
1289
+ If the path name begins with '#', it is unconditionally
1290
+ interpreted relative to the top-level directory of this FS. '#'
1291
+ is treated as a synonym for the top-level SConstruct directory,
1292
+ much like '~' is treated as a synonym for the user's home
1293
+ directory in a UNIX shell. So both '#foo' and '#/foo' refer
1294
+ to the 'foo' subdirectory underneath the top-level SConstruct
1295
+ directory.
1296
+
1297
+ If the path name is relative, then the path is looked up relative
1298
+ to the specified directory, or the current directory (self._cwd,
1299
+ typically the SConscript directory) if the specified directory
1300
+ is None.
1301
+ """
1302
+ if isinstance(p, Base):
1303
+ # It's already a Node.FS object. Make sure it's the right
1304
+ # class and return.
1305
+ p.must_be_same(fsclass)
1306
+ return p
1307
+ # str(p) in case it's something like a proxy object
1308
+ p = str(p)
1309
+
1310
+ if not os_sep_is_slash:
1311
+ p = p.replace(OS_SEP, '/')
1312
+
1313
+ if p[0:1] == '#':
1314
+ # There was an initial '#', so we strip it and override
1315
+ # whatever directory they may have specified with the
1316
+ # top-level SConstruct directory.
1317
+ p = p[1:]
1318
+ directory = self.Top
1319
+
1320
+ # There might be a drive letter following the
1321
+ # '#'. Although it is not described in the SCons man page,
1322
+ # the regression test suite explicitly tests for that
1323
+ # syntax. It seems to mean the following thing:
1324
+ #
1325
+ # Assuming the the SCons top dir is in C:/xxx/yyy,
1326
+ # '#X:/toto' means X:/xxx/yyy/toto.
1327
+ #
1328
+ # i.e. it assumes that the X: drive has a directory
1329
+ # structure similar to the one found on drive C:.
1330
+ if do_splitdrive:
1331
+ drive, p = _my_splitdrive(p)
1332
+ if drive:
1333
+ root = self.get_root(drive)
1334
+ else:
1335
+ root = directory.root
1336
+ else:
1337
+ root = directory.root
1338
+
1339
+ # We can only strip trailing after splitting the drive
1340
+ # since the drive might the UNC '//' prefix.
1341
+ p = p.strip('/')
1342
+
1343
+ needs_normpath = needs_normpath_match(p)
1344
+
1345
+ # The path is relative to the top-level SCons directory.
1346
+ if p in ('', '.'):
1347
+ p = directory.get_labspath()
1348
+ else:
1349
+ p = directory.get_labspath() + '/' + p
1350
+ else:
1351
+ if do_splitdrive:
1352
+ drive, p = _my_splitdrive(p)
1353
+ if drive and not p:
1354
+ # This causes a naked drive letter to be treated
1355
+ # as a synonym for the root directory on that
1356
+ # drive.
1357
+ p = '/'
1358
+ else:
1359
+ drive = ''
1360
+
1361
+ # We can only strip trailing '/' since the drive might the
1362
+ # UNC '//' prefix.
1363
+ if p != '/':
1364
+ p = p.rstrip('/')
1365
+
1366
+ needs_normpath = needs_normpath_match(p)
1367
+
1368
+ if p[0:1] == '/':
1369
+ # Absolute path
1370
+ root = self.get_root(drive)
1371
+ else:
1372
+ # This is a relative lookup or to the current directory
1373
+ # (the path name is not absolute). Add the string to the
1374
+ # appropriate directory lookup path, after which the whole
1375
+ # thing gets normalized.
1376
+ if directory:
1377
+ if not isinstance(directory, Dir):
1378
+ directory = self.Dir(directory)
1379
+ else:
1380
+ directory = self._cwd
1381
+
1382
+ if p in ('', '.'):
1383
+ p = directory.get_labspath()
1384
+ else:
1385
+ p = directory.get_labspath() + '/' + p
1386
+
1387
+ if drive:
1388
+ root = self.get_root(drive)
1389
+ else:
1390
+ root = directory.root
1391
+
1392
+ if needs_normpath is not None:
1393
+ # Normalize a pathname. Will return the same result for
1394
+ # equivalent paths.
1395
+ #
1396
+ # We take advantage of the fact that we have an absolute
1397
+ # path here for sure. In addition, we know that the
1398
+ # components of lookup path are separated by slashes at
1399
+ # this point. Because of this, this code is about 2X
1400
+ # faster than calling os.path.normpath() followed by
1401
+ # replacing os.sep with '/' again.
1402
+ ins = p.split('/')[1:]
1403
+ outs = []
1404
+ for d in ins:
1405
+ if d == '..':
1406
+ try:
1407
+ outs.pop()
1408
+ except IndexError:
1409
+ pass
1410
+ elif d not in ('', '.'):
1411
+ outs.append(d)
1412
+ p = '/' + '/'.join(outs)
1413
+
1414
+ return root._lookup_abs(p, fsclass, create)
1415
+
1416
+ def Entry(self, name, directory = None, create = 1):
1417
+ """Look up or create a generic Entry node with the specified name.
1418
+ If the name is a relative path (begins with ./, ../, or a file
1419
+ name), then it is looked up relative to the supplied directory
1420
+ node, or to the top level directory of the FS (supplied at
1421
+ construction time) if no directory is supplied.
1422
+ """
1423
+ return self._lookup(name, directory, Entry, create)
1424
+
1425
+ def File(self, name, directory = None, create = 1):
1426
+ """Look up or create a File node with the specified name. If
1427
+ the name is a relative path (begins with ./, ../, or a file name),
1428
+ then it is looked up relative to the supplied directory node,
1429
+ or to the top level directory of the FS (supplied at construction
1430
+ time) if no directory is supplied.
1431
+
1432
+ This method will raise TypeError if a directory is found at the
1433
+ specified path.
1434
+ """
1435
+ return self._lookup(name, directory, File, create)
1436
+
1437
+ def Dir(self, name, directory = None, create = True):
1438
+ """Look up or create a Dir node with the specified name. If
1439
+ the name is a relative path (begins with ./, ../, or a file name),
1440
+ then it is looked up relative to the supplied directory node,
1441
+ or to the top level directory of the FS (supplied at construction
1442
+ time) if no directory is supplied.
1443
+
1444
+ This method will raise TypeError if a normal file is found at the
1445
+ specified path.
1446
+ """
1447
+ return self._lookup(name, directory, Dir, create)
1448
+
1449
+ def VariantDir(self, variant_dir, src_dir, duplicate=1):
1450
+ """Link the supplied variant directory to the source directory
1451
+ for purposes of building files."""
1452
+
1453
+ if not isinstance(src_dir, SCons.Node.Node):
1454
+ src_dir = self.Dir(src_dir)
1455
+ if not isinstance(variant_dir, SCons.Node.Node):
1456
+ variant_dir = self.Dir(variant_dir)
1457
+ if src_dir.is_under(variant_dir):
1458
+ raise SCons.Errors.UserError("Source directory cannot be under variant directory.")
1459
+ if variant_dir.srcdir:
1460
+ if variant_dir.srcdir == src_dir:
1461
+ return # We already did this.
1462
+ raise SCons.Errors.UserError("'%s' already has a source directory: '%s'."%(variant_dir, variant_dir.srcdir))
1463
+ variant_dir.link(src_dir, duplicate)
1464
+
1465
+ def Repository(self, *dirs):
1466
+ """Specify Repository directories to search."""
1467
+ for d in dirs:
1468
+ if not isinstance(d, SCons.Node.Node):
1469
+ d = self.Dir(d)
1470
+ self.Top.addRepository(d)
1471
+
1472
+ def PyPackageDir(self, modulename):
1473
+ r"""Locate the directory of a given python module name
1474
+
1475
+ For example scons might resolve to
1476
+ Windows: C:\Python27\Lib\site-packages\scons-2.5.1
1477
+ Linux: /usr/lib/scons
1478
+
1479
+ This can be useful when we want to determine a toolpath based on a python module name"""
1480
+
1481
+ dirpath = ''
1482
+
1483
+ # Python3 Code
1484
+ modspec = importlib.util.find_spec(modulename)
1485
+ dirpath = os.path.dirname(modspec.origin)
1486
+ return self._lookup(dirpath, None, Dir, True)
1487
+
1488
+
1489
+ def variant_dir_target_climb(self, orig, dir, tail):
1490
+ """Create targets in corresponding variant directories
1491
+
1492
+ Climb the directory tree, and look up path names
1493
+ relative to any linked variant directories we find.
1494
+
1495
+ Even though this loops and walks up the tree, we don't memoize
1496
+ the return value because this is really only used to process
1497
+ the command-line targets.
1498
+ """
1499
+ targets = []
1500
+ message = None
1501
+ fmt = "building associated VariantDir targets: %s"
1502
+ start_dir = dir
1503
+ while dir:
1504
+ for bd in dir.variant_dirs:
1505
+ if start_dir.is_under(bd):
1506
+ # If already in the build-dir location, don't reflect
1507
+ return [orig], fmt % str(orig)
1508
+ p = os.path.join(bd._path, *tail)
1509
+ targets.append(self.Entry(p))
1510
+ tail = [dir.name] + tail
1511
+ dir = dir.up()
1512
+ if targets:
1513
+ message = fmt % ' '.join(map(str, targets))
1514
+ return targets, message
1515
+
1516
+ def Glob(self, pathname, ondisk=True, source=True, strings=False, exclude=None, cwd=None):
1517
+ """
1518
+ Globs
1519
+
1520
+ This is mainly a shim layer
1521
+ """
1522
+ if cwd is None:
1523
+ cwd = self.getcwd()
1524
+ return cwd.glob(pathname, ondisk, source, strings, exclude)
1525
+
1526
+ class DirNodeInfo(SCons.Node.NodeInfoBase):
1527
+ __slots__ = ()
1528
+ # This should get reset by the FS initialization.
1529
+ current_version_id = 2
1530
+
1531
+ fs = None
1532
+
1533
+ def str_to_node(self, s):
1534
+ top = self.fs.Top
1535
+ root = top.root
1536
+ if do_splitdrive:
1537
+ drive, s = _my_splitdrive(s)
1538
+ if drive:
1539
+ root = self.fs.get_root(drive)
1540
+ if not os.path.isabs(s):
1541
+ s = top.get_labspath() + '/' + s
1542
+ return root._lookup_abs(s, Entry)
1543
+
1544
+ class DirBuildInfo(SCons.Node.BuildInfoBase):
1545
+ __slots__ = ()
1546
+ current_version_id = 2
1547
+
1548
+ glob_magic_check = re.compile('[*?[]')
1549
+
1550
+ def has_glob_magic(s):
1551
+ return glob_magic_check.search(s) is not None
1552
+
1553
+ class Dir(Base):
1554
+ """A class for directories in a file system.
1555
+ """
1556
+
1557
+ __slots__ = ['scanner_paths',
1558
+ 'cachedir_csig',
1559
+ 'cachesig',
1560
+ 'repositories',
1561
+ 'srcdir',
1562
+ 'entries',
1563
+ 'searched',
1564
+ '_sconsign',
1565
+ 'variant_dirs',
1566
+ 'root',
1567
+ 'dirname',
1568
+ 'on_disk_entries',
1569
+ 'released_target_info',
1570
+ 'contentsig']
1571
+
1572
+ NodeInfo = DirNodeInfo
1573
+ BuildInfo = DirBuildInfo
1574
+
1575
+ def __init__(self, name, directory, fs):
1576
+ if SCons.Debug.track_instances: logInstanceCreation(self, 'Node.FS.Dir')
1577
+ Base.__init__(self, name, directory, fs)
1578
+ self._morph()
1579
+
1580
+ def _morph(self):
1581
+ """Turn a file system Node (either a freshly initialized directory
1582
+ object or a separate Entry object) into a proper directory object.
1583
+
1584
+ Set up this directory's entries and hook it into the file
1585
+ system tree. Specify that directories (this Node) don't use
1586
+ signatures for calculating whether they're current.
1587
+ """
1588
+
1589
+ self.repositories = []
1590
+ self.srcdir = None
1591
+
1592
+ self.entries = {'.': self, '..': self.dir}
1593
+ self.cwd = self
1594
+ self.searched = 0
1595
+ self._sconsign = None
1596
+ self.variant_dirs = []
1597
+ self.root = self.dir.root
1598
+ self.changed_since_last_build = 3
1599
+ self._func_sconsign = 1
1600
+ self._func_exists = 2
1601
+ self._func_get_contents = 2
1602
+
1603
+ self._abspath = SCons.Util.silent_intern(self.dir.entry_abspath(self.name))
1604
+ self._labspath = SCons.Util.silent_intern(self.dir.entry_labspath(self.name))
1605
+ if self.dir._path == '.':
1606
+ self._path = SCons.Util.silent_intern(self.name)
1607
+ else:
1608
+ self._path = SCons.Util.silent_intern(self.dir.entry_path(self.name))
1609
+ if self.dir._tpath == '.':
1610
+ self._tpath = SCons.Util.silent_intern(self.name)
1611
+ else:
1612
+ self._tpath = SCons.Util.silent_intern(self.dir.entry_tpath(self.name))
1613
+ self._path_elements = self.dir._path_elements + [self]
1614
+
1615
+ # For directories, we make a difference between the directory
1616
+ # 'name' and the directory 'dirname'. The 'name' attribute is
1617
+ # used when we need to print the 'name' of the directory or
1618
+ # when we it is used as the last part of a path. The 'dirname'
1619
+ # is used when the directory is not the last element of the
1620
+ # path. The main reason for making that distinction is that
1621
+ # for RoorDir's the dirname can not be easily inferred from
1622
+ # the name. For example, we have to add a '/' after a drive
1623
+ # letter but not after a UNC path prefix ('//').
1624
+ self.dirname = self.name + OS_SEP
1625
+
1626
+ # Don't just reset the executor, replace its action list,
1627
+ # because it might have some pre-or post-actions that need to
1628
+ # be preserved.
1629
+ #
1630
+ # But don't reset the executor if there is a non-null executor
1631
+ # attached already. The existing executor might have other
1632
+ # targets, in which case replacing the action list with a
1633
+ # Mkdir action is a big mistake.
1634
+ if not hasattr(self, 'executor'):
1635
+ self.builder = get_MkdirBuilder()
1636
+ self.get_executor().set_action_list(self.builder.action)
1637
+ else:
1638
+ # Prepend MkdirBuilder action to existing action list
1639
+ l = self.get_executor().action_list
1640
+ a = get_MkdirBuilder().action
1641
+ l.insert(0, a)
1642
+ self.get_executor().set_action_list(l)
1643
+
1644
+ def diskcheck_match(self):
1645
+ diskcheck_match(self, self.isfile,
1646
+ "File %s found where directory expected.")
1647
+
1648
+ def __clearRepositoryCache(self, duplicate=None):
1649
+ """Called when we change the repository(ies) for a directory.
1650
+ This clears any cached information that is invalidated by changing
1651
+ the repository."""
1652
+
1653
+ for node in self.entries.values():
1654
+ if node != self.dir:
1655
+ if node != self and isinstance(node, Dir):
1656
+ node.__clearRepositoryCache(duplicate)
1657
+ else:
1658
+ node.clear()
1659
+ try:
1660
+ del node._srcreps
1661
+ except AttributeError:
1662
+ pass
1663
+ if duplicate is not None:
1664
+ node.duplicate = duplicate
1665
+
1666
+ def __resetDuplicate(self, node):
1667
+ if node != self:
1668
+ node.duplicate = node.get_dir().duplicate
1669
+
1670
+ def Entry(self, name):
1671
+ """
1672
+ Looks up or creates an entry node named 'name' relative to
1673
+ this directory.
1674
+ """
1675
+ return self.fs.Entry(name, self)
1676
+
1677
+ def Dir(self, name, create=True):
1678
+ """
1679
+ Looks up or creates a directory node named 'name' relative to
1680
+ this directory.
1681
+ """
1682
+ return self.fs.Dir(name, self, create)
1683
+
1684
+ def File(self, name):
1685
+ """
1686
+ Looks up or creates a file node named 'name' relative to
1687
+ this directory.
1688
+ """
1689
+ return self.fs.File(name, self)
1690
+
1691
+ def link(self, srcdir, duplicate):
1692
+ """Set this directory as the variant directory for the
1693
+ supplied source directory."""
1694
+ self.srcdir = srcdir
1695
+ self.duplicate = duplicate
1696
+ self.__clearRepositoryCache(duplicate)
1697
+ srcdir.variant_dirs.append(self)
1698
+
1699
+ def getRepositories(self):
1700
+ """Returns a list of repositories for this directory.
1701
+ """
1702
+ if self.srcdir and not self.duplicate:
1703
+ return self.srcdir.get_all_rdirs() + self.repositories
1704
+ return self.repositories
1705
+
1706
+ @SCons.Memoize.CountMethodCall
1707
+ def get_all_rdirs(self):
1708
+ try:
1709
+ return list(self._memo['get_all_rdirs'])
1710
+ except KeyError:
1711
+ pass
1712
+
1713
+ result = [self]
1714
+ fname = '.'
1715
+ dir = self
1716
+ while dir:
1717
+ for rep in dir.getRepositories():
1718
+ result.append(rep.Dir(fname))
1719
+ if fname == '.':
1720
+ fname = dir.name
1721
+ else:
1722
+ fname = dir.name + OS_SEP + fname
1723
+ dir = dir.up()
1724
+
1725
+ self._memo['get_all_rdirs'] = list(result)
1726
+
1727
+ return result
1728
+
1729
+ def addRepository(self, dir):
1730
+ if dir != self and dir not in self.repositories:
1731
+ self.repositories.append(dir)
1732
+ dir._tpath = '.'
1733
+ self.__clearRepositoryCache()
1734
+
1735
+ def up(self):
1736
+ return self.dir
1737
+
1738
+ def _rel_path_key(self, other):
1739
+ return str(other)
1740
+
1741
+ @SCons.Memoize.CountDictCall(_rel_path_key)
1742
+ def rel_path(self, other):
1743
+ """Return a path to "other" relative to this directory.
1744
+ """
1745
+
1746
+ # This complicated and expensive method, which constructs relative
1747
+ # paths between arbitrary Node.FS objects, is no longer used
1748
+ # by SCons itself. It was introduced to store dependency paths
1749
+ # in .sconsign files relative to the target, but that ended up
1750
+ # being significantly inefficient.
1751
+ #
1752
+ # We're continuing to support the method because some SConstruct
1753
+ # files out there started using it when it was available, and
1754
+ # we're all about backwards compatibility..
1755
+
1756
+ try:
1757
+ memo_dict = self._memo['rel_path']
1758
+ except KeyError:
1759
+ memo_dict = {}
1760
+ self._memo['rel_path'] = memo_dict
1761
+ else:
1762
+ try:
1763
+ return memo_dict[other]
1764
+ except KeyError:
1765
+ pass
1766
+
1767
+ if self is other:
1768
+ result = '.'
1769
+
1770
+ elif other not in self._path_elements:
1771
+ try:
1772
+ other_dir = other.get_dir()
1773
+ except AttributeError:
1774
+ result = str(other)
1775
+ else:
1776
+ if other_dir is None:
1777
+ result = other.name
1778
+ else:
1779
+ dir_rel_path = self.rel_path(other_dir)
1780
+ if dir_rel_path == '.':
1781
+ result = other.name
1782
+ else:
1783
+ result = dir_rel_path + OS_SEP + other.name
1784
+ else:
1785
+ i = self._path_elements.index(other) + 1
1786
+
1787
+ path_elems = ['..'] * (len(self._path_elements) - i) \
1788
+ + [n.name for n in other._path_elements[i:]]
1789
+
1790
+ result = OS_SEP.join(path_elems)
1791
+
1792
+ memo_dict[other] = result
1793
+
1794
+ return result
1795
+
1796
+ def get_env_scanner(self, env, kw={}):
1797
+ import SCons.Defaults
1798
+ return SCons.Defaults.DirEntryScanner
1799
+
1800
+ def get_target_scanner(self):
1801
+ import SCons.Defaults
1802
+ return SCons.Defaults.DirEntryScanner
1803
+
1804
+ def get_found_includes(self, env, scanner, path):
1805
+ """Return this directory's implicit dependencies.
1806
+
1807
+ We don't bother caching the results because the scan typically
1808
+ shouldn't be requested more than once (as opposed to scanning
1809
+ .h file contents, which can be requested as many times as the
1810
+ files is #included by other files).
1811
+ """
1812
+ if not scanner:
1813
+ return []
1814
+ # Clear cached info for this Dir. If we already visited this
1815
+ # directory on our walk down the tree (because we didn't know at
1816
+ # that point it was being used as the source for another Node)
1817
+ # then we may have calculated build signature before realizing
1818
+ # we had to scan the disk. Now that we have to, though, we need
1819
+ # to invalidate the old calculated signature so that any node
1820
+ # dependent on our directory structure gets one that includes
1821
+ # info about everything on disk.
1822
+ self.clear()
1823
+ return scanner(self, env, path)
1824
+
1825
+ #
1826
+ # Taskmaster interface subsystem
1827
+ #
1828
+
1829
+ def prepare(self):
1830
+ pass
1831
+
1832
+ def build(self, **kw):
1833
+ """A null "builder" for directories."""
1834
+ global MkdirBuilder
1835
+ if self.builder is not MkdirBuilder:
1836
+ SCons.Node.Node.build(self, **kw)
1837
+
1838
+ #
1839
+ #
1840
+ #
1841
+
1842
+ def _create(self):
1843
+ """Create this directory, silently and without worrying about
1844
+ whether the builder is the default or not."""
1845
+ listDirs = []
1846
+ parent = self
1847
+ while parent:
1848
+ if parent.exists():
1849
+ break
1850
+ listDirs.append(parent)
1851
+ p = parent.up()
1852
+ if p is None:
1853
+ # Don't use while: - else: for this condition because
1854
+ # if so, then parent is None and has no .path attribute.
1855
+ raise SCons.Errors.StopError(parent._path)
1856
+ parent = p
1857
+ listDirs.reverse()
1858
+ for dirnode in listDirs:
1859
+ try:
1860
+ # Don't call dirnode.build(), call the base Node method
1861
+ # directly because we definitely *must* create this
1862
+ # directory. The dirnode.build() method will suppress
1863
+ # the build if it's the default builder.
1864
+ SCons.Node.Node.build(dirnode)
1865
+ dirnode.get_executor().nullify()
1866
+ # The build() action may or may not have actually
1867
+ # created the directory, depending on whether the -n
1868
+ # option was used or not. Delete the _exists and
1869
+ # _rexists attributes so they can be reevaluated.
1870
+ dirnode.clear()
1871
+ except OSError:
1872
+ pass
1873
+
1874
+ def multiple_side_effect_has_builder(self):
1875
+ global MkdirBuilder
1876
+ return self.builder is not MkdirBuilder and self.has_builder()
1877
+
1878
+ def alter_targets(self):
1879
+ """Return any corresponding targets in a variant directory.
1880
+ """
1881
+ return self.fs.variant_dir_target_climb(self, self, [])
1882
+
1883
+ def scanner_key(self):
1884
+ """A directory does not get scanned."""
1885
+ return None
1886
+
1887
+ def get_text_contents(self):
1888
+ """We already emit things in text, so just return the binary
1889
+ version."""
1890
+ return self.get_contents()
1891
+
1892
+ def get_contents(self):
1893
+ """Return content signatures and names of all our children
1894
+ separated by new-lines. Ensure that the nodes are sorted."""
1895
+ return SCons.Node._get_contents_map[self._func_get_contents](self)
1896
+
1897
+ def get_csig(self):
1898
+ """Compute the content signature for Directory nodes. In
1899
+ general, this is not needed and the content signature is not
1900
+ stored in the DirNodeInfo. However, if get_contents on a Dir
1901
+ node is called which has a child directory, the child
1902
+ directory should return the hash of its contents."""
1903
+ contents = self.get_contents()
1904
+ return hash_signature(contents)
1905
+
1906
+ def do_duplicate(self, src):
1907
+ pass
1908
+
1909
+ def is_up_to_date(self):
1910
+ """If any child is not up-to-date, then this directory isn't,
1911
+ either."""
1912
+ if self.builder is not MkdirBuilder and not self.exists():
1913
+ return 0
1914
+ up_to_date = SCons.Node.up_to_date
1915
+ for kid in self.children():
1916
+ if kid.get_state() > up_to_date:
1917
+ return 0
1918
+ return 1
1919
+
1920
+ def rdir(self):
1921
+ if not self.exists():
1922
+ norm_name = _my_normcase(self.name)
1923
+ for dir in self.dir.get_all_rdirs():
1924
+ try: node = dir.entries[norm_name]
1925
+ except KeyError: node = dir.dir_on_disk(self.name)
1926
+ if node and node.exists() and \
1927
+ (isinstance(dir, Dir) or isinstance(dir, Entry)):
1928
+ return node
1929
+ return self
1930
+
1931
+ def sconsign(self):
1932
+ """Return the .sconsign file info for this directory. """
1933
+ return _sconsign_map[self._func_sconsign](self)
1934
+
1935
+ def srcnode(self):
1936
+ """Dir has a special need for srcnode()...if we
1937
+ have a srcdir attribute set, then that *is* our srcnode."""
1938
+ if self.srcdir:
1939
+ return self.srcdir
1940
+ return Base.srcnode(self)
1941
+
1942
+ def get_timestamp(self):
1943
+ """Return the latest timestamp from among our children"""
1944
+ stamp = 0
1945
+ for kid in self.children():
1946
+ if kid.get_timestamp() > stamp:
1947
+ stamp = kid.get_timestamp()
1948
+ return stamp
1949
+
1950
+ def get_abspath(self):
1951
+ """Get the absolute path of the file."""
1952
+ return self._abspath
1953
+
1954
+ def get_labspath(self):
1955
+ """Get the absolute path of the file."""
1956
+ return self._labspath
1957
+
1958
+ def get_internal_path(self):
1959
+ return self._path
1960
+
1961
+ def get_tpath(self):
1962
+ return self._tpath
1963
+
1964
+ def get_path_elements(self):
1965
+ return self._path_elements
1966
+
1967
+ def entry_abspath(self, name):
1968
+ return self._abspath + OS_SEP + name
1969
+
1970
+ def entry_labspath(self, name):
1971
+ return self._labspath + '/' + name
1972
+
1973
+ def entry_path(self, name):
1974
+ return self._path + OS_SEP + name
1975
+
1976
+ def entry_tpath(self, name):
1977
+ return self._tpath + OS_SEP + name
1978
+
1979
+ def entry_exists_on_disk(self, name):
1980
+ """ Searches through the file/dir entries of the current
1981
+ directory, and returns True if a physical entry with the given
1982
+ name could be found.
1983
+
1984
+ @see rentry_exists_on_disk
1985
+ """
1986
+ try:
1987
+ d = self.on_disk_entries
1988
+ except AttributeError:
1989
+ d = {}
1990
+ try:
1991
+ entries = os.listdir(self._abspath)
1992
+ except OSError:
1993
+ pass
1994
+ else:
1995
+ for entry in map(_my_normcase, entries):
1996
+ d[entry] = True
1997
+ self.on_disk_entries = d
1998
+ if sys.platform == 'win32' or sys.platform == 'cygwin':
1999
+ name = _my_normcase(name)
2000
+ result = d.get(name)
2001
+ if result is None:
2002
+ # Belt-and-suspenders for Windows: check directly for
2003
+ # 8.3 file names that don't show up in os.listdir().
2004
+ result = os.path.exists(self._abspath + OS_SEP + name)
2005
+ d[name] = result
2006
+ return result
2007
+ else:
2008
+ return name in d
2009
+
2010
+ def rentry_exists_on_disk(self, name):
2011
+ """ Searches through the file/dir entries of the current
2012
+ *and* all its remote directories (repos), and returns
2013
+ True if a physical entry with the given name could be found.
2014
+ The local directory (self) gets searched first, so
2015
+ repositories take a lower precedence regarding the
2016
+ searching order.
2017
+
2018
+ @see entry_exists_on_disk
2019
+ """
2020
+
2021
+ rentry_exists = self.entry_exists_on_disk(name)
2022
+ if not rentry_exists:
2023
+ # Search through the repository folders
2024
+ norm_name = _my_normcase(name)
2025
+ for rdir in self.get_all_rdirs():
2026
+ try:
2027
+ node = rdir.entries[norm_name]
2028
+ if node:
2029
+ rentry_exists = True
2030
+ break
2031
+ except KeyError:
2032
+ if rdir.entry_exists_on_disk(name):
2033
+ rentry_exists = True
2034
+ break
2035
+ return rentry_exists
2036
+
2037
+ @SCons.Memoize.CountMethodCall
2038
+ def srcdir_list(self):
2039
+ try:
2040
+ return self._memo['srcdir_list']
2041
+ except KeyError:
2042
+ pass
2043
+
2044
+ result = []
2045
+
2046
+ dirname = '.'
2047
+ dir = self
2048
+ while dir:
2049
+ if dir.srcdir:
2050
+ result.append(dir.srcdir.Dir(dirname))
2051
+ dirname = dir.name + OS_SEP + dirname
2052
+ dir = dir.up()
2053
+
2054
+ self._memo['srcdir_list'] = result
2055
+
2056
+ return result
2057
+
2058
+ def srcdir_duplicate(self, name):
2059
+ for dir in self.srcdir_list():
2060
+ if self.is_under(dir):
2061
+ # We shouldn't source from something in the build path;
2062
+ # variant_dir is probably under src_dir, in which case
2063
+ # we are reflecting.
2064
+ break
2065
+ if dir.entry_exists_on_disk(name):
2066
+ srcnode = dir.Entry(name).disambiguate()
2067
+ if self.duplicate:
2068
+ node = self.Entry(name).disambiguate()
2069
+ node.do_duplicate(srcnode)
2070
+ return node
2071
+ else:
2072
+ return srcnode
2073
+ return None
2074
+
2075
+ def _srcdir_find_file_key(self, filename):
2076
+ return filename
2077
+
2078
+ @SCons.Memoize.CountDictCall(_srcdir_find_file_key)
2079
+ def srcdir_find_file(self, filename):
2080
+ try:
2081
+ memo_dict = self._memo['srcdir_find_file']
2082
+ except KeyError:
2083
+ memo_dict = {}
2084
+ self._memo['srcdir_find_file'] = memo_dict
2085
+ else:
2086
+ try:
2087
+ return memo_dict[filename]
2088
+ except KeyError:
2089
+ pass
2090
+
2091
+ def func(node):
2092
+ if (isinstance(node, File) or isinstance(node, Entry)) and \
2093
+ (node.is_derived() or node.exists()):
2094
+ return node
2095
+ return None
2096
+
2097
+ norm_name = _my_normcase(filename)
2098
+
2099
+ for rdir in self.get_all_rdirs():
2100
+ try: node = rdir.entries[norm_name]
2101
+ except KeyError: node = rdir.file_on_disk(filename)
2102
+ else: node = func(node)
2103
+ if node:
2104
+ result = (node, self)
2105
+ memo_dict[filename] = result
2106
+ return result
2107
+
2108
+ for srcdir in self.srcdir_list():
2109
+ for rdir in srcdir.get_all_rdirs():
2110
+ try: node = rdir.entries[norm_name]
2111
+ except KeyError: node = rdir.file_on_disk(filename)
2112
+ else: node = func(node)
2113
+ if node:
2114
+ result = (File(filename, self, self.fs), srcdir)
2115
+ memo_dict[filename] = result
2116
+ return result
2117
+
2118
+ result = (None, None)
2119
+ memo_dict[filename] = result
2120
+ return result
2121
+
2122
+ def dir_on_disk(self, name):
2123
+ if self.entry_exists_on_disk(name):
2124
+ try: return self.Dir(name)
2125
+ except TypeError: pass
2126
+ node = self.srcdir_duplicate(name)
2127
+ if isinstance(node, File):
2128
+ return None
2129
+ return node
2130
+
2131
+ def file_on_disk(self, name):
2132
+ if self.entry_exists_on_disk(name):
2133
+ try: return self.File(name)
2134
+ except TypeError: pass
2135
+ node = self.srcdir_duplicate(name)
2136
+ if isinstance(node, Dir):
2137
+ return None
2138
+ return node
2139
+
2140
+ def walk(self, func, arg):
2141
+ """
2142
+ Walk this directory tree by calling the specified function
2143
+ for each directory in the tree.
2144
+
2145
+ This behaves like the os.path.walk() function, but for in-memory
2146
+ Node.FS.Dir objects. The function takes the same arguments as
2147
+ the functions passed to os.path.walk():
2148
+
2149
+ func(arg, dirname, fnames)
2150
+
2151
+ Except that "dirname" will actually be the directory *Node*,
2152
+ not the string. The '.' and '..' entries are excluded from
2153
+ fnames. The fnames list may be modified in-place to filter the
2154
+ subdirectories visited or otherwise impose a specific order.
2155
+ The "arg" argument is always passed to func() and may be used
2156
+ in any way (or ignored, passing None is common).
2157
+ """
2158
+ entries = self.entries
2159
+ names = list(entries.keys())
2160
+ names.remove('.')
2161
+ names.remove('..')
2162
+ func(arg, self, names)
2163
+ for dirname in [n for n in names if isinstance(entries[n], Dir)]:
2164
+ entries[dirname].walk(func, arg)
2165
+
2166
+ def glob(self, pathname, ondisk=True, source=False, strings=False, exclude=None):
2167
+ """
2168
+ Returns a list of Nodes (or strings) matching a specified
2169
+ pathname pattern.
2170
+
2171
+ Pathname patterns follow UNIX shell semantics: * matches
2172
+ any-length strings of any characters, ? matches any character,
2173
+ and [] can enclose lists or ranges of characters. Matches do
2174
+ not span directory separators.
2175
+
2176
+ The matches take into account Repositories, returning local
2177
+ Nodes if a corresponding entry exists in a Repository (either
2178
+ an in-memory Node or something on disk).
2179
+
2180
+ By defafult, the glob() function matches entries that exist
2181
+ on-disk, in addition to in-memory Nodes. Setting the "ondisk"
2182
+ argument to False (or some other non-true value) causes the glob()
2183
+ function to only match in-memory Nodes. The default behavior is
2184
+ to return both the on-disk and in-memory Nodes.
2185
+
2186
+ The "source" argument, when true, specifies that corresponding
2187
+ source Nodes must be returned if you're globbing in a build
2188
+ directory (initialized with VariantDir()). The default behavior
2189
+ is to return Nodes local to the VariantDir().
2190
+
2191
+ The "strings" argument, when true, returns the matches as strings,
2192
+ not Nodes. The strings are path names relative to this directory.
2193
+
2194
+ The "exclude" argument, if not None, must be a pattern or a list
2195
+ of patterns following the same UNIX shell semantics.
2196
+ Elements matching a least one pattern of this list will be excluded
2197
+ from the result.
2198
+
2199
+ The underlying algorithm is adapted from the glob.glob() function
2200
+ in the Python library (but heavily modified), and uses fnmatch()
2201
+ under the covers.
2202
+ """
2203
+ dirname, basename = os.path.split(pathname)
2204
+ if not dirname:
2205
+ result = self._glob1(basename, ondisk, source, strings)
2206
+ else:
2207
+ if has_glob_magic(dirname):
2208
+ list = self.glob(dirname, ondisk, source, False, exclude)
2209
+ else:
2210
+ list = [self.Dir(dirname, create=True)]
2211
+ result = []
2212
+ for dir in list:
2213
+ r = dir._glob1(basename, ondisk, source, strings)
2214
+ if strings:
2215
+ r = [os.path.join(str(dir), x) for x in r]
2216
+ result.extend(r)
2217
+ if exclude:
2218
+ excludes = []
2219
+ excludeList = SCons.Util.flatten(exclude)
2220
+ for x in excludeList:
2221
+ r = self.glob(x, ondisk, source, strings)
2222
+ excludes.extend(r)
2223
+ result = [x for x in result if not any(fnmatch.fnmatch(str(x), str(e)) for e in SCons.Util.flatten(excludes))]
2224
+ return sorted(result, key=lambda a: str(a))
2225
+
2226
+ def _glob1(self, pattern, ondisk=True, source=False, strings=False):
2227
+ """
2228
+ Globs for and returns a list of entry names matching a single
2229
+ pattern in this directory.
2230
+
2231
+ This searches any repositories and source directories for
2232
+ corresponding entries and returns a Node (or string) relative
2233
+ to the current directory if an entry is found anywhere.
2234
+
2235
+ TODO: handle pattern with no wildcard
2236
+ """
2237
+ search_dir_list = self.get_all_rdirs()
2238
+ for srcdir in self.srcdir_list():
2239
+ search_dir_list.extend(srcdir.get_all_rdirs())
2240
+
2241
+ selfEntry = self.Entry
2242
+ names = []
2243
+ for dir in search_dir_list:
2244
+ # We use the .name attribute from the Node because the keys of
2245
+ # the dir.entries dictionary are normalized (that is, all upper
2246
+ # case) on case-insensitive systems like Windows.
2247
+ node_names = [ v.name for k, v in dir.entries.items()
2248
+ if k not in ('.', '..') ]
2249
+ names.extend(node_names)
2250
+ if not strings:
2251
+ # Make sure the working directory (self) actually has
2252
+ # entries for all Nodes in repositories or variant dirs.
2253
+ for name in node_names: selfEntry(name)
2254
+ if ondisk:
2255
+ try:
2256
+ disk_names = os.listdir(dir._abspath)
2257
+ except os.error:
2258
+ continue
2259
+ names.extend(disk_names)
2260
+ if not strings:
2261
+ # We're going to return corresponding Nodes in
2262
+ # the local directory, so we need to make sure
2263
+ # those Nodes exist. We only want to create
2264
+ # Nodes for the entries that will match the
2265
+ # specified pattern, though, which means we
2266
+ # need to filter the list here, even though
2267
+ # the overall list will also be filtered later,
2268
+ # after we exit this loop.
2269
+ if pattern[0] != '.':
2270
+ disk_names = [x for x in disk_names if x[0] != '.']
2271
+ disk_names = fnmatch.filter(disk_names, pattern)
2272
+ dirEntry = dir.Entry
2273
+ for name in disk_names:
2274
+ # Add './' before disk filename so that '#' at
2275
+ # beginning of filename isn't interpreted.
2276
+ name = './' + name
2277
+ node = dirEntry(name).disambiguate()
2278
+ n = selfEntry(name)
2279
+ if n.__class__ != node.__class__:
2280
+ n.__class__ = node.__class__
2281
+ n._morph()
2282
+
2283
+ names = set(names)
2284
+ if pattern[0] != '.':
2285
+ names = [x for x in names if x[0] != '.']
2286
+ names = fnmatch.filter(names, pattern)
2287
+
2288
+ if strings:
2289
+ return names
2290
+
2291
+ return [self.entries[_my_normcase(n)] for n in names]
2292
+
2293
+ class RootDir(Dir):
2294
+ """A class for the root directory of a file system.
2295
+
2296
+ This is the same as a Dir class, except that the path separator
2297
+ ('/' or '\\') is actually part of the name, so we don't need to
2298
+ add a separator when creating the path names of entries within
2299
+ this directory.
2300
+ """
2301
+
2302
+ __slots__ = ('_lookupDict', 'abspath', 'path')
2303
+
2304
+ def __init__(self, drive, fs):
2305
+ if SCons.Debug.track_instances: logInstanceCreation(self, 'Node.FS.RootDir')
2306
+ SCons.Node.Node.__init__(self)
2307
+
2308
+ # Handle all the types of drives:
2309
+ if drive == '':
2310
+ # No drive, regular UNIX root or Windows default drive.
2311
+ name = OS_SEP
2312
+ dirname = OS_SEP
2313
+ elif drive == '//':
2314
+ # UNC path
2315
+ name = UNC_PREFIX
2316
+ dirname = UNC_PREFIX
2317
+ else:
2318
+ # Windows drive letter
2319
+ name = drive
2320
+ dirname = drive + OS_SEP
2321
+
2322
+ # Filename with extension as it was specified when the object was
2323
+ # created; to obtain filesystem path, use Python str() function
2324
+ self.name = SCons.Util.silent_intern(name)
2325
+ self.fs = fs #: Reference to parent Node.FS object
2326
+
2327
+ self._path_elements = [self]
2328
+ self.dir = self
2329
+ self._func_rexists = 2
2330
+ self._func_target_from_source = 1
2331
+ self.store_info = 1
2332
+
2333
+ # Now set our paths to what we really want them to be. The
2334
+ # name should already contain any necessary separators, such
2335
+ # as the initial drive letter (the name) plus the directory
2336
+ # separator, except for the "lookup abspath," which does not
2337
+ # have the drive letter.
2338
+ self._abspath = dirname
2339
+ self._labspath = ''
2340
+ self._path = dirname
2341
+ self._tpath = dirname
2342
+ self.dirname = dirname
2343
+
2344
+ # EntryProxy interferes with this class and turns drive paths on
2345
+ # Windows such as "C:" into "C:\C:". Avoid this problem by setting
2346
+ # commonly-accessed attributes directly.
2347
+ self.abspath = self._abspath
2348
+ self.path = self._path
2349
+
2350
+ self._morph()
2351
+
2352
+ self.duplicate = 0
2353
+ self._lookupDict = {'': self, '/': self}
2354
+
2355
+ self.root = self
2356
+ # The // entry is necessary because os.path.normpath()
2357
+ # preserves double slashes at the beginning of a path on Posix
2358
+ # platforms.
2359
+ if not has_unc:
2360
+ self._lookupDict['//'] = self
2361
+
2362
+ def _morph(self):
2363
+ """Turn a file system Node (either a freshly initialized directory
2364
+ object or a separate Entry object) into a proper directory object.
2365
+
2366
+ Set up this directory's entries and hook it into the file
2367
+ system tree. Specify that directories (this Node) don't use
2368
+ signatures for calculating whether they're current.
2369
+ """
2370
+
2371
+ self.repositories = []
2372
+ self.srcdir = None
2373
+
2374
+ self.entries = {'.': self, '..': self.dir}
2375
+ self.cwd = self
2376
+ self.searched = 0
2377
+ self._sconsign = None
2378
+ self.variant_dirs = []
2379
+ self.changed_since_last_build = 3
2380
+ self._func_sconsign = 1
2381
+ self._func_exists = 2
2382
+ self._func_get_contents = 2
2383
+
2384
+ # Don't just reset the executor, replace its action list,
2385
+ # because it might have some pre-or post-actions that need to
2386
+ # be preserved.
2387
+ #
2388
+ # But don't reset the executor if there is a non-null executor
2389
+ # attached already. The existing executor might have other
2390
+ # targets, in which case replacing the action list with a
2391
+ # Mkdir action is a big mistake.
2392
+ if not hasattr(self, 'executor'):
2393
+ self.builder = get_MkdirBuilder()
2394
+ self.get_executor().set_action_list(self.builder.action)
2395
+ else:
2396
+ # Prepend MkdirBuilder action to existing action list
2397
+ l = self.get_executor().action_list
2398
+ a = get_MkdirBuilder().action
2399
+ l.insert(0, a)
2400
+ self.get_executor().set_action_list(l)
2401
+
2402
+
2403
+ def must_be_same(self, klass):
2404
+ if klass is Dir:
2405
+ return
2406
+ Base.must_be_same(self, klass)
2407
+
2408
+ def _lookup_abs(self, p, klass, create=1):
2409
+ """
2410
+ Fast (?) lookup of a *normalized* absolute path.
2411
+
2412
+ This method is intended for use by internal lookups with
2413
+ already-normalized path data. For general-purpose lookups,
2414
+ use the FS.Entry(), FS.Dir() or FS.File() methods.
2415
+
2416
+ The caller is responsible for making sure we're passed a
2417
+ normalized absolute path; we merely let Python's dictionary look
2418
+ up and return the One True Node.FS object for the path.
2419
+
2420
+ If a Node for the specified "p" doesn't already exist, and
2421
+ "create" is specified, the Node may be created after recursive
2422
+ invocation to find or create the parent directory or directories.
2423
+ """
2424
+ k = _my_normcase(p)
2425
+ try:
2426
+ result = self._lookupDict[k]
2427
+ except KeyError:
2428
+ if not create:
2429
+ msg = "No such file or directory: '%s' in '%s' (and create is False)" % (p, str(self))
2430
+ raise SCons.Errors.UserError(msg)
2431
+ # There is no Node for this path name, and we're allowed
2432
+ # to create it.
2433
+ dir_name, file_name = p.rsplit('/',1)
2434
+ dir_node = self._lookup_abs(dir_name, Dir)
2435
+ result = klass(file_name, dir_node, self.fs)
2436
+
2437
+ # Double-check on disk (as configured) that the Node we
2438
+ # created matches whatever is out there in the real world.
2439
+ result.diskcheck_match()
2440
+
2441
+ self._lookupDict[k] = result
2442
+ dir_node.entries[_my_normcase(file_name)] = result
2443
+ dir_node.implicit = None
2444
+ else:
2445
+ # There is already a Node for this path name. Allow it to
2446
+ # complain if we were looking for an inappropriate type.
2447
+ result.must_be_same(klass)
2448
+ return result
2449
+
2450
+ def __str__(self):
2451
+ return self._abspath
2452
+
2453
+ def entry_abspath(self, name):
2454
+ return self._abspath + name
2455
+
2456
+ def entry_labspath(self, name):
2457
+ return '/' + name
2458
+
2459
+ def entry_path(self, name):
2460
+ return self._path + name
2461
+
2462
+ def entry_tpath(self, name):
2463
+ return self._tpath + name
2464
+
2465
+ def is_under(self, dir):
2466
+ if self is dir:
2467
+ return 1
2468
+ else:
2469
+ return 0
2470
+
2471
+ def up(self):
2472
+ return None
2473
+
2474
+ def get_dir(self):
2475
+ return None
2476
+
2477
+ def src_builder(self):
2478
+ return _null
2479
+
2480
+
2481
+ class FileNodeInfo(SCons.Node.NodeInfoBase):
2482
+ __slots__ = ('csig', 'timestamp', 'size')
2483
+ current_version_id = 2
2484
+
2485
+ field_list = ['csig', 'timestamp', 'size']
2486
+
2487
+ # This should get reset by the FS initialization.
2488
+ fs = None
2489
+
2490
+ def str_to_node(self, s):
2491
+ top = self.fs.Top
2492
+ root = top.root
2493
+ if do_splitdrive:
2494
+ drive, s = _my_splitdrive(s)
2495
+ if drive:
2496
+ root = self.fs.get_root(drive)
2497
+ if not os.path.isabs(s):
2498
+ s = top.get_labspath() + '/' + s
2499
+ return root._lookup_abs(s, Entry)
2500
+
2501
+ def __getstate__(self):
2502
+ """
2503
+ Return all fields that shall be pickled. Walk the slots in the class
2504
+ hierarchy and add those to the state dictionary. If a '__dict__' slot is
2505
+ available, copy all entries to the dictionary. Also include the version
2506
+ id, which is fixed for all instances of a class.
2507
+ """
2508
+ state = getattr(self, '__dict__', {}).copy()
2509
+ for obj in type(self).mro():
2510
+ for name in getattr(obj, '__slots__', ()):
2511
+ if hasattr(self, name):
2512
+ state[name] = getattr(self, name)
2513
+
2514
+ state['_version_id'] = self.current_version_id
2515
+ try:
2516
+ del state['__weakref__']
2517
+ except KeyError:
2518
+ pass
2519
+
2520
+ return state
2521
+
2522
+ def __setstate__(self, state):
2523
+ """
2524
+ Restore the attributes from a pickled state.
2525
+ """
2526
+ # TODO check or discard version
2527
+ del state['_version_id']
2528
+ for key, value in state.items():
2529
+ if key not in ('__weakref__',):
2530
+ setattr(self, key, value)
2531
+
2532
+ def __eq__(self, other):
2533
+ return self.csig == other.csig and self.timestamp == other.timestamp and self.size == other.size
2534
+
2535
+ def __ne__(self, other):
2536
+ return not self.__eq__(other)
2537
+
2538
+
2539
+ class FileBuildInfo(SCons.Node.BuildInfoBase):
2540
+ """
2541
+ This is info loaded from sconsign.
2542
+
2543
+ Attributes unique to FileBuildInfo:
2544
+ dependency_map : Caches file->csig mapping
2545
+ for all dependencies. Currently this is only used when using
2546
+ MD5-timestamp decider.
2547
+ It's used to ensure that we copy the correct csig from the
2548
+ previous build to be written to .sconsign when current build
2549
+ is done. Previously the matching of csig to file was strictly
2550
+ by order they appeared in bdepends, bsources, or bimplicit,
2551
+ and so a change in order or count of any of these could
2552
+ yield writing wrong csig, and then false positive rebuilds
2553
+ """
2554
+ __slots__ = ['dependency_map', ]
2555
+ current_version_id = 2
2556
+
2557
+ def __setattr__(self, key, value):
2558
+
2559
+ # If any attributes are changed in FileBuildInfo, we need to
2560
+ # invalidate the cached map of file name to content signature
2561
+ # heald in dependency_map. Currently only used with
2562
+ # MD5-timestamp decider
2563
+ if key != 'dependency_map' and hasattr(self, 'dependency_map'):
2564
+ del self.dependency_map
2565
+
2566
+ return super(FileBuildInfo, self).__setattr__(key, value)
2567
+
2568
+ def convert_to_sconsign(self):
2569
+ """
2570
+ Converts this FileBuildInfo object for writing to a .sconsign file
2571
+
2572
+ This replaces each Node in our various dependency lists with its
2573
+ usual string representation: relative to the top-level SConstruct
2574
+ directory, or an absolute path if it's outside.
2575
+ """
2576
+ if os_sep_is_slash:
2577
+ node_to_str = str
2578
+ else:
2579
+ def node_to_str(n):
2580
+ try:
2581
+ s = n.get_internal_path()
2582
+ except AttributeError:
2583
+ s = str(n)
2584
+ else:
2585
+ s = s.replace(OS_SEP, '/')
2586
+ return s
2587
+ for attr in ['bsources', 'bdepends', 'bimplicit']:
2588
+ try:
2589
+ val = getattr(self, attr)
2590
+ except AttributeError:
2591
+ pass
2592
+ else:
2593
+ setattr(self, attr, list(map(node_to_str, val)))
2594
+
2595
+ def convert_from_sconsign(self, dir, name):
2596
+ """
2597
+ Converts a newly-read FileBuildInfo object for in-SCons use
2598
+
2599
+ For normal up-to-date checking, we don't have any conversion to
2600
+ perform--but we're leaving this method here to make that clear.
2601
+ """
2602
+ pass
2603
+
2604
+ def prepare_dependencies(self):
2605
+ """
2606
+ Prepares a FileBuildInfo object for explaining what changed
2607
+
2608
+ The bsources, bdepends and bimplicit lists have all been
2609
+ stored on disk as paths relative to the top-level SConstruct
2610
+ directory. Convert the strings to actual Nodes (for use by the
2611
+ --debug=explain code and --implicit-cache).
2612
+ """
2613
+ attrs = [
2614
+ ('bsources', 'bsourcesigs'),
2615
+ ('bdepends', 'bdependsigs'),
2616
+ ('bimplicit', 'bimplicitsigs'),
2617
+ ]
2618
+ for (nattr, sattr) in attrs:
2619
+ try:
2620
+ strings = getattr(self, nattr)
2621
+ nodeinfos = getattr(self, sattr)
2622
+ except AttributeError:
2623
+ continue
2624
+ if strings is None or nodeinfos is None:
2625
+ continue
2626
+ nodes = []
2627
+ for s, ni in zip(strings, nodeinfos):
2628
+ if not isinstance(s, SCons.Node.Node):
2629
+ s = ni.str_to_node(s)
2630
+ nodes.append(s)
2631
+ setattr(self, nattr, nodes)
2632
+
2633
+ def format(self, names=0):
2634
+ result = []
2635
+ bkids = self.bsources + self.bdepends + self.bimplicit
2636
+ bkidsigs = self.bsourcesigs + self.bdependsigs + self.bimplicitsigs
2637
+ for bkid, bkidsig in zip(bkids, bkidsigs):
2638
+ result.append(str(bkid) + ': ' +
2639
+ ' '.join(bkidsig.format(names=names)))
2640
+ if not hasattr(self,'bact'):
2641
+ self.bact = "none"
2642
+ result.append('%s [%s]' % (self.bactsig, self.bact))
2643
+ return '\n'.join(result)
2644
+
2645
+
2646
+ class File(Base):
2647
+ """A class for files in a file system.
2648
+ """
2649
+
2650
+ __slots__ = ['scanner_paths',
2651
+ 'cachedir_csig',
2652
+ 'cachesig',
2653
+ 'repositories',
2654
+ 'srcdir',
2655
+ 'entries',
2656
+ 'searched',
2657
+ '_sconsign',
2658
+ 'variant_dirs',
2659
+ 'root',
2660
+ 'dirname',
2661
+ 'on_disk_entries',
2662
+ 'released_target_info',
2663
+ 'contentsig']
2664
+
2665
+ NodeInfo = FileNodeInfo
2666
+ BuildInfo = FileBuildInfo
2667
+
2668
+ # Although the command-line argument is in kilobytes, this is in bytes.
2669
+ hash_chunksize = 65536
2670
+
2671
+ def diskcheck_match(self):
2672
+ diskcheck_match(self, self.isdir,
2673
+ "Directory %s found where file expected.")
2674
+
2675
+ def __init__(self, name, directory, fs):
2676
+ if SCons.Debug.track_instances: logInstanceCreation(self, 'Node.FS.File')
2677
+ Base.__init__(self, name, directory, fs)
2678
+ self._morph()
2679
+
2680
+ def Entry(self, name):
2681
+ """Create an entry node named 'name' relative to
2682
+ the directory of this file."""
2683
+ return self.dir.Entry(name)
2684
+
2685
+ def Dir(self, name, create=True):
2686
+ """Create a directory node named 'name' relative to
2687
+ the directory of this file."""
2688
+ return self.dir.Dir(name, create=create)
2689
+
2690
+ def Dirs(self, pathlist):
2691
+ """Create a list of directories relative to the SConscript
2692
+ directory of this file."""
2693
+ return [self.Dir(p) for p in pathlist]
2694
+
2695
+ def File(self, name):
2696
+ """Create a file node named 'name' relative to
2697
+ the directory of this file."""
2698
+ return self.dir.File(name)
2699
+
2700
+ def _morph(self):
2701
+ """Turn a file system node into a File object."""
2702
+ self.scanner_paths = {}
2703
+ if not hasattr(self, '_local'):
2704
+ self._local = 0
2705
+ if not hasattr(self, 'released_target_info'):
2706
+ self.released_target_info = False
2707
+
2708
+ self.store_info = 1
2709
+ self._func_exists = 4
2710
+ self._func_get_contents = 3
2711
+
2712
+ # Initialize this Node's decider function to decide_source() because
2713
+ # every file is a source file until it has a Builder attached...
2714
+ self.changed_since_last_build = 4
2715
+
2716
+ # If there was already a Builder set on this entry, then
2717
+ # we need to make sure we call the target-decider function,
2718
+ # not the source-decider. Reaching in and doing this by hand
2719
+ # is a little bogus. We'd prefer to handle this by adding
2720
+ # an Entry.builder_set() method that disambiguates like the
2721
+ # other methods, but that starts running into problems with the
2722
+ # fragile way we initialize Dir Nodes with their Mkdir builders,
2723
+ # yet still allow them to be overridden by the user. Since it's
2724
+ # not clear right now how to fix that, stick with what works
2725
+ # until it becomes clear...
2726
+ if self.has_builder():
2727
+ self.changed_since_last_build = 5
2728
+
2729
+ def scanner_key(self):
2730
+ return self.get_suffix()
2731
+
2732
+ def get_contents(self) -> bytes:
2733
+ """Return the contents of the file as bytes."""
2734
+ return SCons.Node._get_contents_map[self._func_get_contents](self)
2735
+
2736
+ def get_text_contents(self) -> str:
2737
+ """Return the contents of the file in text form.
2738
+
2739
+ This attempts to figure out what the encoding of the text is
2740
+ based upon the BOM bytes, and then decodes the contents so that
2741
+ it's a valid python string.
2742
+ """
2743
+ contents = self.get_contents()
2744
+ # The behavior of various decode() methods and functions
2745
+ # w.r.t. the initial BOM bytes is different for different
2746
+ # encodings and/or Python versions. ('utf-8' does not strip
2747
+ # them, but has a 'utf-8-sig' which does; 'utf-16' seems to
2748
+ # strip them; etc.) Just sidestep all the complication by
2749
+ # explicitly stripping the BOM before we decode().
2750
+ if contents[:len(codecs.BOM_UTF8)] == codecs.BOM_UTF8:
2751
+ return contents[len(codecs.BOM_UTF8):].decode('utf-8')
2752
+ if contents[:len(codecs.BOM_UTF16_LE)] == codecs.BOM_UTF16_LE:
2753
+ return contents[len(codecs.BOM_UTF16_LE):].decode('utf-16-le')
2754
+ if contents[:len(codecs.BOM_UTF16_BE)] == codecs.BOM_UTF16_BE:
2755
+ return contents[len(codecs.BOM_UTF16_BE):].decode('utf-16-be')
2756
+ try:
2757
+ return contents.decode('utf-8')
2758
+ except UnicodeDecodeError as e:
2759
+ try:
2760
+ return contents.decode('latin-1')
2761
+ except UnicodeDecodeError as e:
2762
+ return contents.decode('utf-8', errors='backslashreplace')
2763
+
2764
+ def get_content_hash(self) -> str:
2765
+ """
2766
+ Compute and return the hash for this file.
2767
+ """
2768
+ if not self.rexists():
2769
+ return hash_signature(SCons.Util.NOFILE)
2770
+ fname = self.rfile().get_abspath()
2771
+ try:
2772
+ cs = hash_file_signature(fname, chunksize=File.hash_chunksize)
2773
+ except EnvironmentError as e:
2774
+ if not e.filename:
2775
+ e.filename = fname
2776
+ raise
2777
+ return cs
2778
+
2779
+ @SCons.Memoize.CountMethodCall
2780
+ def get_size(self) -> int:
2781
+ try:
2782
+ return self._memo['get_size']
2783
+ except KeyError:
2784
+ pass
2785
+
2786
+ if self.rexists():
2787
+ size = self.rfile().getsize()
2788
+ else:
2789
+ # sentinel value for doesn't exist, even in repository
2790
+ size = -1
2791
+
2792
+ self._memo['get_size'] = size
2793
+ return size
2794
+
2795
+ @SCons.Memoize.CountMethodCall
2796
+ def get_timestamp(self) -> int:
2797
+ try:
2798
+ return self._memo['get_timestamp']
2799
+ except KeyError:
2800
+ pass
2801
+
2802
+ if self.rexists():
2803
+ timestamp = self.rfile().getmtime()
2804
+ else:
2805
+ timestamp = 0
2806
+
2807
+ self._memo['get_timestamp'] = timestamp
2808
+ return timestamp
2809
+
2810
+ convert_copy_attrs = [
2811
+ 'bsources',
2812
+ 'bimplicit',
2813
+ 'bdepends',
2814
+ 'bact',
2815
+ 'bactsig',
2816
+ 'ninfo',
2817
+ ]
2818
+
2819
+ convert_sig_attrs = [
2820
+ 'bsourcesigs',
2821
+ 'bimplicitsigs',
2822
+ 'bdependsigs',
2823
+ ]
2824
+
2825
+ def convert_old_entry(self, old_entry):
2826
+ # Convert a .sconsign entry from before the Big Signature
2827
+ # Refactoring, doing what we can to convert its information
2828
+ # to the new .sconsign entry format.
2829
+ #
2830
+ # The old format looked essentially like this:
2831
+ #
2832
+ # BuildInfo
2833
+ # .ninfo (NodeInfo)
2834
+ # .bsig
2835
+ # .csig
2836
+ # .timestamp
2837
+ # .size
2838
+ # .bsources
2839
+ # .bsourcesigs ("signature" list)
2840
+ # .bdepends
2841
+ # .bdependsigs ("signature" list)
2842
+ # .bimplicit
2843
+ # .bimplicitsigs ("signature" list)
2844
+ # .bact
2845
+ # .bactsig
2846
+ #
2847
+ # The new format looks like this:
2848
+ #
2849
+ # .ninfo (NodeInfo)
2850
+ # .bsig
2851
+ # .csig
2852
+ # .timestamp
2853
+ # .size
2854
+ # .binfo (BuildInfo)
2855
+ # .bsources
2856
+ # .bsourcesigs (NodeInfo list)
2857
+ # .bsig
2858
+ # .csig
2859
+ # .timestamp
2860
+ # .size
2861
+ # .bdepends
2862
+ # .bdependsigs (NodeInfo list)
2863
+ # .bsig
2864
+ # .csig
2865
+ # .timestamp
2866
+ # .size
2867
+ # .bimplicit
2868
+ # .bimplicitsigs (NodeInfo list)
2869
+ # .bsig
2870
+ # .csig
2871
+ # .timestamp
2872
+ # .size
2873
+ # .bact
2874
+ # .bactsig
2875
+ #
2876
+ # The basic idea of the new structure is that a NodeInfo always
2877
+ # holds all available information about the state of a given Node
2878
+ # at a certain point in time. The various .b*sigs lists can just
2879
+ # be a list of pointers to the .ninfo attributes of the different
2880
+ # dependent nodes, without any copying of information until it's
2881
+ # time to pickle it for writing out to a .sconsign file.
2882
+ #
2883
+ # The complicating issue is that the *old* format only stored one
2884
+ # "signature" per dependency, based on however the *last* build
2885
+ # was configured. We don't know from just looking at it whether
2886
+ # it was a build signature, a content signature, or a timestamp
2887
+ # "signature". Since we no longer use build signatures, the
2888
+ # best we can do is look at the length and if it's thirty two,
2889
+ # assume that it was (or might have been) a content signature.
2890
+ # If it was actually a build signature, then it will cause a
2891
+ # rebuild anyway when it doesn't match the new content signature,
2892
+ # but that's probably the best we can do.
2893
+ import SCons.SConsign
2894
+ new_entry = SCons.SConsign.SConsignEntry()
2895
+ new_entry.binfo = self.new_binfo()
2896
+ binfo = new_entry.binfo
2897
+ for attr in self.convert_copy_attrs:
2898
+ try:
2899
+ value = getattr(old_entry, attr)
2900
+ except AttributeError:
2901
+ continue
2902
+ setattr(binfo, attr, value)
2903
+ delattr(old_entry, attr)
2904
+ for attr in self.convert_sig_attrs:
2905
+ try:
2906
+ sig_list = getattr(old_entry, attr)
2907
+ except AttributeError:
2908
+ continue
2909
+ value = []
2910
+ for sig in sig_list:
2911
+ ninfo = self.new_ninfo()
2912
+ if len(sig) == 32:
2913
+ ninfo.csig = sig
2914
+ else:
2915
+ ninfo.timestamp = sig
2916
+ value.append(ninfo)
2917
+ setattr(binfo, attr, value)
2918
+ delattr(old_entry, attr)
2919
+ return new_entry
2920
+
2921
+ @SCons.Memoize.CountMethodCall
2922
+ def get_stored_info(self):
2923
+ try:
2924
+ return self._memo['get_stored_info']
2925
+ except KeyError:
2926
+ pass
2927
+
2928
+ try:
2929
+ sconsign_entry = self.dir.sconsign().get_entry(self.name)
2930
+ except (KeyError, EnvironmentError):
2931
+ import SCons.SConsign
2932
+ sconsign_entry = SCons.SConsign.SConsignEntry()
2933
+ sconsign_entry.binfo = self.new_binfo()
2934
+ sconsign_entry.ninfo = self.new_ninfo()
2935
+ else:
2936
+ if isinstance(sconsign_entry, FileBuildInfo):
2937
+ # This is a .sconsign file from before the Big Signature
2938
+ # Refactoring; convert it as best we can.
2939
+ sconsign_entry = self.convert_old_entry(sconsign_entry)
2940
+ try:
2941
+ delattr(sconsign_entry.ninfo, 'bsig')
2942
+ except AttributeError:
2943
+ pass
2944
+
2945
+ self._memo['get_stored_info'] = sconsign_entry
2946
+
2947
+ return sconsign_entry
2948
+
2949
+ def get_stored_implicit(self):
2950
+ binfo = self.get_stored_info().binfo
2951
+ binfo.prepare_dependencies()
2952
+ try: return binfo.bimplicit
2953
+ except AttributeError: return None
2954
+
2955
+ def rel_path(self, other):
2956
+ return self.dir.rel_path(other)
2957
+
2958
+ def _get_found_includes_key(self, env, scanner, path):
2959
+ return (id(env), id(scanner), path)
2960
+
2961
+ @SCons.Memoize.CountDictCall(_get_found_includes_key)
2962
+ def get_found_includes(self, env, scanner, path):
2963
+ """Return the included implicit dependencies in this file.
2964
+ Cache results so we only scan the file once per path
2965
+ regardless of how many times this information is requested.
2966
+ """
2967
+ memo_key = (id(env), id(scanner), path)
2968
+ try:
2969
+ memo_dict = self._memo['get_found_includes']
2970
+ except KeyError:
2971
+ memo_dict = {}
2972
+ self._memo['get_found_includes'] = memo_dict
2973
+ else:
2974
+ try:
2975
+ return memo_dict[memo_key]
2976
+ except KeyError:
2977
+ pass
2978
+
2979
+ if scanner:
2980
+ result = [n.disambiguate() for n in scanner(self, env, path)]
2981
+ else:
2982
+ result = []
2983
+
2984
+ memo_dict[memo_key] = result
2985
+
2986
+ return result
2987
+
2988
+ def _createDir(self):
2989
+ # ensure that the directories for this node are
2990
+ # created.
2991
+ self.dir._create()
2992
+
2993
+ def push_to_cache(self):
2994
+ """Try to push the node into a cache
2995
+ """
2996
+ # This should get called before the Nodes' .built() method is
2997
+ # called, which would clear the build signature if the file has
2998
+ # a source scanner.
2999
+ #
3000
+ # We have to clear the local memoized values *before* we push
3001
+ # the node to cache so that the memoization of the self.exists()
3002
+ # return value doesn't interfere.
3003
+ if self.nocache:
3004
+ return
3005
+ self.clear_memoized_values()
3006
+ if self.exists():
3007
+ self.get_build_env().get_CacheDir().push(self)
3008
+
3009
+ def retrieve_from_cache(self):
3010
+ """Try to retrieve the node's content from a cache
3011
+
3012
+ This method is called from multiple threads in a parallel build,
3013
+ so only do thread safe stuff here. Do thread unsafe stuff in
3014
+ built().
3015
+
3016
+ Returns true if the node was successfully retrieved.
3017
+ """
3018
+ if self.nocache:
3019
+ return None
3020
+ if not self.is_derived():
3021
+ return None
3022
+ return self.get_build_env().get_CacheDir().retrieve(self)
3023
+
3024
+ def visited(self):
3025
+ if self.exists() and self.executor is not None:
3026
+ self.get_build_env().get_CacheDir().push_if_forced(self)
3027
+
3028
+ ninfo = self.get_ninfo()
3029
+
3030
+ csig = self.get_max_drift_csig()
3031
+ if csig:
3032
+ ninfo.csig = csig
3033
+
3034
+ ninfo.timestamp = self.get_timestamp()
3035
+ ninfo.size = self.get_size()
3036
+
3037
+ if not self.has_builder():
3038
+ # This is a source file, but it might have been a target file
3039
+ # in another build that included more of the DAG. Copy
3040
+ # any build information that's stored in the .sconsign file
3041
+ # into our binfo object so it doesn't get lost.
3042
+ old = self.get_stored_info()
3043
+ self.get_binfo().merge(old.binfo)
3044
+
3045
+ SCons.Node.store_info_map[self.store_info](self)
3046
+
3047
+ def release_target_info(self):
3048
+ """Called just after this node has been marked
3049
+ up-to-date or was built completely.
3050
+
3051
+ This is where we try to release as many target node infos
3052
+ as possible for clean builds and update runs, in order
3053
+ to minimize the overall memory consumption.
3054
+
3055
+ We'd like to remove a lot more attributes like self.sources
3056
+ and self.sources_set, but they might get used
3057
+ in a next build step. For example, during configuration
3058
+ the source files for a built E{*}.o file are used to figure out
3059
+ which linker to use for the resulting Program (gcc vs. g++)!
3060
+ That's why we check for the 'keep_targetinfo' attribute,
3061
+ config Nodes and the Interactive mode just don't allow
3062
+ an early release of most variables.
3063
+
3064
+ In the same manner, we can't simply remove the self.attributes
3065
+ here. The smart linking relies on the shared flag, and some
3066
+ parts of the java Tool use it to transport information
3067
+ about nodes...
3068
+
3069
+ @see: built() and Node.release_target_info()
3070
+ """
3071
+ if self.released_target_info or SCons.Node.interactive:
3072
+ return
3073
+
3074
+ if not hasattr(self.attributes, 'keep_targetinfo'):
3075
+ # Cache some required values, before releasing
3076
+ # stuff like env, executor and builder...
3077
+ self.changed(allowcache=True)
3078
+ self.get_contents_sig()
3079
+ self.get_build_env()
3080
+ # Now purge unneeded stuff to free memory...
3081
+ self.executor = None
3082
+ self._memo.pop('rfile', None)
3083
+ self.prerequisites = None
3084
+ # Cleanup lists, but only if they're empty
3085
+ if not len(self.ignore_set):
3086
+ self.ignore_set = None
3087
+ if not len(self.implicit_set):
3088
+ self.implicit_set = None
3089
+ if not len(self.depends_set):
3090
+ self.depends_set = None
3091
+ if not len(self.ignore):
3092
+ self.ignore = None
3093
+ if not len(self.depends):
3094
+ self.depends = None
3095
+ # Mark this node as done, we only have to release
3096
+ # the memory once...
3097
+ self.released_target_info = True
3098
+
3099
+ def find_src_builder(self):
3100
+ if self.rexists():
3101
+ return None
3102
+ scb = self.dir.src_builder()
3103
+ if scb is _null:
3104
+ scb = None
3105
+ if scb is not None:
3106
+ try:
3107
+ b = self.builder
3108
+ except AttributeError:
3109
+ b = None
3110
+ if b is None:
3111
+ self.builder_set(scb)
3112
+ return scb
3113
+
3114
+ def has_src_builder(self):
3115
+ """Return whether this Node has a source builder or not.
3116
+
3117
+ If this Node doesn't have an explicit source code builder, this
3118
+ is where we figure out, on the fly, if there's a transparent
3119
+ source code builder for it.
3120
+
3121
+ Note that if we found a source builder, we also set the
3122
+ self.builder attribute, so that all of the methods that actually
3123
+ *build* this file don't have to do anything different.
3124
+ """
3125
+ try:
3126
+ scb = self.sbuilder
3127
+ except AttributeError:
3128
+ scb = self.sbuilder = self.find_src_builder()
3129
+ return scb is not None
3130
+
3131
+ def alter_targets(self):
3132
+ """Return any corresponding targets in a variant directory.
3133
+ """
3134
+ if self.is_derived():
3135
+ return [], None
3136
+ return self.fs.variant_dir_target_climb(self, self.dir, [self.name])
3137
+
3138
+ def _rmv_existing(self):
3139
+ self.clear_memoized_values()
3140
+ if SCons.Node.print_duplicate:
3141
+ print("dup: removing existing target {}".format(self))
3142
+ e = Unlink(self, [], None)
3143
+ if isinstance(e, SCons.Errors.BuildError):
3144
+ raise e
3145
+
3146
+ #
3147
+ # Taskmaster interface subsystem
3148
+ #
3149
+
3150
+ def make_ready(self):
3151
+ self.has_src_builder()
3152
+ self.get_binfo()
3153
+
3154
+ def prepare(self):
3155
+ """Prepare for this file to be created."""
3156
+ SCons.Node.Node.prepare(self)
3157
+
3158
+ if self.get_state() != SCons.Node.up_to_date:
3159
+ # Exists will report False for dangling symlinks so if it
3160
+ # exists or is a link (which would mean it's a dangling
3161
+ # link) then we should remove it as appropriate.
3162
+ if self.exists() or self.islink():
3163
+ if self.is_derived() and not self.precious:
3164
+ self._rmv_existing()
3165
+ else:
3166
+ try:
3167
+ self._createDir()
3168
+ except SCons.Errors.StopError as drive:
3169
+ raise SCons.Errors.StopError("No drive `{}' for target `{}'.".format(drive, self))
3170
+
3171
+ #
3172
+ #
3173
+ #
3174
+
3175
+ def remove(self):
3176
+ """Remove this file."""
3177
+ if self.exists() or self.islink():
3178
+ self.fs.unlink(self.get_internal_path())
3179
+ return 1
3180
+ return None
3181
+
3182
+ def do_duplicate(self, src):
3183
+ self._createDir()
3184
+ if SCons.Node.print_duplicate:
3185
+ print("dup: relinking variant '{}' from '{}'".format(self, src))
3186
+ Unlink(self, None, None)
3187
+ e = Link(self, src, None)
3188
+ if isinstance(e, SCons.Errors.BuildError):
3189
+ raise SCons.Errors.StopError("Cannot duplicate `{}' in `{}': {}.".format(src.get_internal_path(), self.dir._path, e.errstr))
3190
+ self.linked = 1
3191
+ # The Link() action may or may not have actually
3192
+ # created the file, depending on whether the -n
3193
+ # option was used or not. Delete the _exists and
3194
+ # _rexists attributes so they can be reevaluated.
3195
+ self.clear()
3196
+
3197
+ @SCons.Memoize.CountMethodCall
3198
+ def exists(self):
3199
+ try:
3200
+ return self._memo['exists']
3201
+ except KeyError:
3202
+ pass
3203
+ result = SCons.Node._exists_map[self._func_exists](self)
3204
+ self._memo['exists'] = result
3205
+ return result
3206
+
3207
+ #
3208
+ # SIGNATURE SUBSYSTEM
3209
+ #
3210
+
3211
+ def get_max_drift_csig(self) -> Optional[str]:
3212
+ """
3213
+ Returns the content signature currently stored for this node
3214
+ if it's been unmodified longer than the max_drift value, or the
3215
+ max_drift value is 0. Returns None otherwise.
3216
+ """
3217
+ old = self.get_stored_info()
3218
+ mtime = self.get_timestamp()
3219
+
3220
+ max_drift = self.fs.max_drift
3221
+ if max_drift > 0:
3222
+ if (time.time() - mtime) > max_drift:
3223
+ try:
3224
+ n = old.ninfo
3225
+ if n.timestamp and n.csig and n.timestamp == mtime:
3226
+ return n.csig
3227
+ except AttributeError:
3228
+ pass
3229
+ elif max_drift == 0:
3230
+ try:
3231
+ return old.ninfo.csig
3232
+ except AttributeError:
3233
+ pass
3234
+
3235
+ return None
3236
+
3237
+ def get_csig(self) -> str:
3238
+ """Generate a node's content signature."""
3239
+ ninfo = self.get_ninfo()
3240
+ try:
3241
+ return ninfo.csig
3242
+ except AttributeError:
3243
+ pass
3244
+
3245
+ csig = self.get_max_drift_csig()
3246
+ if csig is None:
3247
+ try:
3248
+ size = self.get_size()
3249
+ if size == -1:
3250
+ contents = SCons.Util.NOFILE
3251
+ elif size < File.hash_chunksize:
3252
+ contents = self.get_contents()
3253
+ else:
3254
+ csig = self.get_content_hash()
3255
+ except IOError:
3256
+ # This can happen if there's actually a directory on-disk,
3257
+ # which can be the case if they've disabled disk checks,
3258
+ # or if an action with a File target actually happens to
3259
+ # create a same-named directory by mistake.
3260
+ csig = ''
3261
+ else:
3262
+ if not csig:
3263
+ csig = SCons.Util.hash_signature(contents)
3264
+
3265
+ ninfo.csig = csig
3266
+
3267
+ return csig
3268
+
3269
+ #
3270
+ # DECISION SUBSYSTEM
3271
+ #
3272
+
3273
+ def builder_set(self, builder):
3274
+ SCons.Node.Node.builder_set(self, builder)
3275
+ self.changed_since_last_build = 5
3276
+
3277
+ def built(self):
3278
+ """Called just after this File node is successfully built.
3279
+
3280
+ Just like for 'release_target_info' we try to release
3281
+ some more target node attributes in order to minimize the
3282
+ overall memory consumption.
3283
+
3284
+ @see: release_target_info
3285
+ """
3286
+
3287
+ SCons.Node.Node.built(self)
3288
+
3289
+ if (not SCons.Node.interactive and
3290
+ not hasattr(self.attributes, 'keep_targetinfo')):
3291
+ # Ensure that the build infos get computed and cached...
3292
+ SCons.Node.store_info_map[self.store_info](self)
3293
+ # ... then release some more variables.
3294
+ self._specific_sources = False
3295
+ self._labspath = None
3296
+ self._save_str()
3297
+ self.cwd = None
3298
+
3299
+ self.scanner_paths = None
3300
+
3301
+ def changed(self, node=None, allowcache=False):
3302
+ """
3303
+ Returns if the node is up-to-date with respect to the BuildInfo
3304
+ stored last time it was built.
3305
+
3306
+ For File nodes this is basically a wrapper around Node.changed(),
3307
+ but we allow the return value to get cached after the reference
3308
+ to the Executor got released in release_target_info().
3309
+
3310
+ @see: Node.changed()
3311
+ """
3312
+ if node is None:
3313
+ try:
3314
+ return self._memo['changed']
3315
+ except KeyError:
3316
+ pass
3317
+
3318
+ has_changed = SCons.Node.Node.changed(self, node)
3319
+ if allowcache:
3320
+ self._memo['changed'] = has_changed
3321
+ return has_changed
3322
+
3323
+ def changed_content(self, target, prev_ni, repo_node=None):
3324
+ cur_csig = self.get_csig()
3325
+ try:
3326
+ return cur_csig != prev_ni.csig
3327
+ except AttributeError:
3328
+ return 1
3329
+
3330
+ def changed_state(self, target, prev_ni, repo_node=None):
3331
+ return self.state != SCons.Node.up_to_date
3332
+
3333
+
3334
+ # Caching node -> string mapping for the below method
3335
+ __dmap_cache = {}
3336
+ __dmap_sig_cache = {}
3337
+
3338
+
3339
+ def _build_dependency_map(self, binfo):
3340
+ """
3341
+ Build mapping from file -> signature
3342
+
3343
+ Args:
3344
+ self - self
3345
+ binfo - buildinfo from node being considered
3346
+
3347
+ Returns:
3348
+ dictionary of file->signature mappings
3349
+ """
3350
+
3351
+ # For an "empty" binfo properties like bsources
3352
+ # do not exist: check this to avoid exception.
3353
+ if (len(binfo.bsourcesigs) + len(binfo.bdependsigs) +
3354
+ len(binfo.bimplicitsigs)) == 0:
3355
+ return {}
3356
+
3357
+ binfo.dependency_map = { child:signature for child, signature in zip(chain(binfo.bsources, binfo.bdepends, binfo.bimplicit),
3358
+ chain(binfo.bsourcesigs, binfo.bdependsigs, binfo.bimplicitsigs))}
3359
+
3360
+ return binfo.dependency_map
3361
+
3362
+ # @profile
3363
+ def _add_strings_to_dependency_map(self, dmap):
3364
+ """
3365
+ In the case comparing node objects isn't sufficient, we'll add the strings for the nodes to the dependency map
3366
+ :return:
3367
+ """
3368
+
3369
+ first_string = str(next(iter(dmap)))
3370
+
3371
+ # print("DMAP:%s"%id(dmap))
3372
+ if first_string not in dmap:
3373
+ string_dict = {str(child): signature for child, signature in dmap.items()}
3374
+ dmap.update(string_dict)
3375
+ return dmap
3376
+
3377
+ def _get_previous_signatures(self, dmap):
3378
+ """
3379
+ Return a list of corresponding csigs from previous
3380
+ build in order of the node/files in children.
3381
+
3382
+ Args:
3383
+ self - self
3384
+ dmap - Dictionary of file -> csig
3385
+
3386
+ Returns:
3387
+ List of csigs for provided list of children
3388
+ """
3389
+ prev = []
3390
+ # MD5_TIMESTAMP_DEBUG = False
3391
+
3392
+ if len(dmap) == 0:
3393
+ if MD5_TIMESTAMP_DEBUG: print("Nothing dmap shortcutting")
3394
+ return None
3395
+ elif MD5_TIMESTAMP_DEBUG: print("len(dmap):%d"%len(dmap))
3396
+
3397
+
3398
+ # First try retrieving via Node
3399
+ if MD5_TIMESTAMP_DEBUG: print("Checking if self is in map:%s id:%s type:%s"%(str(self), id(self), type(self)))
3400
+ df = dmap.get(self, False)
3401
+ if df:
3402
+ return df
3403
+
3404
+ # Now check if self's repository file is in map.
3405
+ rf = self.rfile()
3406
+ if MD5_TIMESTAMP_DEBUG: print("Checking if self.rfile is in map:%s id:%s type:%s"%(str(rf), id(rf), type(rf)))
3407
+ rfm = dmap.get(rf, False)
3408
+ if rfm:
3409
+ return rfm
3410
+
3411
+ # get default string for node and then also string swapping os.altsep for os.sep (/ for \)
3412
+ c_strs = [str(self)]
3413
+
3414
+ if os.altsep:
3415
+ c_strs.append(c_strs[0].replace(os.sep, os.altsep))
3416
+
3417
+ # In some cases the dependency_maps' keys are already strings check.
3418
+ # Check if either string is now in dmap.
3419
+ for s in c_strs:
3420
+ if MD5_TIMESTAMP_DEBUG: print("Checking if str(self) is in map :%s" % s)
3421
+ df = dmap.get(s, False)
3422
+ if df:
3423
+ return df
3424
+
3425
+ # Strings don't exist in map, add them and try again
3426
+ # If there are no strings in this dmap, then add them.
3427
+ # This may not be necessary, we could walk the nodes in the dmap and check each string
3428
+ # rather than adding ALL the strings to dmap. In theory that would be n/2 vs 2n str() calls on node
3429
+ # if not dmap.has_strings:
3430
+ dmap = self._add_strings_to_dependency_map(dmap)
3431
+
3432
+ # In some cases the dependency_maps' keys are already strings check.
3433
+ # Check if either string is now in dmap.
3434
+ for s in c_strs:
3435
+ if MD5_TIMESTAMP_DEBUG: print("Checking if str(self) is in map (now with strings) :%s" % s)
3436
+ df = dmap.get(s, False)
3437
+ if df:
3438
+ return df
3439
+
3440
+ # Lastly use nodes get_path() to generate string and see if that's in dmap
3441
+ if not df:
3442
+ try:
3443
+ # this should yield a path which matches what's in the sconsign
3444
+ c_str = self.get_path()
3445
+ if os.altsep:
3446
+ c_str = c_str.replace(os.sep, os.altsep)
3447
+
3448
+ if MD5_TIMESTAMP_DEBUG: print("Checking if self.get_path is in map (now with strings) :%s" % s)
3449
+
3450
+ df = dmap.get(c_str, None)
3451
+
3452
+ except AttributeError as e:
3453
+ raise FileBuildInfoFileToCsigMappingError("No mapping from file name to content signature for :%s"%c_str)
3454
+
3455
+ return df
3456
+
3457
+ def changed_timestamp_then_content(self, target, prev_ni, node=None):
3458
+ """
3459
+ Used when decider for file is Timestamp-MD5
3460
+
3461
+ NOTE: If the timestamp hasn't changed this will skip md5'ing the
3462
+ file and just copy the prev_ni provided. If the prev_ni
3463
+ is wrong. It will propagate it.
3464
+ See: https://github.com/SCons/scons/issues/2980
3465
+
3466
+ Args:
3467
+ self - dependency
3468
+ target - target
3469
+ prev_ni - The NodeInfo object loaded from previous builds .sconsign
3470
+ node - Node instance. Check this node for file existence/timestamp
3471
+ if specified.
3472
+
3473
+ Returns:
3474
+ Boolean - Indicates if node(File) has changed.
3475
+ """
3476
+
3477
+ if node is None:
3478
+ node = self
3479
+ # Now get sconsign name -> csig map and then get proper prev_ni if possible
3480
+ bi = node.get_stored_info().binfo
3481
+ rebuilt = False
3482
+ try:
3483
+ dependency_map = bi.dependency_map
3484
+ except AttributeError as e:
3485
+ dependency_map = self._build_dependency_map(bi)
3486
+ rebuilt = True
3487
+
3488
+ if len(dependency_map) == 0:
3489
+ # If there's no dependency map, there's no need to find the
3490
+ # prev_ni as there aren't any
3491
+ # shortcut the rest of the logic
3492
+ if MD5_TIMESTAMP_DEBUG: print("Skipping checks len(dmap)=0")
3493
+
3494
+ # We still need to get the current file's csig
3495
+ # This should be slightly faster than calling self.changed_content(target, new_prev_ni)
3496
+ self.get_csig()
3497
+ return True
3498
+
3499
+ new_prev_ni = self._get_previous_signatures(dependency_map)
3500
+ new = self.changed_timestamp_match(target, new_prev_ni)
3501
+
3502
+ if MD5_TIMESTAMP_DEBUG:
3503
+ old = self.changed_timestamp_match(target, prev_ni)
3504
+
3505
+ if old != new:
3506
+ print("Mismatch self.changed_timestamp_match(%s, prev_ni) old:%s new:%s"%(str(target), old, new))
3507
+ new_prev_ni = self._get_previous_signatures(dependency_map)
3508
+
3509
+ if not new:
3510
+ try:
3511
+ # NOTE: We're modifying the current node's csig in a query.
3512
+ self.get_ninfo().csig = new_prev_ni.csig
3513
+ except AttributeError:
3514
+ pass
3515
+ return False
3516
+ return self.changed_content(target, new_prev_ni)
3517
+
3518
+ def changed_timestamp_newer(self, target, prev_ni, repo_node=None):
3519
+ try:
3520
+ return self.get_timestamp() > target.get_timestamp()
3521
+ except AttributeError:
3522
+ return 1
3523
+
3524
+ def changed_timestamp_match(self, target, prev_ni, repo_node=None):
3525
+ """
3526
+ Return True if the timestamps don't match or if there is no previous timestamp
3527
+ :param target:
3528
+ :param prev_ni: Information about the node from the previous build
3529
+ :return:
3530
+ """
3531
+ try:
3532
+ return self.get_timestamp() != prev_ni.timestamp
3533
+ except AttributeError:
3534
+ return 1
3535
+
3536
+ def is_up_to_date(self):
3537
+ """Check for whether the Node is current
3538
+ In all cases self is the target we're checking to see if it's up to date
3539
+ """
3540
+
3541
+ T = 0
3542
+ if T: Trace('is_up_to_date(%s):' % self)
3543
+ if not self.exists():
3544
+ if T: Trace(' not self.exists():')
3545
+ # The file (always a target) doesn't exist locally...
3546
+ r = self.rfile()
3547
+ if r != self:
3548
+ # ...but there is one (always a target) in a Repository...
3549
+ if not self.changed(r):
3550
+ if T: Trace(' changed(%s):' % r)
3551
+ # ...and it's even up-to-date...
3552
+ if self._local:
3553
+ # ...and they'd like a local copy.
3554
+ e = LocalCopy(self, r, None)
3555
+ if isinstance(e, SCons.Errors.BuildError):
3556
+ # Likely this should be re-raising exception e
3557
+ # (which would be BuildError)
3558
+ raise e
3559
+ SCons.Node.store_info_map[self.store_info](self)
3560
+ if T: Trace(' 1\n')
3561
+ return 1
3562
+ self.changed()
3563
+ if T: Trace(' None\n')
3564
+ return None
3565
+ else:
3566
+ r = self.changed()
3567
+ if T: Trace(' self.exists(): %s\n' % r)
3568
+ return not r
3569
+
3570
+ @SCons.Memoize.CountMethodCall
3571
+ def rfile(self):
3572
+ try:
3573
+ return self._memo['rfile']
3574
+ except KeyError:
3575
+ pass
3576
+ result = self
3577
+ if not self.exists():
3578
+ norm_name = _my_normcase(self.name)
3579
+ for repo_dir in self.dir.get_all_rdirs():
3580
+ try:
3581
+ node = repo_dir.entries[norm_name]
3582
+ except KeyError:
3583
+ node = repo_dir.file_on_disk(self.name)
3584
+
3585
+ if node and node.exists() and \
3586
+ (isinstance(node, File) or isinstance(node, Entry)
3587
+ or not node.is_derived()):
3588
+ result = node
3589
+ # Copy over our local attributes to the repository
3590
+ # Node so we identify shared object files in the
3591
+ # repository and don't assume they're static.
3592
+ #
3593
+ # This isn't perfect; the attribute would ideally
3594
+ # be attached to the object in the repository in
3595
+ # case it was built statically in the repository
3596
+ # and we changed it to shared locally, but that's
3597
+ # rarely the case and would only occur if you
3598
+ # intentionally used the same suffix for both
3599
+ # shared and static objects anyway. So this
3600
+ # should work well in practice.
3601
+ result.attributes = self.attributes
3602
+ break
3603
+ self._memo['rfile'] = result
3604
+ return result
3605
+
3606
+ def find_repo_file(self):
3607
+ """
3608
+ For this node, find if there exists a corresponding file in one or more repositories
3609
+ :return: list of corresponding files in repositories
3610
+ """
3611
+ retvals = []
3612
+
3613
+ norm_name = _my_normcase(self.name)
3614
+ for repo_dir in self.dir.get_all_rdirs():
3615
+ try:
3616
+ node = repo_dir.entries[norm_name]
3617
+ except KeyError:
3618
+ node = repo_dir.file_on_disk(self.name)
3619
+
3620
+ if node and node.exists() and \
3621
+ (isinstance(node, File) or isinstance(node, Entry)
3622
+ or not node.is_derived()):
3623
+ retvals.append(node)
3624
+
3625
+ return retvals
3626
+
3627
+
3628
+ def rstr(self):
3629
+ return str(self.rfile())
3630
+
3631
+ def get_cachedir_csig(self):
3632
+ """
3633
+ Fetch a Node's content signature for purposes of computing
3634
+ another Node's cachesig.
3635
+
3636
+ This is a wrapper around the normal get_csig() method that handles
3637
+ the somewhat obscure case of using CacheDir with the -n option.
3638
+ Any files that don't exist would normally be "built" by fetching
3639
+ them from the cache, but the normal get_csig() method will try
3640
+ to open up the local file, which doesn't exist because the -n
3641
+ option meant we didn't actually pull the file from cachedir.
3642
+ But since the file *does* actually exist in the cachedir, we
3643
+ can use its contents for the csig.
3644
+ """
3645
+ try:
3646
+ return self.cachedir_csig
3647
+ except AttributeError:
3648
+ pass
3649
+
3650
+ cache = self.get_build_env().get_CacheDir()
3651
+ cachedir, cachefile = cache.cachepath(self)
3652
+ if not self.exists() and cachefile and os.path.exists(cachefile):
3653
+ self.cachedir_csig = cache.get_cachedir_csig(self)
3654
+ else:
3655
+ self.cachedir_csig = self.get_csig()
3656
+ return self.cachedir_csig
3657
+
3658
+ def get_contents_sig(self):
3659
+ """
3660
+ A helper method for get_cachedir_bsig.
3661
+
3662
+ It computes and returns the signature for this
3663
+ node's contents.
3664
+ """
3665
+
3666
+ try:
3667
+ return self.contentsig
3668
+ except AttributeError:
3669
+ pass
3670
+
3671
+ executor = self.get_executor()
3672
+
3673
+ result = self.contentsig = hash_signature(executor.get_contents())
3674
+ return result
3675
+
3676
+ def get_cachedir_bsig(self):
3677
+ """
3678
+ Return the signature for a cached file, including
3679
+ its children.
3680
+
3681
+ It adds the path of the cached file to the cache signature,
3682
+ because multiple targets built by the same action will all
3683
+ have the same build signature, and we have to differentiate
3684
+ them somehow.
3685
+
3686
+ Signature should normally be string of hex digits.
3687
+ """
3688
+ try:
3689
+ return self.cachesig
3690
+ except AttributeError:
3691
+ pass
3692
+
3693
+ # Collect signatures for all children
3694
+ children = self.children()
3695
+ sigs = [n.get_cachedir_csig() for n in children]
3696
+
3697
+ # Append this node's signature...
3698
+ sigs.append(self.get_contents_sig())
3699
+
3700
+ # ...and it's path
3701
+ sigs.append(self.get_internal_path())
3702
+
3703
+ # Merge this all into a single signature
3704
+ result = self.cachesig = hash_collect(sigs)
3705
+ return result
3706
+
3707
+ default_fs = None
3708
+
3709
+ def get_default_fs():
3710
+ global default_fs
3711
+ if not default_fs:
3712
+ default_fs = FS()
3713
+ return default_fs
3714
+
3715
+ class FileFinder:
3716
+ """
3717
+ """
3718
+
3719
+ def __init__(self):
3720
+ self._memo = {}
3721
+
3722
+ def filedir_lookup(self, p, fd=None):
3723
+ """
3724
+ A helper method for find_file() that looks up a directory for
3725
+ a file we're trying to find. This only creates the Dir Node if
3726
+ it exists on-disk, since if the directory doesn't exist we know
3727
+ we won't find any files in it... :-)
3728
+
3729
+ It would be more compact to just use this as a nested function
3730
+ with a default keyword argument (see the commented-out version
3731
+ below), but that doesn't work unless you have nested scopes,
3732
+ so we define it here just so this work under Python 1.5.2.
3733
+ """
3734
+ if fd is None:
3735
+ fd = self.default_filedir
3736
+ dir, name = os.path.split(fd)
3737
+ drive, d = _my_splitdrive(dir)
3738
+ if not name and d[:1] in ('/', OS_SEP):
3739
+ #return p.fs.get_root(drive).dir_on_disk(name)
3740
+ return p.fs.get_root(drive)
3741
+ if dir:
3742
+ p = self.filedir_lookup(p, dir)
3743
+ if not p:
3744
+ return None
3745
+ norm_name = _my_normcase(name)
3746
+ try:
3747
+ node = p.entries[norm_name]
3748
+ except KeyError:
3749
+ return p.dir_on_disk(name)
3750
+ if isinstance(node, Dir):
3751
+ return node
3752
+ if isinstance(node, Entry):
3753
+ node.must_be_same(Dir)
3754
+ return node
3755
+ return None
3756
+
3757
+ def _find_file_key(self, filename, paths, verbose=None):
3758
+ # Note: paths could be a list, which is not hashable. If it is, convert
3759
+ # it to a tuple, which is hashable.
3760
+ paths_entry = tuple(paths) if isinstance(paths, list) else paths
3761
+ return (filename, paths_entry)
3762
+
3763
+ @SCons.Memoize.CountDictCall(_find_file_key)
3764
+ def find_file(self, filename, paths, verbose=None):
3765
+ """
3766
+ Find a node corresponding to either a derived file or a file that exists already.
3767
+
3768
+ Only the first file found is returned, and none is returned if no file is found.
3769
+
3770
+ filename: A filename to find
3771
+ paths: A list of directory path *nodes* to search in. Can be represented as a list, a tuple, or a callable that is called with no arguments and returns the list or tuple.
3772
+
3773
+ returns The node created from the found file.
3774
+
3775
+ """
3776
+ memo_key = self._find_file_key(filename, paths)
3777
+ try:
3778
+ memo_dict = self._memo['find_file']
3779
+ except KeyError:
3780
+ memo_dict = {}
3781
+ self._memo['find_file'] = memo_dict
3782
+ else:
3783
+ try:
3784
+ return memo_dict[memo_key]
3785
+ except KeyError:
3786
+ pass
3787
+
3788
+ if verbose and not callable(verbose):
3789
+ if not SCons.Util.is_String(verbose):
3790
+ verbose = "find_file"
3791
+ _verbose = ' %s: ' % verbose
3792
+ verbose = lambda s: sys.stdout.write(_verbose + s)
3793
+
3794
+ filedir, filename = os.path.split(filename)
3795
+ if filedir:
3796
+ self.default_filedir = filedir
3797
+ paths = [_f for _f in map(self.filedir_lookup, paths) if _f]
3798
+
3799
+ result = None
3800
+ for dir in paths:
3801
+ if verbose:
3802
+ verbose("looking for '%s' in '%s' ...\n" % (filename, dir))
3803
+ node, d = dir.srcdir_find_file(filename)
3804
+ if node:
3805
+ if verbose:
3806
+ verbose("... FOUND '%s' in '%s'\n" % (filename, d))
3807
+ result = node
3808
+ break
3809
+
3810
+ memo_dict[memo_key] = result
3811
+
3812
+ return result
3813
+
3814
+ find_file = FileFinder().find_file
3815
+
3816
+
3817
+ def invalidate_node_memos(targets):
3818
+ """
3819
+ Invalidate the memoized values of all Nodes (files or directories)
3820
+ that are associated with the given entries. Has been added to
3821
+ clear the cache of nodes affected by a direct execution of an
3822
+ action (e.g. Delete/Copy/Chmod). Existing Node caches become
3823
+ inconsistent if the action is run through Execute(). The argument
3824
+ `targets` can be a single Node object or filename, or a sequence
3825
+ of Nodes/filenames.
3826
+ """
3827
+ from traceback import extract_stack
3828
+
3829
+ # First check if the cache really needs to be flushed. Only
3830
+ # actions run in the SConscript with Execute() seem to be
3831
+ # affected. XXX The way to check if Execute() is in the stacktrace
3832
+ # is a very dirty hack and should be replaced by a more sensible
3833
+ # solution.
3834
+ for f in extract_stack():
3835
+ if f[2] == 'Execute' and f[0][-14:] == 'Environment.py':
3836
+ break
3837
+ else:
3838
+ # Dont have to invalidate, so return
3839
+ return
3840
+
3841
+ if not SCons.Util.is_List(targets):
3842
+ targets = [targets]
3843
+
3844
+ for entry in targets:
3845
+ # If the target is a Node object, clear the cache. If it is a
3846
+ # filename, look up potentially existing Node object first.
3847
+ try:
3848
+ entry.clear_memoized_values()
3849
+ except AttributeError:
3850
+ # Not a Node object, try to look up Node by filename. XXX
3851
+ # This creates Node objects even for those filenames which
3852
+ # do not correspond to an existing Node object.
3853
+ node = get_default_fs().Entry(entry)
3854
+ if node:
3855
+ node.clear_memoized_values()
3856
+
3857
+ # Local Variables:
3858
+ # tab-width:4
3859
+ # indent-tabs-mode:nil
3860
+ # End:
3861
+ # vim: set expandtab tabstop=4 shiftwidth=4: