qrscanner 0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (480) hide show
  1. data/CHANGELOG +2 -0
  2. data/Manifest +478 -0
  3. data/README +41 -0
  4. data/Rakefile +9 -0
  5. data/bin/qrscanner +9 -0
  6. data/ext/qrscanner/extconf.rb +70 -0
  7. data/ext/qrscanner/qrscanner.c +32 -0
  8. data/ext/qrscanner/zxing/README +43 -0
  9. data/ext/qrscanner/zxing/SConscript +55 -0
  10. data/ext/qrscanner/zxing/SConstruct +7 -0
  11. data/ext/qrscanner/zxing/astyle-options +12 -0
  12. data/ext/qrscanner/zxing/blackboxtest.sh +45 -0
  13. data/ext/qrscanner/zxing/core/src/zxing/BarcodeFormat.cpp +38 -0
  14. data/ext/qrscanner/zxing/core/src/zxing/BarcodeFormat.h +42 -0
  15. data/ext/qrscanner/zxing/core/src/zxing/Binarizer.cpp +36 -0
  16. data/ext/qrscanner/zxing/core/src/zxing/Binarizer.h +46 -0
  17. data/ext/qrscanner/zxing/core/src/zxing/BinaryBitmap.cpp +67 -0
  18. data/ext/qrscanner/zxing/core/src/zxing/BinaryBitmap.h +57 -0
  19. data/ext/qrscanner/zxing/core/src/zxing/DecodeHints.cpp +111 -0
  20. data/ext/qrscanner/zxing/core/src/zxing/DecodeHints.h +69 -0
  21. data/ext/qrscanner/zxing/core/src/zxing/Exception.cpp +25 -0
  22. data/ext/qrscanner/zxing/core/src/zxing/Exception.h +39 -0
  23. data/ext/qrscanner/zxing/core/src/zxing/LuminanceSource.cpp +47 -0
  24. data/ext/qrscanner/zxing/core/src/zxing/LuminanceSource.h +49 -0
  25. data/ext/qrscanner/zxing/core/src/zxing/MultiFormatReader.cpp +102 -0
  26. data/ext/qrscanner/zxing/core/src/zxing/MultiFormatReader.h +49 -0
  27. data/ext/qrscanner/zxing/core/src/zxing/Reader.cpp +31 -0
  28. data/ext/qrscanner/zxing/core/src/zxing/Reader.h +40 -0
  29. data/ext/qrscanner/zxing/core/src/zxing/ReaderException.cpp +32 -0
  30. data/ext/qrscanner/zxing/core/src/zxing/ReaderException.h +34 -0
  31. data/ext/qrscanner/zxing/core/src/zxing/Result.cpp +59 -0
  32. data/ext/qrscanner/zxing/core/src/zxing/Result.h +53 -0
  33. data/ext/qrscanner/zxing/core/src/zxing/ResultPoint.cpp +27 -0
  34. data/ext/qrscanner/zxing/core/src/zxing/ResultPoint.h +39 -0
  35. data/ext/qrscanner/zxing/core/src/zxing/ResultPointCallback.cpp +26 -0
  36. data/ext/qrscanner/zxing/core/src/zxing/ResultPointCallback.h +39 -0
  37. data/ext/qrscanner/zxing/core/src/zxing/common/Array.cpp +22 -0
  38. data/ext/qrscanner/zxing/core/src/zxing/common/Array.h +207 -0
  39. data/ext/qrscanner/zxing/core/src/zxing/common/BitArray.cpp +129 -0
  40. data/ext/qrscanner/zxing/core/src/zxing/common/BitArray.h +55 -0
  41. data/ext/qrscanner/zxing/core/src/zxing/common/BitMatrix.cpp +178 -0
  42. data/ext/qrscanner/zxing/core/src/zxing/common/BitMatrix.h +65 -0
  43. data/ext/qrscanner/zxing/core/src/zxing/common/BitSource.cpp +75 -0
  44. data/ext/qrscanner/zxing/core/src/zxing/common/BitSource.h +67 -0
  45. data/ext/qrscanner/zxing/core/src/zxing/common/Counted.cpp +32 -0
  46. data/ext/qrscanner/zxing/core/src/zxing/common/Counted.h +205 -0
  47. data/ext/qrscanner/zxing/core/src/zxing/common/DecoderResult.cpp +37 -0
  48. data/ext/qrscanner/zxing/core/src/zxing/common/DecoderResult.h +43 -0
  49. data/ext/qrscanner/zxing/core/src/zxing/common/DetectorResult.cpp +41 -0
  50. data/ext/qrscanner/zxing/core/src/zxing/common/DetectorResult.h +46 -0
  51. data/ext/qrscanner/zxing/core/src/zxing/common/EdgeDetector.cpp +191 -0
  52. data/ext/qrscanner/zxing/core/src/zxing/common/EdgeDetector.h +38 -0
  53. data/ext/qrscanner/zxing/core/src/zxing/common/GlobalHistogramBinarizer.cpp +209 -0
  54. data/ext/qrscanner/zxing/core/src/zxing/common/GlobalHistogramBinarizer.h +47 -0
  55. data/ext/qrscanner/zxing/core/src/zxing/common/GreyscaleLuminanceSource.cpp +70 -0
  56. data/ext/qrscanner/zxing/core/src/zxing/common/GreyscaleLuminanceSource.h +62 -0
  57. data/ext/qrscanner/zxing/core/src/zxing/common/GreyscaleRotatedLuminanceSource.cpp +65 -0
  58. data/ext/qrscanner/zxing/core/src/zxing/common/GreyscaleRotatedLuminanceSource.h +60 -0
  59. data/ext/qrscanner/zxing/core/src/zxing/common/GridSampler.cpp +101 -0
  60. data/ext/qrscanner/zxing/core/src/zxing/common/GridSampler.h +43 -0
  61. data/ext/qrscanner/zxing/core/src/zxing/common/HybridBinarizer.cpp +168 -0
  62. data/ext/qrscanner/zxing/core/src/zxing/common/HybridBinarizer.h +55 -0
  63. data/ext/qrscanner/zxing/core/src/zxing/common/IllegalArgumentException.cpp +31 -0
  64. data/ext/qrscanner/zxing/core/src/zxing/common/IllegalArgumentException.h +33 -0
  65. data/ext/qrscanner/zxing/core/src/zxing/common/PerspectiveTransform.cpp +107 -0
  66. data/ext/qrscanner/zxing/core/src/zxing/common/PerspectiveTransform.h +49 -0
  67. data/ext/qrscanner/zxing/core/src/zxing/common/Point.h +47 -0
  68. data/ext/qrscanner/zxing/core/src/zxing/common/Str.cpp +38 -0
  69. data/ext/qrscanner/zxing/core/src/zxing/common/Str.h +40 -0
  70. data/ext/qrscanner/zxing/core/src/zxing/common/reedsolomon/GF256.cpp +136 -0
  71. data/ext/qrscanner/zxing/core/src/zxing/common/reedsolomon/GF256.h +68 -0
  72. data/ext/qrscanner/zxing/core/src/zxing/common/reedsolomon/GF256Poly.cpp +198 -0
  73. data/ext/qrscanner/zxing/core/src/zxing/common/reedsolomon/GF256Poly.h +53 -0
  74. data/ext/qrscanner/zxing/core/src/zxing/common/reedsolomon/ReedSolomonDecoder.cpp +193 -0
  75. data/ext/qrscanner/zxing/core/src/zxing/common/reedsolomon/ReedSolomonDecoder.h +46 -0
  76. data/ext/qrscanner/zxing/core/src/zxing/common/reedsolomon/ReedSolomonException.cpp +30 -0
  77. data/ext/qrscanner/zxing/core/src/zxing/common/reedsolomon/ReedSolomonException.h +33 -0
  78. data/ext/qrscanner/zxing/core/src/zxing/datamatrix/DataMatrixReader.cpp +82 -0
  79. data/ext/qrscanner/zxing/core/src/zxing/datamatrix/DataMatrixReader.h +45 -0
  80. data/ext/qrscanner/zxing/core/src/zxing/datamatrix/Version.cpp +199 -0
  81. data/ext/qrscanner/zxing/core/src/zxing/datamatrix/Version.h +87 -0
  82. data/ext/qrscanner/zxing/core/src/zxing/datamatrix/decoder/BitMatrixParser.cpp +364 -0
  83. data/ext/qrscanner/zxing/core/src/zxing/datamatrix/decoder/BitMatrixParser.h +59 -0
  84. data/ext/qrscanner/zxing/core/src/zxing/datamatrix/decoder/DataBlock.cpp +113 -0
  85. data/ext/qrscanner/zxing/core/src/zxing/datamatrix/decoder/DataBlock.h +49 -0
  86. data/ext/qrscanner/zxing/core/src/zxing/datamatrix/decoder/DecodedBitStreamParser.cpp +404 -0
  87. data/ext/qrscanner/zxing/core/src/zxing/datamatrix/decoder/DecodedBitStreamParser.h +103 -0
  88. data/ext/qrscanner/zxing/core/src/zxing/datamatrix/decoder/Decoder.cpp +96 -0
  89. data/ext/qrscanner/zxing/core/src/zxing/datamatrix/decoder/Decoder.h +50 -0
  90. data/ext/qrscanner/zxing/core/src/zxing/datamatrix/detector/CornerPoint.cpp +54 -0
  91. data/ext/qrscanner/zxing/core/src/zxing/datamatrix/detector/CornerPoint.h +47 -0
  92. data/ext/qrscanner/zxing/core/src/zxing/datamatrix/detector/Detector.cpp +315 -0
  93. data/ext/qrscanner/zxing/core/src/zxing/datamatrix/detector/Detector.h +79 -0
  94. data/ext/qrscanner/zxing/core/src/zxing/datamatrix/detector/MonochromeRectangleDetector.cpp +172 -0
  95. data/ext/qrscanner/zxing/core/src/zxing/datamatrix/detector/MonochromeRectangleDetector.h +61 -0
  96. data/ext/qrscanner/zxing/core/src/zxing/oned/Code128Reader.cpp +490 -0
  97. data/ext/qrscanner/zxing/core/src/zxing/oned/Code128Reader.h +63 -0
  98. data/ext/qrscanner/zxing/core/src/zxing/oned/Code39Reader.cpp +352 -0
  99. data/ext/qrscanner/zxing/core/src/zxing/oned/Code39Reader.h +58 -0
  100. data/ext/qrscanner/zxing/core/src/zxing/oned/EAN13Reader.cpp +95 -0
  101. data/ext/qrscanner/zxing/core/src/zxing/oned/EAN13Reader.h +44 -0
  102. data/ext/qrscanner/zxing/core/src/zxing/oned/EAN8Reader.cpp +73 -0
  103. data/ext/qrscanner/zxing/core/src/zxing/oned/EAN8Reader.h +41 -0
  104. data/ext/qrscanner/zxing/core/src/zxing/oned/ITFReader.cpp +363 -0
  105. data/ext/qrscanner/zxing/core/src/zxing/oned/ITFReader.h +56 -0
  106. data/ext/qrscanner/zxing/core/src/zxing/oned/MultiFormatOneDReader.cpp +66 -0
  107. data/ext/qrscanner/zxing/core/src/zxing/oned/MultiFormatOneDReader.h +38 -0
  108. data/ext/qrscanner/zxing/core/src/zxing/oned/MultiFormatUPCEANReader.cpp +87 -0
  109. data/ext/qrscanner/zxing/core/src/zxing/oned/MultiFormatUPCEANReader.h +38 -0
  110. data/ext/qrscanner/zxing/core/src/zxing/oned/OneDReader.cpp +206 -0
  111. data/ext/qrscanner/zxing/core/src/zxing/oned/OneDReader.h +50 -0
  112. data/ext/qrscanner/zxing/core/src/zxing/oned/OneDResultPoint.cpp +36 -0
  113. data/ext/qrscanner/zxing/core/src/zxing/oned/OneDResultPoint.h +40 -0
  114. data/ext/qrscanner/zxing/core/src/zxing/oned/UPCAReader.cpp +65 -0
  115. data/ext/qrscanner/zxing/core/src/zxing/oned/UPCAReader.h +49 -0
  116. data/ext/qrscanner/zxing/core/src/zxing/oned/UPCEANReader.cpp +311 -0
  117. data/ext/qrscanner/zxing/core/src/zxing/oned/UPCEANReader.h +77 -0
  118. data/ext/qrscanner/zxing/core/src/zxing/oned/UPCEReader.cpp +143 -0
  119. data/ext/qrscanner/zxing/core/src/zxing/oned/UPCEReader.h +47 -0
  120. data/ext/qrscanner/zxing/core/src/zxing/qrcode/ErrorCorrectionLevel.cpp +49 -0
  121. data/ext/qrscanner/zxing/core/src/zxing/qrcode/ErrorCorrectionLevel.h +46 -0
  122. data/ext/qrscanner/zxing/core/src/zxing/qrcode/FormatInformation.cpp +108 -0
  123. data/ext/qrscanner/zxing/core/src/zxing/qrcode/FormatInformation.h +54 -0
  124. data/ext/qrscanner/zxing/core/src/zxing/qrcode/QRCodeReader.cpp +82 -0
  125. data/ext/qrscanner/zxing/core/src/zxing/qrcode/QRCodeReader.h +43 -0
  126. data/ext/qrscanner/zxing/core/src/zxing/qrcode/Version.cpp +557 -0
  127. data/ext/qrscanner/zxing/core/src/zxing/qrcode/Version.h +85 -0
  128. data/ext/qrscanner/zxing/core/src/zxing/qrcode/decoder/BitMatrixParser.cpp +191 -0
  129. data/ext/qrscanner/zxing/core/src/zxing/qrcode/decoder/BitMatrixParser.h +56 -0
  130. data/ext/qrscanner/zxing/core/src/zxing/qrcode/decoder/DataBlock.cpp +118 -0
  131. data/ext/qrscanner/zxing/core/src/zxing/qrcode/decoder/DataBlock.h +50 -0
  132. data/ext/qrscanner/zxing/core/src/zxing/qrcode/decoder/DataMask.cpp +159 -0
  133. data/ext/qrscanner/zxing/core/src/zxing/qrcode/decoder/DataMask.h +50 -0
  134. data/ext/qrscanner/zxing/core/src/zxing/qrcode/decoder/DecodedBitStreamParser.cpp +353 -0
  135. data/ext/qrscanner/zxing/core/src/zxing/qrcode/decoder/DecodedBitStreamParser.h +59 -0
  136. data/ext/qrscanner/zxing/core/src/zxing/qrcode/decoder/Decoder.cpp +103 -0
  137. data/ext/qrscanner/zxing/core/src/zxing/qrcode/decoder/Decoder.h +47 -0
  138. data/ext/qrscanner/zxing/core/src/zxing/qrcode/decoder/Mode.cpp +73 -0
  139. data/ext/qrscanner/zxing/core/src/zxing/qrcode/decoder/Mode.h +50 -0
  140. data/ext/qrscanner/zxing/core/src/zxing/qrcode/detector/AlignmentPattern.cpp +46 -0
  141. data/ext/qrscanner/zxing/core/src/zxing/qrcode/detector/AlignmentPattern.h +45 -0
  142. data/ext/qrscanner/zxing/core/src/zxing/qrcode/detector/AlignmentPatternFinder.cpp +209 -0
  143. data/ext/qrscanner/zxing/core/src/zxing/qrcode/detector/AlignmentPatternFinder.h +68 -0
  144. data/ext/qrscanner/zxing/core/src/zxing/qrcode/detector/Detector.cpp +286 -0
  145. data/ext/qrscanner/zxing/core/src/zxing/qrcode/detector/Detector.h +64 -0
  146. data/ext/qrscanner/zxing/core/src/zxing/qrcode/detector/FinderPattern.cpp +58 -0
  147. data/ext/qrscanner/zxing/core/src/zxing/qrcode/detector/FinderPattern.h +48 -0
  148. data/ext/qrscanner/zxing/core/src/zxing/qrcode/detector/FinderPatternFinder.cpp +540 -0
  149. data/ext/qrscanner/zxing/core/src/zxing/qrcode/detector/FinderPatternFinder.h +69 -0
  150. data/ext/qrscanner/zxing/core/src/zxing/qrcode/detector/FinderPatternInfo.cpp +41 -0
  151. data/ext/qrscanner/zxing/core/src/zxing/qrcode/detector/FinderPatternInfo.h +47 -0
  152. data/ext/qrscanner/zxing/core/src/zxing/qrcode/detector/QREdgeDetector.cpp +169 -0
  153. data/ext/qrscanner/zxing/core/src/zxing/qrcode/detector/QREdgeDetector.h +48 -0
  154. data/ext/qrscanner/zxing/core/tests/src/TestRunner.cpp +30 -0
  155. data/ext/qrscanner/zxing/core/tests/src/common/BitArrayTest.cpp +96 -0
  156. data/ext/qrscanner/zxing/core/tests/src/common/BitArrayTest.h +50 -0
  157. data/ext/qrscanner/zxing/core/tests/src/common/BitMatrixTest.cpp +107 -0
  158. data/ext/qrscanner/zxing/core/tests/src/common/BitMatrixTest.h +55 -0
  159. data/ext/qrscanner/zxing/core/tests/src/common/BitSourceTest.cpp +49 -0
  160. data/ext/qrscanner/zxing/core/tests/src/common/BitSourceTest.h +42 -0
  161. data/ext/qrscanner/zxing/core/tests/src/common/BlackPointEstimatorTest.cpp +47 -0
  162. data/ext/qrscanner/zxing/core/tests/src/common/BlackPointEstimatorTest.h +45 -0
  163. data/ext/qrscanner/zxing/core/tests/src/common/CountedTest.cpp +54 -0
  164. data/ext/qrscanner/zxing/core/tests/src/common/CountedTest.h +46 -0
  165. data/ext/qrscanner/zxing/core/tests/src/common/PerspectiveTransformTest.cpp +69 -0
  166. data/ext/qrscanner/zxing/core/tests/src/common/PerspectiveTransformTest.h +47 -0
  167. data/ext/qrscanner/zxing/core/tests/src/common/reedsolomon/ReedSolomonTest.cpp +130 -0
  168. data/ext/qrscanner/zxing/core/tests/src/common/reedsolomon/ReedSolomonTest.h +62 -0
  169. data/ext/qrscanner/zxing/core/tests/src/qrcode/ErrorCorrectionLevelTest.cpp +47 -0
  170. data/ext/qrscanner/zxing/core/tests/src/qrcode/ErrorCorrectionLevelTest.h +45 -0
  171. data/ext/qrscanner/zxing/core/tests/src/qrcode/FormatInformationTest.cpp +70 -0
  172. data/ext/qrscanner/zxing/core/tests/src/qrcode/FormatInformationTest.h +47 -0
  173. data/ext/qrscanner/zxing/core/tests/src/qrcode/VersionTest.cpp +88 -0
  174. data/ext/qrscanner/zxing/core/tests/src/qrcode/VersionTest.h +49 -0
  175. data/ext/qrscanner/zxing/core/tests/src/qrcode/decoder/DataMaskTest.cpp +134 -0
  176. data/ext/qrscanner/zxing/core/tests/src/qrcode/decoder/DataMaskTest.h +91 -0
  177. data/ext/qrscanner/zxing/core/tests/src/qrcode/decoder/ModeTest.cpp +52 -0
  178. data/ext/qrscanner/zxing/core/tests/src/qrcode/decoder/ModeTest.h +47 -0
  179. data/ext/qrscanner/zxing/format +2 -0
  180. data/ext/qrscanner/zxing/magick/src/MagickBitmapSource.cpp +99 -0
  181. data/ext/qrscanner/zxing/magick/src/MagickBitmapSource.h +49 -0
  182. data/ext/qrscanner/zxing/magick/src/example.cpp +83 -0
  183. data/ext/qrscanner/zxing/magick/src/main.cpp +241 -0
  184. data/ext/qrscanner/zxing/magick/src/qrscanner.cpp +188 -0
  185. data/ext/qrscanner/zxing/osx.xcodeproj/project.pbxproj +1045 -0
  186. data/ext/qrscanner/zxing/scons/scons-LICENSE +25 -0
  187. data/ext/qrscanner/zxing/scons/scons-README +204 -0
  188. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Action.py +1241 -0
  189. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Action.pyc +0 -0
  190. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Builder.py +877 -0
  191. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Builder.pyc +0 -0
  192. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/CacheDir.py +216 -0
  193. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/CacheDir.pyc +0 -0
  194. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Conftest.py +793 -0
  195. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Conftest.pyc +0 -0
  196. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Debug.py +220 -0
  197. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Debug.pyc +0 -0
  198. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Defaults.py +480 -0
  199. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Defaults.pyc +0 -0
  200. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Environment.py +2318 -0
  201. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Environment.pyc +0 -0
  202. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Errors.py +205 -0
  203. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Errors.pyc +0 -0
  204. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Executor.py +633 -0
  205. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Executor.pyc +0 -0
  206. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Job.py +435 -0
  207. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Job.pyc +0 -0
  208. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Memoize.py +244 -0
  209. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Memoize.pyc +0 -0
  210. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Node/Alias.py +152 -0
  211. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Node/Alias.pyc +0 -0
  212. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Node/FS.py +3142 -0
  213. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Node/FS.pyc +0 -0
  214. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Node/Python.py +128 -0
  215. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Node/Python.pyc +0 -0
  216. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Node/__init__.py +1328 -0
  217. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Node/__init__.pyc +0 -0
  218. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Options/BoolOption.py +50 -0
  219. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Options/BoolOption.pyc +0 -0
  220. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Options/EnumOption.py +50 -0
  221. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Options/EnumOption.pyc +0 -0
  222. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Options/ListOption.py +50 -0
  223. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Options/ListOption.pyc +0 -0
  224. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Options/PackageOption.py +50 -0
  225. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Options/PackageOption.pyc +0 -0
  226. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Options/PathOption.py +76 -0
  227. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Options/PathOption.pyc +0 -0
  228. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Options/__init__.py +67 -0
  229. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Options/__init__.pyc +0 -0
  230. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/PathList.py +231 -0
  231. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/PathList.pyc +0 -0
  232. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Platform/__init__.py +241 -0
  233. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Platform/__init__.pyc +0 -0
  234. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Platform/aix.py +69 -0
  235. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Platform/cygwin.py +55 -0
  236. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Platform/darwin.py +46 -0
  237. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Platform/hpux.py +46 -0
  238. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Platform/irix.py +44 -0
  239. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Platform/os2.py +58 -0
  240. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Platform/posix.py +263 -0
  241. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Platform/posix.pyc +0 -0
  242. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Platform/sunos.py +50 -0
  243. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Platform/win32.py +385 -0
  244. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/SConf.py +1030 -0
  245. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/SConf.pyc +0 -0
  246. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/SConsign.py +383 -0
  247. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/SConsign.pyc +0 -0
  248. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Scanner/C.py +132 -0
  249. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Scanner/C.pyc +0 -0
  250. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Scanner/D.py +73 -0
  251. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Scanner/D.pyc +0 -0
  252. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Scanner/Dir.py +109 -0
  253. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Scanner/Dir.pyc +0 -0
  254. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Scanner/Fortran.py +316 -0
  255. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Scanner/Fortran.pyc +0 -0
  256. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Scanner/IDL.py +48 -0
  257. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Scanner/LaTeX.py +362 -0
  258. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Scanner/LaTeX.pyc +0 -0
  259. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Scanner/Prog.py +101 -0
  260. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Scanner/Prog.pyc +0 -0
  261. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Scanner/RC.py +55 -0
  262. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Scanner/__init__.py +413 -0
  263. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Scanner/__init__.pyc +0 -0
  264. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Script/Interactive.py +384 -0
  265. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Script/Interactive.pyc +0 -0
  266. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Script/Main.py +1334 -0
  267. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Script/Main.pyc +0 -0
  268. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Script/SConsOptions.py +939 -0
  269. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Script/SConsOptions.pyc +0 -0
  270. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Script/SConscript.py +640 -0
  271. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Script/SConscript.pyc +0 -0
  272. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Script/__init__.py +412 -0
  273. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Script/__init__.pyc +0 -0
  274. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Sig.py +63 -0
  275. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Subst.py +904 -0
  276. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Subst.pyc +0 -0
  277. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Taskmaster.py +1017 -0
  278. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Taskmaster.pyc +0 -0
  279. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/386asm.py +61 -0
  280. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/BitKeeper.py +67 -0
  281. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/BitKeeper.pyc +0 -0
  282. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/CVS.py +73 -0
  283. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/CVS.pyc +0 -0
  284. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/FortranCommon.py +246 -0
  285. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/FortranCommon.pyc +0 -0
  286. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/JavaCommon.py +323 -0
  287. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/JavaCommon.pyc +0 -0
  288. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/MSCommon/__init__.py +56 -0
  289. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/MSCommon/arch.py +61 -0
  290. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/MSCommon/common.py +240 -0
  291. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/MSCommon/netframework.py +82 -0
  292. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/MSCommon/sdk.py +391 -0
  293. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/MSCommon/vc.py +456 -0
  294. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/MSCommon/vs.py +499 -0
  295. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/Perforce.py +103 -0
  296. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/Perforce.pyc +0 -0
  297. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/PharLapCommon.py +137 -0
  298. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/PharLapCommon.pyc +0 -0
  299. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/RCS.py +64 -0
  300. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/RCS.pyc +0 -0
  301. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/SCCS.py +64 -0
  302. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/SCCS.pyc +0 -0
  303. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/Subversion.py +71 -0
  304. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/__init__.py +681 -0
  305. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/__init__.pyc +0 -0
  306. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/aixc++.py +82 -0
  307. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/aixcc.py +74 -0
  308. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/aixf77.py +80 -0
  309. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/aixlink.py +76 -0
  310. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/applelink.py +71 -0
  311. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/ar.py +63 -0
  312. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/ar.pyc +0 -0
  313. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/as.py +78 -0
  314. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/as.pyc +0 -0
  315. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/bcc32.py +81 -0
  316. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/c++.py +99 -0
  317. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/c++.pyc +0 -0
  318. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/cc.py +102 -0
  319. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/cc.pyc +0 -0
  320. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/cvf.py +58 -0
  321. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/default.py +50 -0
  322. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/default.pyc +0 -0
  323. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/dmd.py +223 -0
  324. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/dmd.pyc +0 -0
  325. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/dvi.py +64 -0
  326. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/dvipdf.py +124 -0
  327. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/dvipdf.pyc +0 -0
  328. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/dvips.py +94 -0
  329. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/dvips.pyc +0 -0
  330. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/f77.py +62 -0
  331. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/f77.pyc +0 -0
  332. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/f90.py +62 -0
  333. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/f90.pyc +0 -0
  334. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/f95.py +63 -0
  335. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/f95.pyc +0 -0
  336. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/filesystem.py +98 -0
  337. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/filesystem.pyc +0 -0
  338. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/fortran.py +62 -0
  339. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/fortran.pyc +0 -0
  340. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/g++.py +90 -0
  341. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/g++.pyc +0 -0
  342. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/g77.py +73 -0
  343. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/g77.pyc +0 -0
  344. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/gas.py +53 -0
  345. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/gas.pyc +0 -0
  346. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/gcc.py +80 -0
  347. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/gcc.pyc +0 -0
  348. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/gfortran.py +64 -0
  349. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/gfortran.pyc +0 -0
  350. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/gnulink.py +63 -0
  351. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/gnulink.pyc +0 -0
  352. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/gs.py +81 -0
  353. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/gs.pyc +0 -0
  354. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/hpc++.py +84 -0
  355. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/hpcc.py +53 -0
  356. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/hplink.py +77 -0
  357. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/icc.py +59 -0
  358. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/icl.py +52 -0
  359. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/ifl.py +72 -0
  360. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/ifl.pyc +0 -0
  361. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/ifort.py +88 -0
  362. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/ifort.pyc +0 -0
  363. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/ilink.py +59 -0
  364. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/ilink32.py +60 -0
  365. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/install.py +229 -0
  366. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/install.pyc +0 -0
  367. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/intelc.py +482 -0
  368. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/ipkg.py +67 -0
  369. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/jar.py +110 -0
  370. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/jar.pyc +0 -0
  371. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/javac.py +230 -0
  372. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/javac.pyc +0 -0
  373. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/javah.py +137 -0
  374. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/javah.pyc +0 -0
  375. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/latex.py +79 -0
  376. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/latex.pyc +0 -0
  377. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/lex.py +97 -0
  378. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/lex.pyc +0 -0
  379. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/link.py +121 -0
  380. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/link.pyc +0 -0
  381. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/linkloc.py +112 -0
  382. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/m4.py +63 -0
  383. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/m4.pyc +0 -0
  384. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/masm.py +77 -0
  385. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/midl.py +88 -0
  386. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/mingw.py +158 -0
  387. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/mslib.py +64 -0
  388. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/mslink.py +266 -0
  389. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/mssdk.py +50 -0
  390. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/msvc.py +268 -0
  391. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/msvs.py +1388 -0
  392. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/mwcc.py +207 -0
  393. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/mwld.py +107 -0
  394. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/nasm.py +72 -0
  395. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/packaging/__init__.py +312 -0
  396. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/packaging/ipk.py +185 -0
  397. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/packaging/msi.py +527 -0
  398. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/packaging/rpm.py +365 -0
  399. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/packaging/src_tarbz2.py +43 -0
  400. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/packaging/src_targz.py +43 -0
  401. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/packaging/src_zip.py +43 -0
  402. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/packaging/tarbz2.py +44 -0
  403. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/packaging/targz.py +44 -0
  404. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/packaging/zip.py +44 -0
  405. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/pdf.py +78 -0
  406. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/pdf.pyc +0 -0
  407. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/pdflatex.py +83 -0
  408. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/pdflatex.pyc +0 -0
  409. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/pdftex.py +108 -0
  410. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/pdftex.pyc +0 -0
  411. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/qt.py +336 -0
  412. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/rmic.py +120 -0
  413. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/rmic.pyc +0 -0
  414. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/rpcgen.py +70 -0
  415. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/rpcgen.pyc +0 -0
  416. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/rpm.py +132 -0
  417. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/rpm.pyc +0 -0
  418. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/sgiar.py +68 -0
  419. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/sgic++.py +58 -0
  420. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/sgicc.py +53 -0
  421. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/sgilink.py +63 -0
  422. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/sunar.py +67 -0
  423. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/sunc++.py +142 -0
  424. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/suncc.py +58 -0
  425. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/sunf77.py +63 -0
  426. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/sunf90.py +64 -0
  427. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/sunf95.py +64 -0
  428. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/sunlink.py +77 -0
  429. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/swig.py +182 -0
  430. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/swig.pyc +0 -0
  431. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/tar.py +73 -0
  432. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/tar.pyc +0 -0
  433. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/tex.py +807 -0
  434. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/tex.pyc +0 -0
  435. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/textfile.py +175 -0
  436. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/tlib.py +53 -0
  437. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/wix.py +99 -0
  438. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/wix.pyc +0 -0
  439. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/yacc.py +130 -0
  440. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/yacc.pyc +0 -0
  441. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/zip.py +99 -0
  442. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Tool/zip.pyc +0 -0
  443. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Util.py +1496 -0
  444. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Util.pyc +0 -0
  445. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Variables/BoolVariable.py +89 -0
  446. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Variables/BoolVariable.pyc +0 -0
  447. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Variables/EnumVariable.py +103 -0
  448. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Variables/EnumVariable.pyc +0 -0
  449. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Variables/ListVariable.py +135 -0
  450. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Variables/ListVariable.pyc +0 -0
  451. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Variables/PackageVariable.py +106 -0
  452. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Variables/PackageVariable.pyc +0 -0
  453. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Variables/PathVariable.py +147 -0
  454. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Variables/PathVariable.pyc +0 -0
  455. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Variables/__init__.py +312 -0
  456. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Variables/__init__.pyc +0 -0
  457. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Warnings.py +246 -0
  458. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/Warnings.pyc +0 -0
  459. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/__init__.py +49 -0
  460. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/__init__.pyc +0 -0
  461. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/compat/__init__.py +237 -0
  462. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/compat/__init__.pyc +0 -0
  463. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/compat/_scons_builtins.py +150 -0
  464. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/compat/_scons_builtins.pyc +0 -0
  465. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/compat/_scons_collections.py +45 -0
  466. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/compat/_scons_dbm.py +45 -0
  467. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/compat/_scons_hashlib.py +76 -0
  468. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/compat/_scons_io.py +45 -0
  469. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/compat/_scons_sets.py +563 -0
  470. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/compat/_scons_subprocess.py +1281 -0
  471. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/cpp.py +589 -0
  472. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/cpp.pyc +0 -0
  473. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/dblite.py +251 -0
  474. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/dblite.pyc +0 -0
  475. data/ext/qrscanner/zxing/scons/scons-local-2.0.0.final.0/SCons/exitfuncs.py +77 -0
  476. data/ext/qrscanner/zxing/scons/scons-time.py +1544 -0
  477. data/ext/qrscanner/zxing/scons/scons.py +196 -0
  478. data/ext/qrscanner/zxing/scons/sconsign.py +513 -0
  479. data/qrscanner.gemspec +33 -0
  480. metadata +1023 -0
@@ -0,0 +1,152 @@
1
+
2
+ """scons.Node.Alias
3
+
4
+ Alias nodes.
5
+
6
+ This creates a hash of global Aliases (dummy targets).
7
+
8
+ """
9
+
10
+ #
11
+ # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 The SCons Foundation
12
+ #
13
+ # Permission is hereby granted, free of charge, to any person obtaining
14
+ # a copy of this software and associated documentation files (the
15
+ # "Software"), to deal in the Software without restriction, including
16
+ # without limitation the rights to use, copy, modify, merge, publish,
17
+ # distribute, sublicense, and/or sell copies of the Software, and to
18
+ # permit persons to whom the Software is furnished to do so, subject to
19
+ # the following conditions:
20
+ #
21
+ # The above copyright notice and this permission notice shall be included
22
+ # in all copies or substantial portions of the Software.
23
+ #
24
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
25
+ # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
26
+ # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31
+ #
32
+
33
+ __revision__ = "src/engine/SCons/Node/Alias.py 5023 2010/06/14 22:05:46 scons"
34
+
35
+ import collections
36
+
37
+ import SCons.Errors
38
+ import SCons.Node
39
+ import SCons.Util
40
+
41
+ class AliasNameSpace(collections.UserDict):
42
+ def Alias(self, name, **kw):
43
+ if isinstance(name, SCons.Node.Alias.Alias):
44
+ return name
45
+ try:
46
+ a = self[name]
47
+ except KeyError:
48
+ a = SCons.Node.Alias.Alias(name, **kw)
49
+ self[name] = a
50
+ return a
51
+
52
+ def lookup(self, name, **kw):
53
+ try:
54
+ return self[name]
55
+ except KeyError:
56
+ return None
57
+
58
+ class AliasNodeInfo(SCons.Node.NodeInfoBase):
59
+ current_version_id = 1
60
+ field_list = ['csig']
61
+ def str_to_node(self, s):
62
+ return default_ans.Alias(s)
63
+
64
+ class AliasBuildInfo(SCons.Node.BuildInfoBase):
65
+ current_version_id = 1
66
+
67
+ class Alias(SCons.Node.Node):
68
+
69
+ NodeInfo = AliasNodeInfo
70
+ BuildInfo = AliasBuildInfo
71
+
72
+ def __init__(self, name):
73
+ SCons.Node.Node.__init__(self)
74
+ self.name = name
75
+
76
+ def str_for_display(self):
77
+ return '"' + self.__str__() + '"'
78
+
79
+ def __str__(self):
80
+ return self.name
81
+
82
+ def make_ready(self):
83
+ self.get_csig()
84
+
85
+ really_build = SCons.Node.Node.build
86
+ is_up_to_date = SCons.Node.Node.children_are_up_to_date
87
+
88
+ def is_under(self, dir):
89
+ # Make Alias nodes get built regardless of
90
+ # what directory scons was run from. Alias nodes
91
+ # are outside the filesystem:
92
+ return 1
93
+
94
+ def get_contents(self):
95
+ """The contents of an alias is the concatenation
96
+ of the content signatures of all its sources."""
97
+ childsigs = [n.get_csig() for n in self.children()]
98
+ return ''.join(childsigs)
99
+
100
+ def sconsign(self):
101
+ """An Alias is not recorded in .sconsign files"""
102
+ pass
103
+
104
+ #
105
+ #
106
+ #
107
+
108
+ def changed_since_last_build(self, target, prev_ni):
109
+ cur_csig = self.get_csig()
110
+ try:
111
+ return cur_csig != prev_ni.csig
112
+ except AttributeError:
113
+ return 1
114
+
115
+ def build(self):
116
+ """A "builder" for aliases."""
117
+ pass
118
+
119
+ def convert(self):
120
+ try: del self.builder
121
+ except AttributeError: pass
122
+ self.reset_executor()
123
+ self.build = self.really_build
124
+
125
+ def get_csig(self):
126
+ """
127
+ Generate a node's content signature, the digested signature
128
+ of its content.
129
+
130
+ node - the node
131
+ cache - alternate node to use for the signature cache
132
+ returns - the content signature
133
+ """
134
+ try:
135
+ return self.ninfo.csig
136
+ except AttributeError:
137
+ pass
138
+
139
+ contents = self.get_contents()
140
+ csig = SCons.Util.MD5signature(contents)
141
+ self.get_ninfo().csig = csig
142
+ return csig
143
+
144
+ default_ans = AliasNameSpace()
145
+
146
+ SCons.Node.arg2nodes_lookups.append(default_ans.lookup)
147
+
148
+ # Local Variables:
149
+ # tab-width:4
150
+ # indent-tabs-mode:nil
151
+ # End:
152
+ # vim: set expandtab tabstop=4 shiftwidth=4:
@@ -0,0 +1,3142 @@
1
+ """scons.Node.FS
2
+
3
+ File system nodes.
4
+
5
+ These Nodes represent the canonical external objects that people think
6
+ of when they think of building software: files and directories.
7
+
8
+ This holds a "default_fs" variable that should be initialized with an FS
9
+ that can be used by scripts or modules looking for the canonical default.
10
+
11
+ """
12
+
13
+ #
14
+ # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 The SCons Foundation
15
+ #
16
+ # Permission is hereby granted, free of charge, to any person obtaining
17
+ # a copy of this software and associated documentation files (the
18
+ # "Software"), to deal in the Software without restriction, including
19
+ # without limitation the rights to use, copy, modify, merge, publish,
20
+ # distribute, sublicense, and/or sell copies of the Software, and to
21
+ # permit persons to whom the Software is furnished to do so, subject to
22
+ # the following conditions:
23
+ #
24
+ # The above copyright notice and this permission notice shall be included
25
+ # in all copies or substantial portions of the Software.
26
+ #
27
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
28
+ # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
29
+ # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
30
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
31
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
32
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
33
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34
+
35
+ __revision__ = "src/engine/SCons/Node/FS.py 5023 2010/06/14 22:05:46 scons"
36
+
37
+ import fnmatch
38
+ import os
39
+ import re
40
+ import shutil
41
+ import stat
42
+ import sys
43
+ import time
44
+ import codecs
45
+
46
+ import SCons.Action
47
+ from SCons.Debug import logInstanceCreation
48
+ import SCons.Errors
49
+ import SCons.Memoize
50
+ import SCons.Node
51
+ import SCons.Node.Alias
52
+ import SCons.Subst
53
+ import SCons.Util
54
+ import SCons.Warnings
55
+
56
+ from SCons.Debug import Trace
57
+
58
+ do_store_info = True
59
+
60
+
61
+ class EntryProxyAttributeError(AttributeError):
62
+ """
63
+ An AttributeError subclass for recording and displaying the name
64
+ of the underlying Entry involved in an AttributeError exception.
65
+ """
66
+ def __init__(self, entry_proxy, attribute):
67
+ AttributeError.__init__(self)
68
+ self.entry_proxy = entry_proxy
69
+ self.attribute = attribute
70
+ def __str__(self):
71
+ entry = self.entry_proxy.get()
72
+ fmt = "%s instance %s has no attribute %s"
73
+ return fmt % (entry.__class__.__name__,
74
+ repr(entry.name),
75
+ repr(self.attribute))
76
+
77
+ # The max_drift value: by default, use a cached signature value for
78
+ # any file that's been untouched for more than two days.
79
+ default_max_drift = 2*24*60*60
80
+
81
+ #
82
+ # We stringify these file system Nodes a lot. Turning a file system Node
83
+ # into a string is non-trivial, because the final string representation
84
+ # can depend on a lot of factors: whether it's a derived target or not,
85
+ # whether it's linked to a repository or source directory, and whether
86
+ # there's duplication going on. The normal technique for optimizing
87
+ # calculations like this is to memoize (cache) the string value, so you
88
+ # only have to do the calculation once.
89
+ #
90
+ # A number of the above factors, however, can be set after we've already
91
+ # been asked to return a string for a Node, because a Repository() or
92
+ # VariantDir() call or the like may not occur until later in SConscript
93
+ # files. So this variable controls whether we bother trying to save
94
+ # string values for Nodes. The wrapper interface can set this whenever
95
+ # they're done mucking with Repository and VariantDir and the other stuff,
96
+ # to let this module know it can start returning saved string values
97
+ # for Nodes.
98
+ #
99
+ Save_Strings = None
100
+
101
+ def save_strings(val):
102
+ global Save_Strings
103
+ Save_Strings = val
104
+
105
+ #
106
+ # Avoid unnecessary function calls by recording a Boolean value that
107
+ # tells us whether or not os.path.splitdrive() actually does anything
108
+ # on this system, and therefore whether we need to bother calling it
109
+ # when looking up path names in various methods below.
110
+ #
111
+
112
+ do_splitdrive = None
113
+
114
+ def initialize_do_splitdrive():
115
+ global do_splitdrive
116
+ drive, path = os.path.splitdrive('X:/foo')
117
+ do_splitdrive = not not drive
118
+
119
+ initialize_do_splitdrive()
120
+
121
+ #
122
+
123
+ needs_normpath_check = None
124
+
125
+ def initialize_normpath_check():
126
+ """
127
+ Initialize the normpath_check regular expression.
128
+
129
+ This function is used by the unit tests to re-initialize the pattern
130
+ when testing for behavior with different values of os.sep.
131
+ """
132
+ global needs_normpath_check
133
+ if os.sep == '/':
134
+ pattern = r'.*/|\.$|\.\.$'
135
+ else:
136
+ pattern = r'.*[/%s]|\.$|\.\.$' % re.escape(os.sep)
137
+ needs_normpath_check = re.compile(pattern)
138
+
139
+ initialize_normpath_check()
140
+
141
+ #
142
+ # SCons.Action objects for interacting with the outside world.
143
+ #
144
+ # The Node.FS methods in this module should use these actions to
145
+ # create and/or remove files and directories; they should *not* use
146
+ # os.{link,symlink,unlink,mkdir}(), etc., directly.
147
+ #
148
+ # Using these SCons.Action objects ensures that descriptions of these
149
+ # external activities are properly displayed, that the displays are
150
+ # suppressed when the -s (silent) option is used, and (most importantly)
151
+ # the actions are disabled when the the -n option is used, in which case
152
+ # there should be *no* changes to the external file system(s)...
153
+ #
154
+
155
+ if hasattr(os, 'link'):
156
+ def _hardlink_func(fs, src, dst):
157
+ # If the source is a symlink, we can't just hard-link to it
158
+ # because a relative symlink may point somewhere completely
159
+ # different. We must disambiguate the symlink and then
160
+ # hard-link the final destination file.
161
+ while fs.islink(src):
162
+ link = fs.readlink(src)
163
+ if not os.path.isabs(link):
164
+ src = link
165
+ else:
166
+ src = os.path.join(os.path.dirname(src), link)
167
+ fs.link(src, dst)
168
+ else:
169
+ _hardlink_func = None
170
+
171
+ if hasattr(os, 'symlink'):
172
+ def _softlink_func(fs, src, dst):
173
+ fs.symlink(src, dst)
174
+ else:
175
+ _softlink_func = None
176
+
177
+ def _copy_func(fs, src, dest):
178
+ shutil.copy2(src, dest)
179
+ st = fs.stat(src)
180
+ fs.chmod(dest, stat.S_IMODE(st[stat.ST_MODE]) | stat.S_IWRITE)
181
+
182
+
183
+ Valid_Duplicates = ['hard-soft-copy', 'soft-hard-copy',
184
+ 'hard-copy', 'soft-copy', 'copy']
185
+
186
+ Link_Funcs = [] # contains the callables of the specified duplication style
187
+
188
+ def set_duplicate(duplicate):
189
+ # Fill in the Link_Funcs list according to the argument
190
+ # (discarding those not available on the platform).
191
+
192
+ # Set up the dictionary that maps the argument names to the
193
+ # underlying implementations. We do this inside this function,
194
+ # not in the top-level module code, so that we can remap os.link
195
+ # and os.symlink for testing purposes.
196
+ link_dict = {
197
+ 'hard' : _hardlink_func,
198
+ 'soft' : _softlink_func,
199
+ 'copy' : _copy_func
200
+ }
201
+
202
+ if not duplicate in Valid_Duplicates:
203
+ raise SCons.Errors.InternalError("The argument of set_duplicate "
204
+ "should be in Valid_Duplicates")
205
+ global Link_Funcs
206
+ Link_Funcs = []
207
+ for func in duplicate.split('-'):
208
+ if link_dict[func]:
209
+ Link_Funcs.append(link_dict[func])
210
+
211
+ def LinkFunc(target, source, env):
212
+ # Relative paths cause problems with symbolic links, so
213
+ # we use absolute paths, which may be a problem for people
214
+ # who want to move their soft-linked src-trees around. Those
215
+ # people should use the 'hard-copy' mode, softlinks cannot be
216
+ # used for that; at least I have no idea how ...
217
+ src = source[0].abspath
218
+ dest = target[0].abspath
219
+ dir, file = os.path.split(dest)
220
+ if dir and not target[0].fs.isdir(dir):
221
+ os.makedirs(dir)
222
+ if not Link_Funcs:
223
+ # Set a default order of link functions.
224
+ set_duplicate('hard-soft-copy')
225
+ fs = source[0].fs
226
+ # Now link the files with the previously specified order.
227
+ for func in Link_Funcs:
228
+ try:
229
+ func(fs, src, dest)
230
+ break
231
+ except (IOError, OSError):
232
+ # An OSError indicates something happened like a permissions
233
+ # problem or an attempt to symlink across file-system
234
+ # boundaries. An IOError indicates something like the file
235
+ # not existing. In either case, keeping trying additional
236
+ # functions in the list and only raise an error if the last
237
+ # one failed.
238
+ if func == Link_Funcs[-1]:
239
+ # exception of the last link method (copy) are fatal
240
+ raise
241
+ return 0
242
+
243
+ Link = SCons.Action.Action(LinkFunc, None)
244
+ def LocalString(target, source, env):
245
+ return 'Local copy of %s from %s' % (target[0], source[0])
246
+
247
+ LocalCopy = SCons.Action.Action(LinkFunc, LocalString)
248
+
249
+ def UnlinkFunc(target, source, env):
250
+ t = target[0]
251
+ t.fs.unlink(t.abspath)
252
+ return 0
253
+
254
+ Unlink = SCons.Action.Action(UnlinkFunc, None)
255
+
256
+ def MkdirFunc(target, source, env):
257
+ t = target[0]
258
+ if not t.exists():
259
+ t.fs.mkdir(t.abspath)
260
+ return 0
261
+
262
+ Mkdir = SCons.Action.Action(MkdirFunc, None, presub=None)
263
+
264
+ MkdirBuilder = None
265
+
266
+ def get_MkdirBuilder():
267
+ global MkdirBuilder
268
+ if MkdirBuilder is None:
269
+ import SCons.Builder
270
+ import SCons.Defaults
271
+ # "env" will get filled in by Executor.get_build_env()
272
+ # calling SCons.Defaults.DefaultEnvironment() when necessary.
273
+ MkdirBuilder = SCons.Builder.Builder(action = Mkdir,
274
+ env = None,
275
+ explain = None,
276
+ is_explicit = None,
277
+ target_scanner = SCons.Defaults.DirEntryScanner,
278
+ name = "MkdirBuilder")
279
+ return MkdirBuilder
280
+
281
+ class _Null(object):
282
+ pass
283
+
284
+ _null = _Null()
285
+
286
+ DefaultSCCSBuilder = None
287
+ DefaultRCSBuilder = None
288
+
289
+ def get_DefaultSCCSBuilder():
290
+ global DefaultSCCSBuilder
291
+ if DefaultSCCSBuilder is None:
292
+ import SCons.Builder
293
+ # "env" will get filled in by Executor.get_build_env()
294
+ # calling SCons.Defaults.DefaultEnvironment() when necessary.
295
+ act = SCons.Action.Action('$SCCSCOM', '$SCCSCOMSTR')
296
+ DefaultSCCSBuilder = SCons.Builder.Builder(action = act,
297
+ env = None,
298
+ name = "DefaultSCCSBuilder")
299
+ return DefaultSCCSBuilder
300
+
301
+ def get_DefaultRCSBuilder():
302
+ global DefaultRCSBuilder
303
+ if DefaultRCSBuilder is None:
304
+ import SCons.Builder
305
+ # "env" will get filled in by Executor.get_build_env()
306
+ # calling SCons.Defaults.DefaultEnvironment() when necessary.
307
+ act = SCons.Action.Action('$RCS_COCOM', '$RCS_COCOMSTR')
308
+ DefaultRCSBuilder = SCons.Builder.Builder(action = act,
309
+ env = None,
310
+ name = "DefaultRCSBuilder")
311
+ return DefaultRCSBuilder
312
+
313
+ # Cygwin's os.path.normcase pretends it's on a case-sensitive filesystem.
314
+ _is_cygwin = sys.platform == "cygwin"
315
+ if os.path.normcase("TeSt") == os.path.normpath("TeSt") and not _is_cygwin:
316
+ def _my_normcase(x):
317
+ return x
318
+ else:
319
+ def _my_normcase(x):
320
+ return x.upper()
321
+
322
+
323
+
324
+ class DiskChecker(object):
325
+ def __init__(self, type, do, ignore):
326
+ self.type = type
327
+ self.do = do
328
+ self.ignore = ignore
329
+ self.func = do
330
+ def __call__(self, *args, **kw):
331
+ return self.func(*args, **kw)
332
+ def set(self, list):
333
+ if self.type in list:
334
+ self.func = self.do
335
+ else:
336
+ self.func = self.ignore
337
+
338
+ def do_diskcheck_match(node, predicate, errorfmt):
339
+ result = predicate()
340
+ try:
341
+ # If calling the predicate() cached a None value from stat(),
342
+ # remove it so it doesn't interfere with later attempts to
343
+ # build this Node as we walk the DAG. (This isn't a great way
344
+ # to do this, we're reaching into an interface that doesn't
345
+ # really belong to us, but it's all about performance, so
346
+ # for now we'll just document the dependency...)
347
+ if node._memo['stat'] is None:
348
+ del node._memo['stat']
349
+ except (AttributeError, KeyError):
350
+ pass
351
+ if result:
352
+ raise TypeError(errorfmt % node.abspath)
353
+
354
+ def ignore_diskcheck_match(node, predicate, errorfmt):
355
+ pass
356
+
357
+ def do_diskcheck_rcs(node, name):
358
+ try:
359
+ rcs_dir = node.rcs_dir
360
+ except AttributeError:
361
+ if node.entry_exists_on_disk('RCS'):
362
+ rcs_dir = node.Dir('RCS')
363
+ else:
364
+ rcs_dir = None
365
+ node.rcs_dir = rcs_dir
366
+ if rcs_dir:
367
+ return rcs_dir.entry_exists_on_disk(name+',v')
368
+ return None
369
+
370
+ def ignore_diskcheck_rcs(node, name):
371
+ return None
372
+
373
+ def do_diskcheck_sccs(node, name):
374
+ try:
375
+ sccs_dir = node.sccs_dir
376
+ except AttributeError:
377
+ if node.entry_exists_on_disk('SCCS'):
378
+ sccs_dir = node.Dir('SCCS')
379
+ else:
380
+ sccs_dir = None
381
+ node.sccs_dir = sccs_dir
382
+ if sccs_dir:
383
+ return sccs_dir.entry_exists_on_disk('s.'+name)
384
+ return None
385
+
386
+ def ignore_diskcheck_sccs(node, name):
387
+ return None
388
+
389
+ diskcheck_match = DiskChecker('match', do_diskcheck_match, ignore_diskcheck_match)
390
+ diskcheck_rcs = DiskChecker('rcs', do_diskcheck_rcs, ignore_diskcheck_rcs)
391
+ diskcheck_sccs = DiskChecker('sccs', do_diskcheck_sccs, ignore_diskcheck_sccs)
392
+
393
+ diskcheckers = [
394
+ diskcheck_match,
395
+ diskcheck_rcs,
396
+ diskcheck_sccs,
397
+ ]
398
+
399
+ def set_diskcheck(list):
400
+ for dc in diskcheckers:
401
+ dc.set(list)
402
+
403
+ def diskcheck_types():
404
+ return [dc.type for dc in diskcheckers]
405
+
406
+
407
+
408
+ class EntryProxy(SCons.Util.Proxy):
409
+
410
+ __str__ = SCons.Util.Delegate('__str__')
411
+
412
+ def __get_abspath(self):
413
+ entry = self.get()
414
+ return SCons.Subst.SpecialAttrWrapper(entry.get_abspath(),
415
+ entry.name + "_abspath")
416
+
417
+ def __get_filebase(self):
418
+ name = self.get().name
419
+ return SCons.Subst.SpecialAttrWrapper(SCons.Util.splitext(name)[0],
420
+ name + "_filebase")
421
+
422
+ def __get_suffix(self):
423
+ name = self.get().name
424
+ return SCons.Subst.SpecialAttrWrapper(SCons.Util.splitext(name)[1],
425
+ name + "_suffix")
426
+
427
+ def __get_file(self):
428
+ name = self.get().name
429
+ return SCons.Subst.SpecialAttrWrapper(name, name + "_file")
430
+
431
+ def __get_base_path(self):
432
+ """Return the file's directory and file name, with the
433
+ suffix stripped."""
434
+ entry = self.get()
435
+ return SCons.Subst.SpecialAttrWrapper(SCons.Util.splitext(entry.get_path())[0],
436
+ entry.name + "_base")
437
+
438
+ def __get_posix_path(self):
439
+ """Return the path with / as the path separator,
440
+ regardless of platform."""
441
+ if os.sep == '/':
442
+ return self
443
+ else:
444
+ entry = self.get()
445
+ r = entry.get_path().replace(os.sep, '/')
446
+ return SCons.Subst.SpecialAttrWrapper(r, entry.name + "_posix")
447
+
448
+ def __get_windows_path(self):
449
+ """Return the path with \ as the path separator,
450
+ regardless of platform."""
451
+ if os.sep == '\\':
452
+ return self
453
+ else:
454
+ entry = self.get()
455
+ r = entry.get_path().replace(os.sep, '\\')
456
+ return SCons.Subst.SpecialAttrWrapper(r, entry.name + "_windows")
457
+
458
+ def __get_srcnode(self):
459
+ return EntryProxy(self.get().srcnode())
460
+
461
+ def __get_srcdir(self):
462
+ """Returns the directory containing the source node linked to this
463
+ node via VariantDir(), or the directory of this node if not linked."""
464
+ return EntryProxy(self.get().srcnode().dir)
465
+
466
+ def __get_rsrcnode(self):
467
+ return EntryProxy(self.get().srcnode().rfile())
468
+
469
+ def __get_rsrcdir(self):
470
+ """Returns the directory containing the source node linked to this
471
+ node via VariantDir(), or the directory of this node if not linked."""
472
+ return EntryProxy(self.get().srcnode().rfile().dir)
473
+
474
+ def __get_dir(self):
475
+ return EntryProxy(self.get().dir)
476
+
477
+ dictSpecialAttrs = { "base" : __get_base_path,
478
+ "posix" : __get_posix_path,
479
+ "windows" : __get_windows_path,
480
+ "win32" : __get_windows_path,
481
+ "srcpath" : __get_srcnode,
482
+ "srcdir" : __get_srcdir,
483
+ "dir" : __get_dir,
484
+ "abspath" : __get_abspath,
485
+ "filebase" : __get_filebase,
486
+ "suffix" : __get_suffix,
487
+ "file" : __get_file,
488
+ "rsrcpath" : __get_rsrcnode,
489
+ "rsrcdir" : __get_rsrcdir,
490
+ }
491
+
492
+ def __getattr__(self, name):
493
+ # This is how we implement the "special" attributes
494
+ # such as base, posix, srcdir, etc.
495
+ try:
496
+ attr_function = self.dictSpecialAttrs[name]
497
+ except KeyError:
498
+ try:
499
+ attr = SCons.Util.Proxy.__getattr__(self, name)
500
+ except AttributeError, e:
501
+ # Raise our own AttributeError subclass with an
502
+ # overridden __str__() method that identifies the
503
+ # name of the entry that caused the exception.
504
+ raise EntryProxyAttributeError(self, name)
505
+ return attr
506
+ else:
507
+ return attr_function(self)
508
+
509
+ class Base(SCons.Node.Node):
510
+ """A generic class for file system entries. This class is for
511
+ when we don't know yet whether the entry being looked up is a file
512
+ or a directory. Instances of this class can morph into either
513
+ Dir or File objects by a later, more precise lookup.
514
+
515
+ Note: this class does not define __cmp__ and __hash__ for
516
+ efficiency reasons. SCons does a lot of comparing of
517
+ Node.FS.{Base,Entry,File,Dir} objects, so those operations must be
518
+ as fast as possible, which means we want to use Python's built-in
519
+ object identity comparisons.
520
+ """
521
+
522
+ memoizer_counters = []
523
+
524
+ def __init__(self, name, directory, fs):
525
+ """Initialize a generic Node.FS.Base object.
526
+
527
+ Call the superclass initialization, take care of setting up
528
+ our relative and absolute paths, identify our parent
529
+ directory, and indicate that this node should use
530
+ signatures."""
531
+ if __debug__: logInstanceCreation(self, 'Node.FS.Base')
532
+ SCons.Node.Node.__init__(self)
533
+
534
+ # Filenames and paths are probably reused and are intern'ed to
535
+ # save some memory.
536
+ self.name = SCons.Util.silent_intern(name)
537
+ self.suffix = SCons.Util.silent_intern(SCons.Util.splitext(name)[1])
538
+ self.fs = fs
539
+
540
+ assert directory, "A directory must be provided"
541
+
542
+ self.abspath = SCons.Util.silent_intern(directory.entry_abspath(name))
543
+ self.labspath = SCons.Util.silent_intern(directory.entry_labspath(name))
544
+ if directory.path == '.':
545
+ self.path = SCons.Util.silent_intern(name)
546
+ else:
547
+ self.path = SCons.Util.silent_intern(directory.entry_path(name))
548
+ if directory.tpath == '.':
549
+ self.tpath = SCons.Util.silent_intern(name)
550
+ else:
551
+ self.tpath = SCons.Util.silent_intern(directory.entry_tpath(name))
552
+ self.path_elements = directory.path_elements + [self]
553
+
554
+ self.dir = directory
555
+ self.cwd = None # will hold the SConscript directory for target nodes
556
+ self.duplicate = directory.duplicate
557
+
558
+ def str_for_display(self):
559
+ return '"' + self.__str__() + '"'
560
+
561
+ def must_be_same(self, klass):
562
+ """
563
+ This node, which already existed, is being looked up as the
564
+ specified klass. Raise an exception if it isn't.
565
+ """
566
+ if isinstance(self, klass) or klass is Entry:
567
+ return
568
+ raise TypeError("Tried to lookup %s '%s' as a %s." %\
569
+ (self.__class__.__name__, self.path, klass.__name__))
570
+
571
+ def get_dir(self):
572
+ return self.dir
573
+
574
+ def get_suffix(self):
575
+ return self.suffix
576
+
577
+ def rfile(self):
578
+ return self
579
+
580
+ def __str__(self):
581
+ """A Node.FS.Base object's string representation is its path
582
+ name."""
583
+ global Save_Strings
584
+ if Save_Strings:
585
+ return self._save_str()
586
+ return self._get_str()
587
+
588
+ memoizer_counters.append(SCons.Memoize.CountValue('_save_str'))
589
+
590
+ def _save_str(self):
591
+ try:
592
+ return self._memo['_save_str']
593
+ except KeyError:
594
+ pass
595
+ result = sys.intern(self._get_str())
596
+ self._memo['_save_str'] = result
597
+ return result
598
+
599
+ def _get_str(self):
600
+ global Save_Strings
601
+ if self.duplicate or self.is_derived():
602
+ return self.get_path()
603
+ srcnode = self.srcnode()
604
+ if srcnode.stat() is None and self.stat() is not None:
605
+ result = self.get_path()
606
+ else:
607
+ result = srcnode.get_path()
608
+ if not Save_Strings:
609
+ # We're not at the point where we're saving the string string
610
+ # representations of FS Nodes (because we haven't finished
611
+ # reading the SConscript files and need to have str() return
612
+ # things relative to them). That also means we can't yet
613
+ # cache values returned (or not returned) by stat(), since
614
+ # Python code in the SConscript files might still create
615
+ # or otherwise affect the on-disk file. So get rid of the
616
+ # values that the underlying stat() method saved.
617
+ try: del self._memo['stat']
618
+ except KeyError: pass
619
+ if self is not srcnode:
620
+ try: del srcnode._memo['stat']
621
+ except KeyError: pass
622
+ return result
623
+
624
+ rstr = __str__
625
+
626
+ memoizer_counters.append(SCons.Memoize.CountValue('stat'))
627
+
628
+ def stat(self):
629
+ try: return self._memo['stat']
630
+ except KeyError: pass
631
+ try: result = self.fs.stat(self.abspath)
632
+ except os.error: result = None
633
+ self._memo['stat'] = result
634
+ return result
635
+
636
+ def exists(self):
637
+ return self.stat() is not None
638
+
639
+ def rexists(self):
640
+ return self.rfile().exists()
641
+
642
+ def getmtime(self):
643
+ st = self.stat()
644
+ if st: return st[stat.ST_MTIME]
645
+ else: return None
646
+
647
+ def getsize(self):
648
+ st = self.stat()
649
+ if st: return st[stat.ST_SIZE]
650
+ else: return None
651
+
652
+ def isdir(self):
653
+ st = self.stat()
654
+ return st is not None and stat.S_ISDIR(st[stat.ST_MODE])
655
+
656
+ def isfile(self):
657
+ st = self.stat()
658
+ return st is not None and stat.S_ISREG(st[stat.ST_MODE])
659
+
660
+ if hasattr(os, 'symlink'):
661
+ def islink(self):
662
+ try: st = self.fs.lstat(self.abspath)
663
+ except os.error: return 0
664
+ return stat.S_ISLNK(st[stat.ST_MODE])
665
+ else:
666
+ def islink(self):
667
+ return 0 # no symlinks
668
+
669
+ def is_under(self, dir):
670
+ if self is dir:
671
+ return 1
672
+ else:
673
+ return self.dir.is_under(dir)
674
+
675
+ def set_local(self):
676
+ self._local = 1
677
+
678
+ def srcnode(self):
679
+ """If this node is in a build path, return the node
680
+ corresponding to its source file. Otherwise, return
681
+ ourself.
682
+ """
683
+ srcdir_list = self.dir.srcdir_list()
684
+ if srcdir_list:
685
+ srcnode = srcdir_list[0].Entry(self.name)
686
+ srcnode.must_be_same(self.__class__)
687
+ return srcnode
688
+ return self
689
+
690
+ def get_path(self, dir=None):
691
+ """Return path relative to the current working directory of the
692
+ Node.FS.Base object that owns us."""
693
+ if not dir:
694
+ dir = self.fs.getcwd()
695
+ if self == dir:
696
+ return '.'
697
+ path_elems = self.path_elements
698
+ try: i = path_elems.index(dir)
699
+ except ValueError: pass
700
+ else: path_elems = path_elems[i+1:]
701
+ path_elems = [n.name for n in path_elems]
702
+ return os.sep.join(path_elems)
703
+
704
+ def set_src_builder(self, builder):
705
+ """Set the source code builder for this node."""
706
+ self.sbuilder = builder
707
+ if not self.has_builder():
708
+ self.builder_set(builder)
709
+
710
+ def src_builder(self):
711
+ """Fetch the source code builder for this node.
712
+
713
+ If there isn't one, we cache the source code builder specified
714
+ for the directory (which in turn will cache the value from its
715
+ parent directory, and so on up to the file system root).
716
+ """
717
+ try:
718
+ scb = self.sbuilder
719
+ except AttributeError:
720
+ scb = self.dir.src_builder()
721
+ self.sbuilder = scb
722
+ return scb
723
+
724
+ def get_abspath(self):
725
+ """Get the absolute path of the file."""
726
+ return self.abspath
727
+
728
+ def for_signature(self):
729
+ # Return just our name. Even an absolute path would not work,
730
+ # because that can change thanks to symlinks or remapped network
731
+ # paths.
732
+ return self.name
733
+
734
+ def get_subst_proxy(self):
735
+ try:
736
+ return self._proxy
737
+ except AttributeError:
738
+ ret = EntryProxy(self)
739
+ self._proxy = ret
740
+ return ret
741
+
742
+ def target_from_source(self, prefix, suffix, splitext=SCons.Util.splitext):
743
+ """
744
+
745
+ Generates a target entry that corresponds to this entry (usually
746
+ a source file) with the specified prefix and suffix.
747
+
748
+ Note that this method can be overridden dynamically for generated
749
+ files that need different behavior. See Tool/swig.py for
750
+ an example.
751
+ """
752
+ return self.dir.Entry(prefix + splitext(self.name)[0] + suffix)
753
+
754
+ def _Rfindalldirs_key(self, pathlist):
755
+ return pathlist
756
+
757
+ memoizer_counters.append(SCons.Memoize.CountDict('Rfindalldirs', _Rfindalldirs_key))
758
+
759
+ def Rfindalldirs(self, pathlist):
760
+ """
761
+ Return all of the directories for a given path list, including
762
+ corresponding "backing" directories in any repositories.
763
+
764
+ The Node lookups are relative to this Node (typically a
765
+ directory), so memoizing result saves cycles from looking
766
+ up the same path for each target in a given directory.
767
+ """
768
+ try:
769
+ memo_dict = self._memo['Rfindalldirs']
770
+ except KeyError:
771
+ memo_dict = {}
772
+ self._memo['Rfindalldirs'] = memo_dict
773
+ else:
774
+ try:
775
+ return memo_dict[pathlist]
776
+ except KeyError:
777
+ pass
778
+
779
+ create_dir_relative_to_self = self.Dir
780
+ result = []
781
+ for path in pathlist:
782
+ if isinstance(path, SCons.Node.Node):
783
+ result.append(path)
784
+ else:
785
+ dir = create_dir_relative_to_self(path)
786
+ result.extend(dir.get_all_rdirs())
787
+
788
+ memo_dict[pathlist] = result
789
+
790
+ return result
791
+
792
+ def RDirs(self, pathlist):
793
+ """Search for a list of directories in the Repository list."""
794
+ cwd = self.cwd or self.fs._cwd
795
+ return cwd.Rfindalldirs(pathlist)
796
+
797
+ memoizer_counters.append(SCons.Memoize.CountValue('rentry'))
798
+
799
+ def rentry(self):
800
+ try:
801
+ return self._memo['rentry']
802
+ except KeyError:
803
+ pass
804
+ result = self
805
+ if not self.exists():
806
+ norm_name = _my_normcase(self.name)
807
+ for dir in self.dir.get_all_rdirs():
808
+ try:
809
+ node = dir.entries[norm_name]
810
+ except KeyError:
811
+ if dir.entry_exists_on_disk(self.name):
812
+ result = dir.Entry(self.name)
813
+ break
814
+ self._memo['rentry'] = result
815
+ return result
816
+
817
+ def _glob1(self, pattern, ondisk=True, source=False, strings=False):
818
+ return []
819
+
820
+ class Entry(Base):
821
+ """This is the class for generic Node.FS entries--that is, things
822
+ that could be a File or a Dir, but we're just not sure yet.
823
+ Consequently, the methods in this class really exist just to
824
+ transform their associated object into the right class when the
825
+ time comes, and then call the same-named method in the transformed
826
+ class."""
827
+
828
+ def diskcheck_match(self):
829
+ pass
830
+
831
+ def disambiguate(self, must_exist=None):
832
+ """
833
+ """
834
+ if self.isdir():
835
+ self.__class__ = Dir
836
+ self._morph()
837
+ elif self.isfile():
838
+ self.__class__ = File
839
+ self._morph()
840
+ self.clear()
841
+ else:
842
+ # There was nothing on-disk at this location, so look in
843
+ # the src directory.
844
+ #
845
+ # We can't just use self.srcnode() straight away because
846
+ # that would create an actual Node for this file in the src
847
+ # directory, and there might not be one. Instead, use the
848
+ # dir_on_disk() method to see if there's something on-disk
849
+ # with that name, in which case we can go ahead and call
850
+ # self.srcnode() to create the right type of entry.
851
+ srcdir = self.dir.srcnode()
852
+ if srcdir != self.dir and \
853
+ srcdir.entry_exists_on_disk(self.name) and \
854
+ self.srcnode().isdir():
855
+ self.__class__ = Dir
856
+ self._morph()
857
+ elif must_exist:
858
+ msg = "No such file or directory: '%s'" % self.abspath
859
+ raise SCons.Errors.UserError(msg)
860
+ else:
861
+ self.__class__ = File
862
+ self._morph()
863
+ self.clear()
864
+ return self
865
+
866
+ def rfile(self):
867
+ """We're a generic Entry, but the caller is actually looking for
868
+ a File at this point, so morph into one."""
869
+ self.__class__ = File
870
+ self._morph()
871
+ self.clear()
872
+ return File.rfile(self)
873
+
874
+ def scanner_key(self):
875
+ return self.get_suffix()
876
+
877
+ def get_contents(self):
878
+ """Fetch the contents of the entry. Returns the exact binary
879
+ contents of the file."""
880
+ try:
881
+ self = self.disambiguate(must_exist=1)
882
+ except SCons.Errors.UserError:
883
+ # There was nothing on disk with which to disambiguate
884
+ # this entry. Leave it as an Entry, but return a null
885
+ # string so calls to get_contents() in emitters and the
886
+ # like (e.g. in qt.py) don't have to disambiguate by hand
887
+ # or catch the exception.
888
+ return ''
889
+ else:
890
+ return self.get_contents()
891
+
892
+ def get_text_contents(self):
893
+ """Fetch the decoded text contents of a Unicode encoded Entry.
894
+
895
+ Since this should return the text contents from the file
896
+ system, we check to see into what sort of subclass we should
897
+ morph this Entry."""
898
+ try:
899
+ self = self.disambiguate(must_exist=1)
900
+ except SCons.Errors.UserError:
901
+ # There was nothing on disk with which to disambiguate
902
+ # this entry. Leave it as an Entry, but return a null
903
+ # string so calls to get_text_contents() in emitters and
904
+ # the like (e.g. in qt.py) don't have to disambiguate by
905
+ # hand or catch the exception.
906
+ return ''
907
+ else:
908
+ return self.get_text_contents()
909
+
910
+ def must_be_same(self, klass):
911
+ """Called to make sure a Node is a Dir. Since we're an
912
+ Entry, we can morph into one."""
913
+ if self.__class__ is not klass:
914
+ self.__class__ = klass
915
+ self._morph()
916
+ self.clear()
917
+
918
+ # The following methods can get called before the Taskmaster has
919
+ # had a chance to call disambiguate() directly to see if this Entry
920
+ # should really be a Dir or a File. We therefore use these to call
921
+ # disambiguate() transparently (from our caller's point of view).
922
+ #
923
+ # Right now, this minimal set of methods has been derived by just
924
+ # looking at some of the methods that will obviously be called early
925
+ # in any of the various Taskmasters' calling sequences, and then
926
+ # empirically figuring out which additional methods are necessary
927
+ # to make various tests pass.
928
+
929
+ def exists(self):
930
+ """Return if the Entry exists. Check the file system to see
931
+ what we should turn into first. Assume a file if there's no
932
+ directory."""
933
+ return self.disambiguate().exists()
934
+
935
+ def rel_path(self, other):
936
+ d = self.disambiguate()
937
+ if d.__class__ is Entry:
938
+ raise Exception("rel_path() could not disambiguate File/Dir")
939
+ return d.rel_path(other)
940
+
941
+ def new_ninfo(self):
942
+ return self.disambiguate().new_ninfo()
943
+
944
+ def changed_since_last_build(self, target, prev_ni):
945
+ return self.disambiguate().changed_since_last_build(target, prev_ni)
946
+
947
+ def _glob1(self, pattern, ondisk=True, source=False, strings=False):
948
+ return self.disambiguate()._glob1(pattern, ondisk, source, strings)
949
+
950
+ def get_subst_proxy(self):
951
+ return self.disambiguate().get_subst_proxy()
952
+
953
+ # This is for later so we can differentiate between Entry the class and Entry
954
+ # the method of the FS class.
955
+ _classEntry = Entry
956
+
957
+
958
+ class LocalFS(object):
959
+
960
+ if SCons.Memoize.use_memoizer:
961
+ __metaclass__ = SCons.Memoize.Memoized_Metaclass
962
+
963
+ # This class implements an abstraction layer for operations involving
964
+ # a local file system. Essentially, this wraps any function in
965
+ # the os, os.path or shutil modules that we use to actually go do
966
+ # anything with or to the local file system.
967
+ #
968
+ # Note that there's a very good chance we'll refactor this part of
969
+ # the architecture in some way as we really implement the interface(s)
970
+ # for remote file system Nodes. For example, the right architecture
971
+ # might be to have this be a subclass instead of a base class.
972
+ # Nevertheless, we're using this as a first step in that direction.
973
+ #
974
+ # We're not using chdir() yet because the calling subclass method
975
+ # needs to use os.chdir() directly to avoid recursion. Will we
976
+ # really need this one?
977
+ #def chdir(self, path):
978
+ # return os.chdir(path)
979
+ def chmod(self, path, mode):
980
+ return os.chmod(path, mode)
981
+ def copy(self, src, dst):
982
+ return shutil.copy(src, dst)
983
+ def copy2(self, src, dst):
984
+ return shutil.copy2(src, dst)
985
+ def exists(self, path):
986
+ return os.path.exists(path)
987
+ def getmtime(self, path):
988
+ return os.path.getmtime(path)
989
+ def getsize(self, path):
990
+ return os.path.getsize(path)
991
+ def isdir(self, path):
992
+ return os.path.isdir(path)
993
+ def isfile(self, path):
994
+ return os.path.isfile(path)
995
+ def link(self, src, dst):
996
+ return os.link(src, dst)
997
+ def lstat(self, path):
998
+ return os.lstat(path)
999
+ def listdir(self, path):
1000
+ return os.listdir(path)
1001
+ def makedirs(self, path):
1002
+ return os.makedirs(path)
1003
+ def mkdir(self, path):
1004
+ return os.mkdir(path)
1005
+ def rename(self, old, new):
1006
+ return os.rename(old, new)
1007
+ def stat(self, path):
1008
+ return os.stat(path)
1009
+ def symlink(self, src, dst):
1010
+ return os.symlink(src, dst)
1011
+ def open(self, path):
1012
+ return open(path)
1013
+ def unlink(self, path):
1014
+ return os.unlink(path)
1015
+
1016
+ if hasattr(os, 'symlink'):
1017
+ def islink(self, path):
1018
+ return os.path.islink(path)
1019
+ else:
1020
+ def islink(self, path):
1021
+ return 0 # no symlinks
1022
+
1023
+ if hasattr(os, 'readlink'):
1024
+ def readlink(self, file):
1025
+ return os.readlink(file)
1026
+ else:
1027
+ def readlink(self, file):
1028
+ return ''
1029
+
1030
+
1031
+ #class RemoteFS:
1032
+ # # Skeleton for the obvious methods we might need from the
1033
+ # # abstraction layer for a remote filesystem.
1034
+ # def upload(self, local_src, remote_dst):
1035
+ # pass
1036
+ # def download(self, remote_src, local_dst):
1037
+ # pass
1038
+
1039
+
1040
+ class FS(LocalFS):
1041
+
1042
+ memoizer_counters = []
1043
+
1044
+ def __init__(self, path = None):
1045
+ """Initialize the Node.FS subsystem.
1046
+
1047
+ The supplied path is the top of the source tree, where we
1048
+ expect to find the top-level build file. If no path is
1049
+ supplied, the current directory is the default.
1050
+
1051
+ The path argument must be a valid absolute path.
1052
+ """
1053
+ if __debug__: logInstanceCreation(self, 'Node.FS')
1054
+
1055
+ self._memo = {}
1056
+
1057
+ self.Root = {}
1058
+ self.SConstruct_dir = None
1059
+ self.max_drift = default_max_drift
1060
+
1061
+ self.Top = None
1062
+ if path is None:
1063
+ self.pathTop = os.getcwd()
1064
+ else:
1065
+ self.pathTop = path
1066
+ self.defaultDrive = _my_normcase(os.path.splitdrive(self.pathTop)[0])
1067
+
1068
+ self.Top = self.Dir(self.pathTop)
1069
+ self.Top.path = '.'
1070
+ self.Top.tpath = '.'
1071
+ self._cwd = self.Top
1072
+
1073
+ DirNodeInfo.fs = self
1074
+ FileNodeInfo.fs = self
1075
+
1076
+ def set_SConstruct_dir(self, dir):
1077
+ self.SConstruct_dir = dir
1078
+
1079
+ def get_max_drift(self):
1080
+ return self.max_drift
1081
+
1082
+ def set_max_drift(self, max_drift):
1083
+ self.max_drift = max_drift
1084
+
1085
+ def getcwd(self):
1086
+ return self._cwd
1087
+
1088
+ def chdir(self, dir, change_os_dir=0):
1089
+ """Change the current working directory for lookups.
1090
+ If change_os_dir is true, we will also change the "real" cwd
1091
+ to match.
1092
+ """
1093
+ curr=self._cwd
1094
+ try:
1095
+ if dir is not None:
1096
+ self._cwd = dir
1097
+ if change_os_dir:
1098
+ os.chdir(dir.abspath)
1099
+ except OSError:
1100
+ self._cwd = curr
1101
+ raise
1102
+
1103
+ def get_root(self, drive):
1104
+ """
1105
+ Returns the root directory for the specified drive, creating
1106
+ it if necessary.
1107
+ """
1108
+ drive = _my_normcase(drive)
1109
+ try:
1110
+ return self.Root[drive]
1111
+ except KeyError:
1112
+ root = RootDir(drive, self)
1113
+ self.Root[drive] = root
1114
+ if not drive:
1115
+ self.Root[self.defaultDrive] = root
1116
+ elif drive == self.defaultDrive:
1117
+ self.Root[''] = root
1118
+ return root
1119
+
1120
+ def _lookup(self, p, directory, fsclass, create=1):
1121
+ """
1122
+ The generic entry point for Node lookup with user-supplied data.
1123
+
1124
+ This translates arbitrary input into a canonical Node.FS object
1125
+ of the specified fsclass. The general approach for strings is
1126
+ to turn it into a fully normalized absolute path and then call
1127
+ the root directory's lookup_abs() method for the heavy lifting.
1128
+
1129
+ If the path name begins with '#', it is unconditionally
1130
+ interpreted relative to the top-level directory of this FS. '#'
1131
+ is treated as a synonym for the top-level SConstruct directory,
1132
+ much like '~' is treated as a synonym for the user's home
1133
+ directory in a UNIX shell. So both '#foo' and '#/foo' refer
1134
+ to the 'foo' subdirectory underneath the top-level SConstruct
1135
+ directory.
1136
+
1137
+ If the path name is relative, then the path is looked up relative
1138
+ to the specified directory, or the current directory (self._cwd,
1139
+ typically the SConscript directory) if the specified directory
1140
+ is None.
1141
+ """
1142
+ if isinstance(p, Base):
1143
+ # It's already a Node.FS object. Make sure it's the right
1144
+ # class and return.
1145
+ p.must_be_same(fsclass)
1146
+ return p
1147
+ # str(p) in case it's something like a proxy object
1148
+ p = str(p)
1149
+
1150
+ initial_hash = (p[0:1] == '#')
1151
+ if initial_hash:
1152
+ # There was an initial '#', so we strip it and override
1153
+ # whatever directory they may have specified with the
1154
+ # top-level SConstruct directory.
1155
+ p = p[1:]
1156
+ directory = self.Top
1157
+
1158
+ if directory and not isinstance(directory, Dir):
1159
+ directory = self.Dir(directory)
1160
+
1161
+ if do_splitdrive:
1162
+ drive, p = os.path.splitdrive(p)
1163
+ else:
1164
+ drive = ''
1165
+ if drive and not p:
1166
+ # This causes a naked drive letter to be treated as a synonym
1167
+ # for the root directory on that drive.
1168
+ p = os.sep
1169
+ absolute = os.path.isabs(p)
1170
+
1171
+ needs_normpath = needs_normpath_check.match(p)
1172
+
1173
+ if initial_hash or not absolute:
1174
+ # This is a relative lookup, either to the top-level
1175
+ # SConstruct directory (because of the initial '#') or to
1176
+ # the current directory (the path name is not absolute).
1177
+ # Add the string to the appropriate directory lookup path,
1178
+ # after which the whole thing gets normalized.
1179
+ if not directory:
1180
+ directory = self._cwd
1181
+ if p:
1182
+ p = directory.labspath + '/' + p
1183
+ else:
1184
+ p = directory.labspath
1185
+
1186
+ if needs_normpath:
1187
+ p = os.path.normpath(p)
1188
+
1189
+ if drive or absolute:
1190
+ root = self.get_root(drive)
1191
+ else:
1192
+ if not directory:
1193
+ directory = self._cwd
1194
+ root = directory.root
1195
+
1196
+ if os.sep != '/':
1197
+ p = p.replace(os.sep, '/')
1198
+ return root._lookup_abs(p, fsclass, create)
1199
+
1200
+ def Entry(self, name, directory = None, create = 1):
1201
+ """Look up or create a generic Entry node with the specified name.
1202
+ If the name is a relative path (begins with ./, ../, or a file
1203
+ name), then it is looked up relative to the supplied directory
1204
+ node, or to the top level directory of the FS (supplied at
1205
+ construction time) if no directory is supplied.
1206
+ """
1207
+ return self._lookup(name, directory, Entry, create)
1208
+
1209
+ def File(self, name, directory = None, create = 1):
1210
+ """Look up or create a File node with the specified name. If
1211
+ the name is a relative path (begins with ./, ../, or a file name),
1212
+ then it is looked up relative to the supplied directory node,
1213
+ or to the top level directory of the FS (supplied at construction
1214
+ time) if no directory is supplied.
1215
+
1216
+ This method will raise TypeError if a directory is found at the
1217
+ specified path.
1218
+ """
1219
+ return self._lookup(name, directory, File, create)
1220
+
1221
+ def Dir(self, name, directory = None, create = True):
1222
+ """Look up or create a Dir node with the specified name. If
1223
+ the name is a relative path (begins with ./, ../, or a file name),
1224
+ then it is looked up relative to the supplied directory node,
1225
+ or to the top level directory of the FS (supplied at construction
1226
+ time) if no directory is supplied.
1227
+
1228
+ This method will raise TypeError if a normal file is found at the
1229
+ specified path.
1230
+ """
1231
+ return self._lookup(name, directory, Dir, create)
1232
+
1233
+ def VariantDir(self, variant_dir, src_dir, duplicate=1):
1234
+ """Link the supplied variant directory to the source directory
1235
+ for purposes of building files."""
1236
+
1237
+ if not isinstance(src_dir, SCons.Node.Node):
1238
+ src_dir = self.Dir(src_dir)
1239
+ if not isinstance(variant_dir, SCons.Node.Node):
1240
+ variant_dir = self.Dir(variant_dir)
1241
+ if src_dir.is_under(variant_dir):
1242
+ raise SCons.Errors.UserError("Source directory cannot be under variant directory.")
1243
+ if variant_dir.srcdir:
1244
+ if variant_dir.srcdir == src_dir:
1245
+ return # We already did this.
1246
+ raise SCons.Errors.UserError("'%s' already has a source directory: '%s'."%(variant_dir, variant_dir.srcdir))
1247
+ variant_dir.link(src_dir, duplicate)
1248
+
1249
+ def Repository(self, *dirs):
1250
+ """Specify Repository directories to search."""
1251
+ for d in dirs:
1252
+ if not isinstance(d, SCons.Node.Node):
1253
+ d = self.Dir(d)
1254
+ self.Top.addRepository(d)
1255
+
1256
+ def variant_dir_target_climb(self, orig, dir, tail):
1257
+ """Create targets in corresponding variant directories
1258
+
1259
+ Climb the directory tree, and look up path names
1260
+ relative to any linked variant directories we find.
1261
+
1262
+ Even though this loops and walks up the tree, we don't memoize
1263
+ the return value because this is really only used to process
1264
+ the command-line targets.
1265
+ """
1266
+ targets = []
1267
+ message = None
1268
+ fmt = "building associated VariantDir targets: %s"
1269
+ start_dir = dir
1270
+ while dir:
1271
+ for bd in dir.variant_dirs:
1272
+ if start_dir.is_under(bd):
1273
+ # If already in the build-dir location, don't reflect
1274
+ return [orig], fmt % str(orig)
1275
+ p = os.path.join(bd.path, *tail)
1276
+ targets.append(self.Entry(p))
1277
+ tail = [dir.name] + tail
1278
+ dir = dir.up()
1279
+ if targets:
1280
+ message = fmt % ' '.join(map(str, targets))
1281
+ return targets, message
1282
+
1283
+ def Glob(self, pathname, ondisk=True, source=True, strings=False, cwd=None):
1284
+ """
1285
+ Globs
1286
+
1287
+ This is mainly a shim layer
1288
+ """
1289
+ if cwd is None:
1290
+ cwd = self.getcwd()
1291
+ return cwd.glob(pathname, ondisk, source, strings)
1292
+
1293
+ class DirNodeInfo(SCons.Node.NodeInfoBase):
1294
+ # This should get reset by the FS initialization.
1295
+ current_version_id = 1
1296
+
1297
+ fs = None
1298
+
1299
+ def str_to_node(self, s):
1300
+ top = self.fs.Top
1301
+ root = top.root
1302
+ if do_splitdrive:
1303
+ drive, s = os.path.splitdrive(s)
1304
+ if drive:
1305
+ root = self.fs.get_root(drive)
1306
+ if not os.path.isabs(s):
1307
+ s = top.labspath + '/' + s
1308
+ return root._lookup_abs(s, Entry)
1309
+
1310
+ class DirBuildInfo(SCons.Node.BuildInfoBase):
1311
+ current_version_id = 1
1312
+
1313
+ glob_magic_check = re.compile('[*?[]')
1314
+
1315
+ def has_glob_magic(s):
1316
+ return glob_magic_check.search(s) is not None
1317
+
1318
+ class Dir(Base):
1319
+ """A class for directories in a file system.
1320
+ """
1321
+
1322
+ memoizer_counters = []
1323
+
1324
+ NodeInfo = DirNodeInfo
1325
+ BuildInfo = DirBuildInfo
1326
+
1327
+ def __init__(self, name, directory, fs):
1328
+ if __debug__: logInstanceCreation(self, 'Node.FS.Dir')
1329
+ Base.__init__(self, name, directory, fs)
1330
+ self._morph()
1331
+
1332
+ def _morph(self):
1333
+ """Turn a file system Node (either a freshly initialized directory
1334
+ object or a separate Entry object) into a proper directory object.
1335
+
1336
+ Set up this directory's entries and hook it into the file
1337
+ system tree. Specify that directories (this Node) don't use
1338
+ signatures for calculating whether they're current.
1339
+ """
1340
+
1341
+ self.repositories = []
1342
+ self.srcdir = None
1343
+
1344
+ self.entries = {}
1345
+ self.entries['.'] = self
1346
+ self.entries['..'] = self.dir
1347
+ self.cwd = self
1348
+ self.searched = 0
1349
+ self._sconsign = None
1350
+ self.variant_dirs = []
1351
+ self.root = self.dir.root
1352
+
1353
+ # Don't just reset the executor, replace its action list,
1354
+ # because it might have some pre-or post-actions that need to
1355
+ # be preserved.
1356
+ self.builder = get_MkdirBuilder()
1357
+ self.get_executor().set_action_list(self.builder.action)
1358
+
1359
+ def diskcheck_match(self):
1360
+ diskcheck_match(self, self.isfile,
1361
+ "File %s found where directory expected.")
1362
+
1363
+ def __clearRepositoryCache(self, duplicate=None):
1364
+ """Called when we change the repository(ies) for a directory.
1365
+ This clears any cached information that is invalidated by changing
1366
+ the repository."""
1367
+
1368
+ for node in self.entries.values():
1369
+ if node != self.dir:
1370
+ if node != self and isinstance(node, Dir):
1371
+ node.__clearRepositoryCache(duplicate)
1372
+ else:
1373
+ node.clear()
1374
+ try:
1375
+ del node._srcreps
1376
+ except AttributeError:
1377
+ pass
1378
+ if duplicate is not None:
1379
+ node.duplicate=duplicate
1380
+
1381
+ def __resetDuplicate(self, node):
1382
+ if node != self:
1383
+ node.duplicate = node.get_dir().duplicate
1384
+
1385
+ def Entry(self, name):
1386
+ """
1387
+ Looks up or creates an entry node named 'name' relative to
1388
+ this directory.
1389
+ """
1390
+ return self.fs.Entry(name, self)
1391
+
1392
+ def Dir(self, name, create=True):
1393
+ """
1394
+ Looks up or creates a directory node named 'name' relative to
1395
+ this directory.
1396
+ """
1397
+ return self.fs.Dir(name, self, create)
1398
+
1399
+ def File(self, name):
1400
+ """
1401
+ Looks up or creates a file node named 'name' relative to
1402
+ this directory.
1403
+ """
1404
+ return self.fs.File(name, self)
1405
+
1406
+ def _lookup_rel(self, name, klass, create=1):
1407
+ """
1408
+ Looks up a *normalized* relative path name, relative to this
1409
+ directory.
1410
+
1411
+ This method is intended for use by internal lookups with
1412
+ already-normalized path data. For general-purpose lookups,
1413
+ use the Entry(), Dir() and File() methods above.
1414
+
1415
+ This method does *no* input checking and will die or give
1416
+ incorrect results if it's passed a non-normalized path name (e.g.,
1417
+ a path containing '..'), an absolute path name, a top-relative
1418
+ ('#foo') path name, or any kind of object.
1419
+ """
1420
+ name = self.entry_labspath(name)
1421
+ return self.root._lookup_abs(name, klass, create)
1422
+
1423
+ def link(self, srcdir, duplicate):
1424
+ """Set this directory as the variant directory for the
1425
+ supplied source directory."""
1426
+ self.srcdir = srcdir
1427
+ self.duplicate = duplicate
1428
+ self.__clearRepositoryCache(duplicate)
1429
+ srcdir.variant_dirs.append(self)
1430
+
1431
+ def getRepositories(self):
1432
+ """Returns a list of repositories for this directory.
1433
+ """
1434
+ if self.srcdir and not self.duplicate:
1435
+ return self.srcdir.get_all_rdirs() + self.repositories
1436
+ return self.repositories
1437
+
1438
+ memoizer_counters.append(SCons.Memoize.CountValue('get_all_rdirs'))
1439
+
1440
+ def get_all_rdirs(self):
1441
+ try:
1442
+ return list(self._memo['get_all_rdirs'])
1443
+ except KeyError:
1444
+ pass
1445
+
1446
+ result = [self]
1447
+ fname = '.'
1448
+ dir = self
1449
+ while dir:
1450
+ for rep in dir.getRepositories():
1451
+ result.append(rep.Dir(fname))
1452
+ if fname == '.':
1453
+ fname = dir.name
1454
+ else:
1455
+ fname = dir.name + os.sep + fname
1456
+ dir = dir.up()
1457
+
1458
+ self._memo['get_all_rdirs'] = list(result)
1459
+
1460
+ return result
1461
+
1462
+ def addRepository(self, dir):
1463
+ if dir != self and not dir in self.repositories:
1464
+ self.repositories.append(dir)
1465
+ dir.tpath = '.'
1466
+ self.__clearRepositoryCache()
1467
+
1468
+ def up(self):
1469
+ return self.entries['..']
1470
+
1471
+ def _rel_path_key(self, other):
1472
+ return str(other)
1473
+
1474
+ memoizer_counters.append(SCons.Memoize.CountDict('rel_path', _rel_path_key))
1475
+
1476
+ def rel_path(self, other):
1477
+ """Return a path to "other" relative to this directory.
1478
+ """
1479
+
1480
+ # This complicated and expensive method, which constructs relative
1481
+ # paths between arbitrary Node.FS objects, is no longer used
1482
+ # by SCons itself. It was introduced to store dependency paths
1483
+ # in .sconsign files relative to the target, but that ended up
1484
+ # being significantly inefficient.
1485
+ #
1486
+ # We're continuing to support the method because some SConstruct
1487
+ # files out there started using it when it was available, and
1488
+ # we're all about backwards compatibility..
1489
+
1490
+ try:
1491
+ memo_dict = self._memo['rel_path']
1492
+ except KeyError:
1493
+ memo_dict = {}
1494
+ self._memo['rel_path'] = memo_dict
1495
+ else:
1496
+ try:
1497
+ return memo_dict[other]
1498
+ except KeyError:
1499
+ pass
1500
+
1501
+ if self is other:
1502
+ result = '.'
1503
+
1504
+ elif not other in self.path_elements:
1505
+ try:
1506
+ other_dir = other.get_dir()
1507
+ except AttributeError:
1508
+ result = str(other)
1509
+ else:
1510
+ if other_dir is None:
1511
+ result = other.name
1512
+ else:
1513
+ dir_rel_path = self.rel_path(other_dir)
1514
+ if dir_rel_path == '.':
1515
+ result = other.name
1516
+ else:
1517
+ result = dir_rel_path + os.sep + other.name
1518
+ else:
1519
+ i = self.path_elements.index(other) + 1
1520
+
1521
+ path_elems = ['..'] * (len(self.path_elements) - i) \
1522
+ + [n.name for n in other.path_elements[i:]]
1523
+
1524
+ result = os.sep.join(path_elems)
1525
+
1526
+ memo_dict[other] = result
1527
+
1528
+ return result
1529
+
1530
+ def get_env_scanner(self, env, kw={}):
1531
+ import SCons.Defaults
1532
+ return SCons.Defaults.DirEntryScanner
1533
+
1534
+ def get_target_scanner(self):
1535
+ import SCons.Defaults
1536
+ return SCons.Defaults.DirEntryScanner
1537
+
1538
+ def get_found_includes(self, env, scanner, path):
1539
+ """Return this directory's implicit dependencies.
1540
+
1541
+ We don't bother caching the results because the scan typically
1542
+ shouldn't be requested more than once (as opposed to scanning
1543
+ .h file contents, which can be requested as many times as the
1544
+ files is #included by other files).
1545
+ """
1546
+ if not scanner:
1547
+ return []
1548
+ # Clear cached info for this Dir. If we already visited this
1549
+ # directory on our walk down the tree (because we didn't know at
1550
+ # that point it was being used as the source for another Node)
1551
+ # then we may have calculated build signature before realizing
1552
+ # we had to scan the disk. Now that we have to, though, we need
1553
+ # to invalidate the old calculated signature so that any node
1554
+ # dependent on our directory structure gets one that includes
1555
+ # info about everything on disk.
1556
+ self.clear()
1557
+ return scanner(self, env, path)
1558
+
1559
+ #
1560
+ # Taskmaster interface subsystem
1561
+ #
1562
+
1563
+ def prepare(self):
1564
+ pass
1565
+
1566
+ def build(self, **kw):
1567
+ """A null "builder" for directories."""
1568
+ global MkdirBuilder
1569
+ if self.builder is not MkdirBuilder:
1570
+ SCons.Node.Node.build(self, **kw)
1571
+
1572
+ #
1573
+ #
1574
+ #
1575
+
1576
+ def _create(self):
1577
+ """Create this directory, silently and without worrying about
1578
+ whether the builder is the default or not."""
1579
+ listDirs = []
1580
+ parent = self
1581
+ while parent:
1582
+ if parent.exists():
1583
+ break
1584
+ listDirs.append(parent)
1585
+ p = parent.up()
1586
+ if p is None:
1587
+ # Don't use while: - else: for this condition because
1588
+ # if so, then parent is None and has no .path attribute.
1589
+ raise SCons.Errors.StopError(parent.path)
1590
+ parent = p
1591
+ listDirs.reverse()
1592
+ for dirnode in listDirs:
1593
+ try:
1594
+ # Don't call dirnode.build(), call the base Node method
1595
+ # directly because we definitely *must* create this
1596
+ # directory. The dirnode.build() method will suppress
1597
+ # the build if it's the default builder.
1598
+ SCons.Node.Node.build(dirnode)
1599
+ dirnode.get_executor().nullify()
1600
+ # The build() action may or may not have actually
1601
+ # created the directory, depending on whether the -n
1602
+ # option was used or not. Delete the _exists and
1603
+ # _rexists attributes so they can be reevaluated.
1604
+ dirnode.clear()
1605
+ except OSError:
1606
+ pass
1607
+
1608
+ def multiple_side_effect_has_builder(self):
1609
+ global MkdirBuilder
1610
+ return self.builder is not MkdirBuilder and self.has_builder()
1611
+
1612
+ def alter_targets(self):
1613
+ """Return any corresponding targets in a variant directory.
1614
+ """
1615
+ return self.fs.variant_dir_target_climb(self, self, [])
1616
+
1617
+ def scanner_key(self):
1618
+ """A directory does not get scanned."""
1619
+ return None
1620
+
1621
+ def get_text_contents(self):
1622
+ """We already emit things in text, so just return the binary
1623
+ version."""
1624
+ return self.get_contents()
1625
+
1626
+ def get_contents(self):
1627
+ """Return content signatures and names of all our children
1628
+ separated by new-lines. Ensure that the nodes are sorted."""
1629
+ contents = []
1630
+ for node in sorted(self.children(), key=lambda t: t.name):
1631
+ contents.append('%s %s\n' % (node.get_csig(), node.name))
1632
+ return ''.join(contents)
1633
+
1634
+ def get_csig(self):
1635
+ """Compute the content signature for Directory nodes. In
1636
+ general, this is not needed and the content signature is not
1637
+ stored in the DirNodeInfo. However, if get_contents on a Dir
1638
+ node is called which has a child directory, the child
1639
+ directory should return the hash of its contents."""
1640
+ contents = self.get_contents()
1641
+ return SCons.Util.MD5signature(contents)
1642
+
1643
+ def do_duplicate(self, src):
1644
+ pass
1645
+
1646
+ changed_since_last_build = SCons.Node.Node.state_has_changed
1647
+
1648
+ def is_up_to_date(self):
1649
+ """If any child is not up-to-date, then this directory isn't,
1650
+ either."""
1651
+ if self.builder is not MkdirBuilder and not self.exists():
1652
+ return 0
1653
+ up_to_date = SCons.Node.up_to_date
1654
+ for kid in self.children():
1655
+ if kid.get_state() > up_to_date:
1656
+ return 0
1657
+ return 1
1658
+
1659
+ def rdir(self):
1660
+ if not self.exists():
1661
+ norm_name = _my_normcase(self.name)
1662
+ for dir in self.dir.get_all_rdirs():
1663
+ try: node = dir.entries[norm_name]
1664
+ except KeyError: node = dir.dir_on_disk(self.name)
1665
+ if node and node.exists() and \
1666
+ (isinstance(dir, Dir) or isinstance(dir, Entry)):
1667
+ return node
1668
+ return self
1669
+
1670
+ def sconsign(self):
1671
+ """Return the .sconsign file info for this directory,
1672
+ creating it first if necessary."""
1673
+ if not self._sconsign:
1674
+ import SCons.SConsign
1675
+ self._sconsign = SCons.SConsign.ForDirectory(self)
1676
+ return self._sconsign
1677
+
1678
+ def srcnode(self):
1679
+ """Dir has a special need for srcnode()...if we
1680
+ have a srcdir attribute set, then that *is* our srcnode."""
1681
+ if self.srcdir:
1682
+ return self.srcdir
1683
+ return Base.srcnode(self)
1684
+
1685
+ def get_timestamp(self):
1686
+ """Return the latest timestamp from among our children"""
1687
+ stamp = 0
1688
+ for kid in self.children():
1689
+ if kid.get_timestamp() > stamp:
1690
+ stamp = kid.get_timestamp()
1691
+ return stamp
1692
+
1693
+ def entry_abspath(self, name):
1694
+ return self.abspath + os.sep + name
1695
+
1696
+ def entry_labspath(self, name):
1697
+ return self.labspath + '/' + name
1698
+
1699
+ def entry_path(self, name):
1700
+ return self.path + os.sep + name
1701
+
1702
+ def entry_tpath(self, name):
1703
+ return self.tpath + os.sep + name
1704
+
1705
+ def entry_exists_on_disk(self, name):
1706
+ try:
1707
+ d = self.on_disk_entries
1708
+ except AttributeError:
1709
+ d = {}
1710
+ try:
1711
+ entries = os.listdir(self.abspath)
1712
+ except OSError:
1713
+ pass
1714
+ else:
1715
+ for entry in map(_my_normcase, entries):
1716
+ d[entry] = True
1717
+ self.on_disk_entries = d
1718
+ if sys.platform == 'win32':
1719
+ name = _my_normcase(name)
1720
+ result = d.get(name)
1721
+ if result is None:
1722
+ # Belt-and-suspenders for Windows: check directly for
1723
+ # 8.3 file names that don't show up in os.listdir().
1724
+ result = os.path.exists(self.abspath + os.sep + name)
1725
+ d[name] = result
1726
+ return result
1727
+ else:
1728
+ return name in d
1729
+
1730
+ memoizer_counters.append(SCons.Memoize.CountValue('srcdir_list'))
1731
+
1732
+ def srcdir_list(self):
1733
+ try:
1734
+ return self._memo['srcdir_list']
1735
+ except KeyError:
1736
+ pass
1737
+
1738
+ result = []
1739
+
1740
+ dirname = '.'
1741
+ dir = self
1742
+ while dir:
1743
+ if dir.srcdir:
1744
+ result.append(dir.srcdir.Dir(dirname))
1745
+ dirname = dir.name + os.sep + dirname
1746
+ dir = dir.up()
1747
+
1748
+ self._memo['srcdir_list'] = result
1749
+
1750
+ return result
1751
+
1752
+ def srcdir_duplicate(self, name):
1753
+ for dir in self.srcdir_list():
1754
+ if self.is_under(dir):
1755
+ # We shouldn't source from something in the build path;
1756
+ # variant_dir is probably under src_dir, in which case
1757
+ # we are reflecting.
1758
+ break
1759
+ if dir.entry_exists_on_disk(name):
1760
+ srcnode = dir.Entry(name).disambiguate()
1761
+ if self.duplicate:
1762
+ node = self.Entry(name).disambiguate()
1763
+ node.do_duplicate(srcnode)
1764
+ return node
1765
+ else:
1766
+ return srcnode
1767
+ return None
1768
+
1769
+ def _srcdir_find_file_key(self, filename):
1770
+ return filename
1771
+
1772
+ memoizer_counters.append(SCons.Memoize.CountDict('srcdir_find_file', _srcdir_find_file_key))
1773
+
1774
+ def srcdir_find_file(self, filename):
1775
+ try:
1776
+ memo_dict = self._memo['srcdir_find_file']
1777
+ except KeyError:
1778
+ memo_dict = {}
1779
+ self._memo['srcdir_find_file'] = memo_dict
1780
+ else:
1781
+ try:
1782
+ return memo_dict[filename]
1783
+ except KeyError:
1784
+ pass
1785
+
1786
+ def func(node):
1787
+ if (isinstance(node, File) or isinstance(node, Entry)) and \
1788
+ (node.is_derived() or node.exists()):
1789
+ return node
1790
+ return None
1791
+
1792
+ norm_name = _my_normcase(filename)
1793
+
1794
+ for rdir in self.get_all_rdirs():
1795
+ try: node = rdir.entries[norm_name]
1796
+ except KeyError: node = rdir.file_on_disk(filename)
1797
+ else: node = func(node)
1798
+ if node:
1799
+ result = (node, self)
1800
+ memo_dict[filename] = result
1801
+ return result
1802
+
1803
+ for srcdir in self.srcdir_list():
1804
+ for rdir in srcdir.get_all_rdirs():
1805
+ try: node = rdir.entries[norm_name]
1806
+ except KeyError: node = rdir.file_on_disk(filename)
1807
+ else: node = func(node)
1808
+ if node:
1809
+ result = (File(filename, self, self.fs), srcdir)
1810
+ memo_dict[filename] = result
1811
+ return result
1812
+
1813
+ result = (None, None)
1814
+ memo_dict[filename] = result
1815
+ return result
1816
+
1817
+ def dir_on_disk(self, name):
1818
+ if self.entry_exists_on_disk(name):
1819
+ try: return self.Dir(name)
1820
+ except TypeError: pass
1821
+ node = self.srcdir_duplicate(name)
1822
+ if isinstance(node, File):
1823
+ return None
1824
+ return node
1825
+
1826
+ def file_on_disk(self, name):
1827
+ if self.entry_exists_on_disk(name) or \
1828
+ diskcheck_rcs(self, name) or \
1829
+ diskcheck_sccs(self, name):
1830
+ try: return self.File(name)
1831
+ except TypeError: pass
1832
+ node = self.srcdir_duplicate(name)
1833
+ if isinstance(node, Dir):
1834
+ return None
1835
+ return node
1836
+
1837
+ def walk(self, func, arg):
1838
+ """
1839
+ Walk this directory tree by calling the specified function
1840
+ for each directory in the tree.
1841
+
1842
+ This behaves like the os.path.walk() function, but for in-memory
1843
+ Node.FS.Dir objects. The function takes the same arguments as
1844
+ the functions passed to os.path.walk():
1845
+
1846
+ func(arg, dirname, fnames)
1847
+
1848
+ Except that "dirname" will actually be the directory *Node*,
1849
+ not the string. The '.' and '..' entries are excluded from
1850
+ fnames. The fnames list may be modified in-place to filter the
1851
+ subdirectories visited or otherwise impose a specific order.
1852
+ The "arg" argument is always passed to func() and may be used
1853
+ in any way (or ignored, passing None is common).
1854
+ """
1855
+ entries = self.entries
1856
+ names = list(entries.keys())
1857
+ names.remove('.')
1858
+ names.remove('..')
1859
+ func(arg, self, names)
1860
+ for dirname in [n for n in names if isinstance(entries[n], Dir)]:
1861
+ entries[dirname].walk(func, arg)
1862
+
1863
+ def glob(self, pathname, ondisk=True, source=False, strings=False):
1864
+ """
1865
+ Returns a list of Nodes (or strings) matching a specified
1866
+ pathname pattern.
1867
+
1868
+ Pathname patterns follow UNIX shell semantics: * matches
1869
+ any-length strings of any characters, ? matches any character,
1870
+ and [] can enclose lists or ranges of characters. Matches do
1871
+ not span directory separators.
1872
+
1873
+ The matches take into account Repositories, returning local
1874
+ Nodes if a corresponding entry exists in a Repository (either
1875
+ an in-memory Node or something on disk).
1876
+
1877
+ By defafult, the glob() function matches entries that exist
1878
+ on-disk, in addition to in-memory Nodes. Setting the "ondisk"
1879
+ argument to False (or some other non-true value) causes the glob()
1880
+ function to only match in-memory Nodes. The default behavior is
1881
+ to return both the on-disk and in-memory Nodes.
1882
+
1883
+ The "source" argument, when true, specifies that corresponding
1884
+ source Nodes must be returned if you're globbing in a build
1885
+ directory (initialized with VariantDir()). The default behavior
1886
+ is to return Nodes local to the VariantDir().
1887
+
1888
+ The "strings" argument, when true, returns the matches as strings,
1889
+ not Nodes. The strings are path names relative to this directory.
1890
+
1891
+ The underlying algorithm is adapted from the glob.glob() function
1892
+ in the Python library (but heavily modified), and uses fnmatch()
1893
+ under the covers.
1894
+ """
1895
+ dirname, basename = os.path.split(pathname)
1896
+ if not dirname:
1897
+ return sorted(self._glob1(basename, ondisk, source, strings),
1898
+ key=lambda t: str(t))
1899
+ if has_glob_magic(dirname):
1900
+ list = self.glob(dirname, ondisk, source, strings=False)
1901
+ else:
1902
+ list = [self.Dir(dirname, create=True)]
1903
+ result = []
1904
+ for dir in list:
1905
+ r = dir._glob1(basename, ondisk, source, strings)
1906
+ if strings:
1907
+ r = [os.path.join(str(dir), x) for x in r]
1908
+ result.extend(r)
1909
+ return sorted(result, key=lambda a: str(a))
1910
+
1911
+ def _glob1(self, pattern, ondisk=True, source=False, strings=False):
1912
+ """
1913
+ Globs for and returns a list of entry names matching a single
1914
+ pattern in this directory.
1915
+
1916
+ This searches any repositories and source directories for
1917
+ corresponding entries and returns a Node (or string) relative
1918
+ to the current directory if an entry is found anywhere.
1919
+
1920
+ TODO: handle pattern with no wildcard
1921
+ """
1922
+ search_dir_list = self.get_all_rdirs()
1923
+ for srcdir in self.srcdir_list():
1924
+ search_dir_list.extend(srcdir.get_all_rdirs())
1925
+
1926
+ selfEntry = self.Entry
1927
+ names = []
1928
+ for dir in search_dir_list:
1929
+ # We use the .name attribute from the Node because the keys of
1930
+ # the dir.entries dictionary are normalized (that is, all upper
1931
+ # case) on case-insensitive systems like Windows.
1932
+ node_names = [ v.name for k, v in dir.entries.items()
1933
+ if k not in ('.', '..') ]
1934
+ names.extend(node_names)
1935
+ if not strings:
1936
+ # Make sure the working directory (self) actually has
1937
+ # entries for all Nodes in repositories or variant dirs.
1938
+ for name in node_names: selfEntry(name)
1939
+ if ondisk:
1940
+ try:
1941
+ disk_names = os.listdir(dir.abspath)
1942
+ except os.error:
1943
+ continue
1944
+ names.extend(disk_names)
1945
+ if not strings:
1946
+ # We're going to return corresponding Nodes in
1947
+ # the local directory, so we need to make sure
1948
+ # those Nodes exist. We only want to create
1949
+ # Nodes for the entries that will match the
1950
+ # specified pattern, though, which means we
1951
+ # need to filter the list here, even though
1952
+ # the overall list will also be filtered later,
1953
+ # after we exit this loop.
1954
+ if pattern[0] != '.':
1955
+ #disk_names = [ d for d in disk_names if d[0] != '.' ]
1956
+ disk_names = [x for x in disk_names if x[0] != '.']
1957
+ disk_names = fnmatch.filter(disk_names, pattern)
1958
+ dirEntry = dir.Entry
1959
+ for name in disk_names:
1960
+ # Add './' before disk filename so that '#' at
1961
+ # beginning of filename isn't interpreted.
1962
+ name = './' + name
1963
+ node = dirEntry(name).disambiguate()
1964
+ n = selfEntry(name)
1965
+ if n.__class__ != node.__class__:
1966
+ n.__class__ = node.__class__
1967
+ n._morph()
1968
+
1969
+ names = set(names)
1970
+ if pattern[0] != '.':
1971
+ #names = [ n for n in names if n[0] != '.' ]
1972
+ names = [x for x in names if x[0] != '.']
1973
+ names = fnmatch.filter(names, pattern)
1974
+
1975
+ if strings:
1976
+ return names
1977
+
1978
+ #return [ self.entries[_my_normcase(n)] for n in names ]
1979
+ return [self.entries[_my_normcase(n)] for n in names]
1980
+
1981
+ class RootDir(Dir):
1982
+ """A class for the root directory of a file system.
1983
+
1984
+ This is the same as a Dir class, except that the path separator
1985
+ ('/' or '\\') is actually part of the name, so we don't need to
1986
+ add a separator when creating the path names of entries within
1987
+ this directory.
1988
+ """
1989
+ def __init__(self, name, fs):
1990
+ if __debug__: logInstanceCreation(self, 'Node.FS.RootDir')
1991
+ # We're going to be our own parent directory (".." entry and .dir
1992
+ # attribute) so we have to set up some values so Base.__init__()
1993
+ # won't gag won't it calls some of our methods.
1994
+ self.abspath = ''
1995
+ self.labspath = ''
1996
+ self.path = ''
1997
+ self.tpath = ''
1998
+ self.path_elements = []
1999
+ self.duplicate = 0
2000
+ self.root = self
2001
+ Base.__init__(self, name, self, fs)
2002
+
2003
+ # Now set our paths to what we really want them to be: the
2004
+ # initial drive letter (the name) plus the directory separator,
2005
+ # except for the "lookup abspath," which does not have the
2006
+ # drive letter.
2007
+ self.abspath = name + os.sep
2008
+ self.labspath = ''
2009
+ self.path = name + os.sep
2010
+ self.tpath = name + os.sep
2011
+ self._morph()
2012
+
2013
+ self._lookupDict = {}
2014
+
2015
+ # The // and os.sep + os.sep entries are necessary because
2016
+ # os.path.normpath() seems to preserve double slashes at the
2017
+ # beginning of a path (presumably for UNC path names), but
2018
+ # collapses triple slashes to a single slash.
2019
+ self._lookupDict[''] = self
2020
+ self._lookupDict['/'] = self
2021
+ self._lookupDict['//'] = self
2022
+ self._lookupDict[os.sep] = self
2023
+ self._lookupDict[os.sep + os.sep] = self
2024
+
2025
+ def must_be_same(self, klass):
2026
+ if klass is Dir:
2027
+ return
2028
+ Base.must_be_same(self, klass)
2029
+
2030
+ def _lookup_abs(self, p, klass, create=1):
2031
+ """
2032
+ Fast (?) lookup of a *normalized* absolute path.
2033
+
2034
+ This method is intended for use by internal lookups with
2035
+ already-normalized path data. For general-purpose lookups,
2036
+ use the FS.Entry(), FS.Dir() or FS.File() methods.
2037
+
2038
+ The caller is responsible for making sure we're passed a
2039
+ normalized absolute path; we merely let Python's dictionary look
2040
+ up and return the One True Node.FS object for the path.
2041
+
2042
+ If no Node for the specified "p" doesn't already exist, and
2043
+ "create" is specified, the Node may be created after recursive
2044
+ invocation to find or create the parent directory or directories.
2045
+ """
2046
+ k = _my_normcase(p)
2047
+ try:
2048
+ result = self._lookupDict[k]
2049
+ except KeyError:
2050
+ if not create:
2051
+ msg = "No such file or directory: '%s' in '%s' (and create is False)" % (p, str(self))
2052
+ raise SCons.Errors.UserError(msg)
2053
+ # There is no Node for this path name, and we're allowed
2054
+ # to create it.
2055
+ dir_name, file_name = os.path.split(p)
2056
+ dir_node = self._lookup_abs(dir_name, Dir)
2057
+ result = klass(file_name, dir_node, self.fs)
2058
+
2059
+ # Double-check on disk (as configured) that the Node we
2060
+ # created matches whatever is out there in the real world.
2061
+ result.diskcheck_match()
2062
+
2063
+ self._lookupDict[k] = result
2064
+ dir_node.entries[_my_normcase(file_name)] = result
2065
+ dir_node.implicit = None
2066
+ else:
2067
+ # There is already a Node for this path name. Allow it to
2068
+ # complain if we were looking for an inappropriate type.
2069
+ result.must_be_same(klass)
2070
+ return result
2071
+
2072
+ def __str__(self):
2073
+ return self.abspath
2074
+
2075
+ def entry_abspath(self, name):
2076
+ return self.abspath + name
2077
+
2078
+ def entry_labspath(self, name):
2079
+ return '/' + name
2080
+
2081
+ def entry_path(self, name):
2082
+ return self.path + name
2083
+
2084
+ def entry_tpath(self, name):
2085
+ return self.tpath + name
2086
+
2087
+ def is_under(self, dir):
2088
+ if self is dir:
2089
+ return 1
2090
+ else:
2091
+ return 0
2092
+
2093
+ def up(self):
2094
+ return None
2095
+
2096
+ def get_dir(self):
2097
+ return None
2098
+
2099
+ def src_builder(self):
2100
+ return _null
2101
+
2102
+ class FileNodeInfo(SCons.Node.NodeInfoBase):
2103
+ current_version_id = 1
2104
+
2105
+ field_list = ['csig', 'timestamp', 'size']
2106
+
2107
+ # This should get reset by the FS initialization.
2108
+ fs = None
2109
+
2110
+ def str_to_node(self, s):
2111
+ top = self.fs.Top
2112
+ root = top.root
2113
+ if do_splitdrive:
2114
+ drive, s = os.path.splitdrive(s)
2115
+ if drive:
2116
+ root = self.fs.get_root(drive)
2117
+ if not os.path.isabs(s):
2118
+ s = top.labspath + '/' + s
2119
+ return root._lookup_abs(s, Entry)
2120
+
2121
+ class FileBuildInfo(SCons.Node.BuildInfoBase):
2122
+ current_version_id = 1
2123
+
2124
+ def convert_to_sconsign(self):
2125
+ """
2126
+ Converts this FileBuildInfo object for writing to a .sconsign file
2127
+
2128
+ This replaces each Node in our various dependency lists with its
2129
+ usual string representation: relative to the top-level SConstruct
2130
+ directory, or an absolute path if it's outside.
2131
+ """
2132
+ if os.sep == '/':
2133
+ node_to_str = str
2134
+ else:
2135
+ def node_to_str(n):
2136
+ try:
2137
+ s = n.path
2138
+ except AttributeError:
2139
+ s = str(n)
2140
+ else:
2141
+ s = s.replace(os.sep, '/')
2142
+ return s
2143
+ for attr in ['bsources', 'bdepends', 'bimplicit']:
2144
+ try:
2145
+ val = getattr(self, attr)
2146
+ except AttributeError:
2147
+ pass
2148
+ else:
2149
+ setattr(self, attr, list(map(node_to_str, val)))
2150
+ def convert_from_sconsign(self, dir, name):
2151
+ """
2152
+ Converts a newly-read FileBuildInfo object for in-SCons use
2153
+
2154
+ For normal up-to-date checking, we don't have any conversion to
2155
+ perform--but we're leaving this method here to make that clear.
2156
+ """
2157
+ pass
2158
+ def prepare_dependencies(self):
2159
+ """
2160
+ Prepares a FileBuildInfo object for explaining what changed
2161
+
2162
+ The bsources, bdepends and bimplicit lists have all been
2163
+ stored on disk as paths relative to the top-level SConstruct
2164
+ directory. Convert the strings to actual Nodes (for use by the
2165
+ --debug=explain code and --implicit-cache).
2166
+ """
2167
+ attrs = [
2168
+ ('bsources', 'bsourcesigs'),
2169
+ ('bdepends', 'bdependsigs'),
2170
+ ('bimplicit', 'bimplicitsigs'),
2171
+ ]
2172
+ for (nattr, sattr) in attrs:
2173
+ try:
2174
+ strings = getattr(self, nattr)
2175
+ nodeinfos = getattr(self, sattr)
2176
+ except AttributeError:
2177
+ continue
2178
+ nodes = []
2179
+ for s, ni in zip(strings, nodeinfos):
2180
+ if not isinstance(s, SCons.Node.Node):
2181
+ s = ni.str_to_node(s)
2182
+ nodes.append(s)
2183
+ setattr(self, nattr, nodes)
2184
+ def format(self, names=0):
2185
+ result = []
2186
+ bkids = self.bsources + self.bdepends + self.bimplicit
2187
+ bkidsigs = self.bsourcesigs + self.bdependsigs + self.bimplicitsigs
2188
+ for bkid, bkidsig in zip(bkids, bkidsigs):
2189
+ result.append(str(bkid) + ': ' +
2190
+ ' '.join(bkidsig.format(names=names)))
2191
+ result.append('%s [%s]' % (self.bactsig, self.bact))
2192
+ return '\n'.join(result)
2193
+
2194
+ class File(Base):
2195
+ """A class for files in a file system.
2196
+ """
2197
+
2198
+ memoizer_counters = []
2199
+
2200
+ NodeInfo = FileNodeInfo
2201
+ BuildInfo = FileBuildInfo
2202
+
2203
+ md5_chunksize = 64
2204
+
2205
+ def diskcheck_match(self):
2206
+ diskcheck_match(self, self.isdir,
2207
+ "Directory %s found where file expected.")
2208
+
2209
+ def __init__(self, name, directory, fs):
2210
+ if __debug__: logInstanceCreation(self, 'Node.FS.File')
2211
+ Base.__init__(self, name, directory, fs)
2212
+ self._morph()
2213
+
2214
+ def Entry(self, name):
2215
+ """Create an entry node named 'name' relative to
2216
+ the directory of this file."""
2217
+ return self.dir.Entry(name)
2218
+
2219
+ def Dir(self, name, create=True):
2220
+ """Create a directory node named 'name' relative to
2221
+ the directory of this file."""
2222
+ return self.dir.Dir(name, create=create)
2223
+
2224
+ def Dirs(self, pathlist):
2225
+ """Create a list of directories relative to the SConscript
2226
+ directory of this file."""
2227
+ return [self.Dir(p) for p in pathlist]
2228
+
2229
+ def File(self, name):
2230
+ """Create a file node named 'name' relative to
2231
+ the directory of this file."""
2232
+ return self.dir.File(name)
2233
+
2234
+ #def generate_build_dict(self):
2235
+ # """Return an appropriate dictionary of values for building
2236
+ # this File."""
2237
+ # return {'Dir' : self.Dir,
2238
+ # 'File' : self.File,
2239
+ # 'RDirs' : self.RDirs}
2240
+
2241
+ def _morph(self):
2242
+ """Turn a file system node into a File object."""
2243
+ self.scanner_paths = {}
2244
+ if not hasattr(self, '_local'):
2245
+ self._local = 0
2246
+
2247
+ # If there was already a Builder set on this entry, then
2248
+ # we need to make sure we call the target-decider function,
2249
+ # not the source-decider. Reaching in and doing this by hand
2250
+ # is a little bogus. We'd prefer to handle this by adding
2251
+ # an Entry.builder_set() method that disambiguates like the
2252
+ # other methods, but that starts running into problems with the
2253
+ # fragile way we initialize Dir Nodes with their Mkdir builders,
2254
+ # yet still allow them to be overridden by the user. Since it's
2255
+ # not clear right now how to fix that, stick with what works
2256
+ # until it becomes clear...
2257
+ if self.has_builder():
2258
+ self.changed_since_last_build = self.decide_target
2259
+
2260
+ def scanner_key(self):
2261
+ return self.get_suffix()
2262
+
2263
+ def get_contents(self):
2264
+ if not self.rexists():
2265
+ return ''
2266
+ fname = self.rfile().abspath
2267
+ try:
2268
+ contents = open(fname, "rb").read()
2269
+ except EnvironmentError, e:
2270
+ if not e.filename:
2271
+ e.filename = fname
2272
+ raise
2273
+ return contents
2274
+
2275
+ # This attempts to figure out what the encoding of the text is
2276
+ # based upon the BOM bytes, and then decodes the contents so that
2277
+ # it's a valid python string.
2278
+ def get_text_contents(self):
2279
+ contents = self.get_contents()
2280
+ # The behavior of various decode() methods and functions
2281
+ # w.r.t. the initial BOM bytes is different for different
2282
+ # encodings and/or Python versions. ('utf-8' does not strip
2283
+ # them, but has a 'utf-8-sig' which does; 'utf-16' seems to
2284
+ # strip them; etc.) Just sidestep all the complication by
2285
+ # explicitly stripping the BOM before we decode().
2286
+ if contents.startswith(codecs.BOM_UTF8):
2287
+ return contents[len(codecs.BOM_UTF8):].decode('utf-8')
2288
+ if contents.startswith(codecs.BOM_UTF16_LE):
2289
+ return contents[len(codecs.BOM_UTF16_LE):].decode('utf-16-le')
2290
+ if contents.startswith(codecs.BOM_UTF16_BE):
2291
+ return contents[len(codecs.BOM_UTF16_BE):].decode('utf-16-be')
2292
+ return contents
2293
+
2294
+ def get_content_hash(self):
2295
+ """
2296
+ Compute and return the MD5 hash for this file.
2297
+ """
2298
+ if not self.rexists():
2299
+ return SCons.Util.MD5signature('')
2300
+ fname = self.rfile().abspath
2301
+ try:
2302
+ cs = SCons.Util.MD5filesignature(fname,
2303
+ chunksize=SCons.Node.FS.File.md5_chunksize*1024)
2304
+ except EnvironmentError, e:
2305
+ if not e.filename:
2306
+ e.filename = fname
2307
+ raise
2308
+ return cs
2309
+
2310
+
2311
+ memoizer_counters.append(SCons.Memoize.CountValue('get_size'))
2312
+
2313
+ def get_size(self):
2314
+ try:
2315
+ return self._memo['get_size']
2316
+ except KeyError:
2317
+ pass
2318
+
2319
+ if self.rexists():
2320
+ size = self.rfile().getsize()
2321
+ else:
2322
+ size = 0
2323
+
2324
+ self._memo['get_size'] = size
2325
+
2326
+ return size
2327
+
2328
+ memoizer_counters.append(SCons.Memoize.CountValue('get_timestamp'))
2329
+
2330
+ def get_timestamp(self):
2331
+ try:
2332
+ return self._memo['get_timestamp']
2333
+ except KeyError:
2334
+ pass
2335
+
2336
+ if self.rexists():
2337
+ timestamp = self.rfile().getmtime()
2338
+ else:
2339
+ timestamp = 0
2340
+
2341
+ self._memo['get_timestamp'] = timestamp
2342
+
2343
+ return timestamp
2344
+
2345
+ def store_info(self):
2346
+ # Merge our build information into the already-stored entry.
2347
+ # This accomodates "chained builds" where a file that's a target
2348
+ # in one build (SConstruct file) is a source in a different build.
2349
+ # See test/chained-build.py for the use case.
2350
+ if do_store_info:
2351
+ self.dir.sconsign().store_info(self.name, self)
2352
+
2353
+ convert_copy_attrs = [
2354
+ 'bsources',
2355
+ 'bimplicit',
2356
+ 'bdepends',
2357
+ 'bact',
2358
+ 'bactsig',
2359
+ 'ninfo',
2360
+ ]
2361
+
2362
+
2363
+ convert_sig_attrs = [
2364
+ 'bsourcesigs',
2365
+ 'bimplicitsigs',
2366
+ 'bdependsigs',
2367
+ ]
2368
+
2369
+ def convert_old_entry(self, old_entry):
2370
+ # Convert a .sconsign entry from before the Big Signature
2371
+ # Refactoring, doing what we can to convert its information
2372
+ # to the new .sconsign entry format.
2373
+ #
2374
+ # The old format looked essentially like this:
2375
+ #
2376
+ # BuildInfo
2377
+ # .ninfo (NodeInfo)
2378
+ # .bsig
2379
+ # .csig
2380
+ # .timestamp
2381
+ # .size
2382
+ # .bsources
2383
+ # .bsourcesigs ("signature" list)
2384
+ # .bdepends
2385
+ # .bdependsigs ("signature" list)
2386
+ # .bimplicit
2387
+ # .bimplicitsigs ("signature" list)
2388
+ # .bact
2389
+ # .bactsig
2390
+ #
2391
+ # The new format looks like this:
2392
+ #
2393
+ # .ninfo (NodeInfo)
2394
+ # .bsig
2395
+ # .csig
2396
+ # .timestamp
2397
+ # .size
2398
+ # .binfo (BuildInfo)
2399
+ # .bsources
2400
+ # .bsourcesigs (NodeInfo list)
2401
+ # .bsig
2402
+ # .csig
2403
+ # .timestamp
2404
+ # .size
2405
+ # .bdepends
2406
+ # .bdependsigs (NodeInfo list)
2407
+ # .bsig
2408
+ # .csig
2409
+ # .timestamp
2410
+ # .size
2411
+ # .bimplicit
2412
+ # .bimplicitsigs (NodeInfo list)
2413
+ # .bsig
2414
+ # .csig
2415
+ # .timestamp
2416
+ # .size
2417
+ # .bact
2418
+ # .bactsig
2419
+ #
2420
+ # The basic idea of the new structure is that a NodeInfo always
2421
+ # holds all available information about the state of a given Node
2422
+ # at a certain point in time. The various .b*sigs lists can just
2423
+ # be a list of pointers to the .ninfo attributes of the different
2424
+ # dependent nodes, without any copying of information until it's
2425
+ # time to pickle it for writing out to a .sconsign file.
2426
+ #
2427
+ # The complicating issue is that the *old* format only stored one
2428
+ # "signature" per dependency, based on however the *last* build
2429
+ # was configured. We don't know from just looking at it whether
2430
+ # it was a build signature, a content signature, or a timestamp
2431
+ # "signature". Since we no longer use build signatures, the
2432
+ # best we can do is look at the length and if it's thirty two,
2433
+ # assume that it was (or might have been) a content signature.
2434
+ # If it was actually a build signature, then it will cause a
2435
+ # rebuild anyway when it doesn't match the new content signature,
2436
+ # but that's probably the best we can do.
2437
+ import SCons.SConsign
2438
+ new_entry = SCons.SConsign.SConsignEntry()
2439
+ new_entry.binfo = self.new_binfo()
2440
+ binfo = new_entry.binfo
2441
+ for attr in self.convert_copy_attrs:
2442
+ try:
2443
+ value = getattr(old_entry, attr)
2444
+ except AttributeError:
2445
+ continue
2446
+ setattr(binfo, attr, value)
2447
+ delattr(old_entry, attr)
2448
+ for attr in self.convert_sig_attrs:
2449
+ try:
2450
+ sig_list = getattr(old_entry, attr)
2451
+ except AttributeError:
2452
+ continue
2453
+ value = []
2454
+ for sig in sig_list:
2455
+ ninfo = self.new_ninfo()
2456
+ if len(sig) == 32:
2457
+ ninfo.csig = sig
2458
+ else:
2459
+ ninfo.timestamp = sig
2460
+ value.append(ninfo)
2461
+ setattr(binfo, attr, value)
2462
+ delattr(old_entry, attr)
2463
+ return new_entry
2464
+
2465
+ memoizer_counters.append(SCons.Memoize.CountValue('get_stored_info'))
2466
+
2467
+ def get_stored_info(self):
2468
+ try:
2469
+ return self._memo['get_stored_info']
2470
+ except KeyError:
2471
+ pass
2472
+
2473
+ try:
2474
+ sconsign_entry = self.dir.sconsign().get_entry(self.name)
2475
+ except (KeyError, EnvironmentError):
2476
+ import SCons.SConsign
2477
+ sconsign_entry = SCons.SConsign.SConsignEntry()
2478
+ sconsign_entry.binfo = self.new_binfo()
2479
+ sconsign_entry.ninfo = self.new_ninfo()
2480
+ else:
2481
+ if isinstance(sconsign_entry, FileBuildInfo):
2482
+ # This is a .sconsign file from before the Big Signature
2483
+ # Refactoring; convert it as best we can.
2484
+ sconsign_entry = self.convert_old_entry(sconsign_entry)
2485
+ try:
2486
+ delattr(sconsign_entry.ninfo, 'bsig')
2487
+ except AttributeError:
2488
+ pass
2489
+
2490
+ self._memo['get_stored_info'] = sconsign_entry
2491
+
2492
+ return sconsign_entry
2493
+
2494
+ def get_stored_implicit(self):
2495
+ binfo = self.get_stored_info().binfo
2496
+ binfo.prepare_dependencies()
2497
+ try: return binfo.bimplicit
2498
+ except AttributeError: return None
2499
+
2500
+ def rel_path(self, other):
2501
+ return self.dir.rel_path(other)
2502
+
2503
+ def _get_found_includes_key(self, env, scanner, path):
2504
+ return (id(env), id(scanner), path)
2505
+
2506
+ memoizer_counters.append(SCons.Memoize.CountDict('get_found_includes', _get_found_includes_key))
2507
+
2508
+ def get_found_includes(self, env, scanner, path):
2509
+ """Return the included implicit dependencies in this file.
2510
+ Cache results so we only scan the file once per path
2511
+ regardless of how many times this information is requested.
2512
+ """
2513
+ memo_key = (id(env), id(scanner), path)
2514
+ try:
2515
+ memo_dict = self._memo['get_found_includes']
2516
+ except KeyError:
2517
+ memo_dict = {}
2518
+ self._memo['get_found_includes'] = memo_dict
2519
+ else:
2520
+ try:
2521
+ return memo_dict[memo_key]
2522
+ except KeyError:
2523
+ pass
2524
+
2525
+ if scanner:
2526
+ # result = [n.disambiguate() for n in scanner(self, env, path)]
2527
+ result = scanner(self, env, path)
2528
+ result = [N.disambiguate() for N in result]
2529
+ else:
2530
+ result = []
2531
+
2532
+ memo_dict[memo_key] = result
2533
+
2534
+ return result
2535
+
2536
+ def _createDir(self):
2537
+ # ensure that the directories for this node are
2538
+ # created.
2539
+ self.dir._create()
2540
+
2541
+ def push_to_cache(self):
2542
+ """Try to push the node into a cache
2543
+ """
2544
+ # This should get called before the Nodes' .built() method is
2545
+ # called, which would clear the build signature if the file has
2546
+ # a source scanner.
2547
+ #
2548
+ # We have to clear the local memoized values *before* we push
2549
+ # the node to cache so that the memoization of the self.exists()
2550
+ # return value doesn't interfere.
2551
+ if self.nocache:
2552
+ return
2553
+ self.clear_memoized_values()
2554
+ if self.exists():
2555
+ self.get_build_env().get_CacheDir().push(self)
2556
+
2557
+ def retrieve_from_cache(self):
2558
+ """Try to retrieve the node's content from a cache
2559
+
2560
+ This method is called from multiple threads in a parallel build,
2561
+ so only do thread safe stuff here. Do thread unsafe stuff in
2562
+ built().
2563
+
2564
+ Returns true iff the node was successfully retrieved.
2565
+ """
2566
+ if self.nocache:
2567
+ return None
2568
+ if not self.is_derived():
2569
+ return None
2570
+ return self.get_build_env().get_CacheDir().retrieve(self)
2571
+
2572
+ def visited(self):
2573
+ if self.exists():
2574
+ self.get_build_env().get_CacheDir().push_if_forced(self)
2575
+
2576
+ ninfo = self.get_ninfo()
2577
+
2578
+ csig = self.get_max_drift_csig()
2579
+ if csig:
2580
+ ninfo.csig = csig
2581
+
2582
+ ninfo.timestamp = self.get_timestamp()
2583
+ ninfo.size = self.get_size()
2584
+
2585
+ if not self.has_builder():
2586
+ # This is a source file, but it might have been a target file
2587
+ # in another build that included more of the DAG. Copy
2588
+ # any build information that's stored in the .sconsign file
2589
+ # into our binfo object so it doesn't get lost.
2590
+ old = self.get_stored_info()
2591
+ self.get_binfo().__dict__.update(old.binfo.__dict__)
2592
+
2593
+ self.store_info()
2594
+
2595
+ def find_src_builder(self):
2596
+ if self.rexists():
2597
+ return None
2598
+ scb = self.dir.src_builder()
2599
+ if scb is _null:
2600
+ if diskcheck_sccs(self.dir, self.name):
2601
+ scb = get_DefaultSCCSBuilder()
2602
+ elif diskcheck_rcs(self.dir, self.name):
2603
+ scb = get_DefaultRCSBuilder()
2604
+ else:
2605
+ scb = None
2606
+ if scb is not None:
2607
+ try:
2608
+ b = self.builder
2609
+ except AttributeError:
2610
+ b = None
2611
+ if b is None:
2612
+ self.builder_set(scb)
2613
+ return scb
2614
+
2615
+ def has_src_builder(self):
2616
+ """Return whether this Node has a source builder or not.
2617
+
2618
+ If this Node doesn't have an explicit source code builder, this
2619
+ is where we figure out, on the fly, if there's a transparent
2620
+ source code builder for it.
2621
+
2622
+ Note that if we found a source builder, we also set the
2623
+ self.builder attribute, so that all of the methods that actually
2624
+ *build* this file don't have to do anything different.
2625
+ """
2626
+ try:
2627
+ scb = self.sbuilder
2628
+ except AttributeError:
2629
+ scb = self.sbuilder = self.find_src_builder()
2630
+ return scb is not None
2631
+
2632
+ def alter_targets(self):
2633
+ """Return any corresponding targets in a variant directory.
2634
+ """
2635
+ if self.is_derived():
2636
+ return [], None
2637
+ return self.fs.variant_dir_target_climb(self, self.dir, [self.name])
2638
+
2639
+ def _rmv_existing(self):
2640
+ self.clear_memoized_values()
2641
+ e = Unlink(self, [], None)
2642
+ if isinstance(e, SCons.Errors.BuildError):
2643
+ raise e
2644
+
2645
+ #
2646
+ # Taskmaster interface subsystem
2647
+ #
2648
+
2649
+ def make_ready(self):
2650
+ self.has_src_builder()
2651
+ self.get_binfo()
2652
+
2653
+ def prepare(self):
2654
+ """Prepare for this file to be created."""
2655
+ SCons.Node.Node.prepare(self)
2656
+
2657
+ if self.get_state() != SCons.Node.up_to_date:
2658
+ if self.exists():
2659
+ if self.is_derived() and not self.precious:
2660
+ self._rmv_existing()
2661
+ else:
2662
+ try:
2663
+ self._createDir()
2664
+ except SCons.Errors.StopError, drive:
2665
+ desc = "No drive `%s' for target `%s'." % (drive, self)
2666
+ raise SCons.Errors.StopError(desc)
2667
+
2668
+ #
2669
+ #
2670
+ #
2671
+
2672
+ def remove(self):
2673
+ """Remove this file."""
2674
+ if self.exists() or self.islink():
2675
+ self.fs.unlink(self.path)
2676
+ return 1
2677
+ return None
2678
+
2679
+ def do_duplicate(self, src):
2680
+ self._createDir()
2681
+ Unlink(self, None, None)
2682
+ e = Link(self, src, None)
2683
+ if isinstance(e, SCons.Errors.BuildError):
2684
+ desc = "Cannot duplicate `%s' in `%s': %s." % (src.path, self.dir.path, e.errstr)
2685
+ raise SCons.Errors.StopError(desc)
2686
+ self.linked = 1
2687
+ # The Link() action may or may not have actually
2688
+ # created the file, depending on whether the -n
2689
+ # option was used or not. Delete the _exists and
2690
+ # _rexists attributes so they can be reevaluated.
2691
+ self.clear()
2692
+
2693
+ memoizer_counters.append(SCons.Memoize.CountValue('exists'))
2694
+
2695
+ def exists(self):
2696
+ try:
2697
+ return self._memo['exists']
2698
+ except KeyError:
2699
+ pass
2700
+ # Duplicate from source path if we are set up to do this.
2701
+ if self.duplicate and not self.is_derived() and not self.linked:
2702
+ src = self.srcnode()
2703
+ if src is not self:
2704
+ # At this point, src is meant to be copied in a variant directory.
2705
+ src = src.rfile()
2706
+ if src.abspath != self.abspath:
2707
+ if src.exists():
2708
+ self.do_duplicate(src)
2709
+ # Can't return 1 here because the duplication might
2710
+ # not actually occur if the -n option is being used.
2711
+ else:
2712
+ # The source file does not exist. Make sure no old
2713
+ # copy remains in the variant directory.
2714
+ if Base.exists(self) or self.islink():
2715
+ self.fs.unlink(self.path)
2716
+ # Return None explicitly because the Base.exists() call
2717
+ # above will have cached its value if the file existed.
2718
+ self._memo['exists'] = None
2719
+ return None
2720
+ result = Base.exists(self)
2721
+ self._memo['exists'] = result
2722
+ return result
2723
+
2724
+ #
2725
+ # SIGNATURE SUBSYSTEM
2726
+ #
2727
+
2728
+ def get_max_drift_csig(self):
2729
+ """
2730
+ Returns the content signature currently stored for this node
2731
+ if it's been unmodified longer than the max_drift value, or the
2732
+ max_drift value is 0. Returns None otherwise.
2733
+ """
2734
+ old = self.get_stored_info()
2735
+ mtime = self.get_timestamp()
2736
+
2737
+ max_drift = self.fs.max_drift
2738
+ if max_drift > 0:
2739
+ if (time.time() - mtime) > max_drift:
2740
+ try:
2741
+ n = old.ninfo
2742
+ if n.timestamp and n.csig and n.timestamp == mtime:
2743
+ return n.csig
2744
+ except AttributeError:
2745
+ pass
2746
+ elif max_drift == 0:
2747
+ try:
2748
+ return old.ninfo.csig
2749
+ except AttributeError:
2750
+ pass
2751
+
2752
+ return None
2753
+
2754
+ def get_csig(self):
2755
+ """
2756
+ Generate a node's content signature, the digested signature
2757
+ of its content.
2758
+
2759
+ node - the node
2760
+ cache - alternate node to use for the signature cache
2761
+ returns - the content signature
2762
+ """
2763
+ ninfo = self.get_ninfo()
2764
+ try:
2765
+ return ninfo.csig
2766
+ except AttributeError:
2767
+ pass
2768
+
2769
+ csig = self.get_max_drift_csig()
2770
+ if csig is None:
2771
+
2772
+ try:
2773
+ if self.get_size() < SCons.Node.FS.File.md5_chunksize:
2774
+ contents = self.get_contents()
2775
+ else:
2776
+ csig = self.get_content_hash()
2777
+ except IOError:
2778
+ # This can happen if there's actually a directory on-disk,
2779
+ # which can be the case if they've disabled disk checks,
2780
+ # or if an action with a File target actually happens to
2781
+ # create a same-named directory by mistake.
2782
+ csig = ''
2783
+ else:
2784
+ if not csig:
2785
+ csig = SCons.Util.MD5signature(contents)
2786
+
2787
+ ninfo.csig = csig
2788
+
2789
+ return csig
2790
+
2791
+ #
2792
+ # DECISION SUBSYSTEM
2793
+ #
2794
+
2795
+ def builder_set(self, builder):
2796
+ SCons.Node.Node.builder_set(self, builder)
2797
+ self.changed_since_last_build = self.decide_target
2798
+
2799
+ def changed_content(self, target, prev_ni):
2800
+ cur_csig = self.get_csig()
2801
+ try:
2802
+ return cur_csig != prev_ni.csig
2803
+ except AttributeError:
2804
+ return 1
2805
+
2806
+ def changed_state(self, target, prev_ni):
2807
+ return self.state != SCons.Node.up_to_date
2808
+
2809
+ def changed_timestamp_then_content(self, target, prev_ni):
2810
+ if not self.changed_timestamp_match(target, prev_ni):
2811
+ try:
2812
+ self.get_ninfo().csig = prev_ni.csig
2813
+ except AttributeError:
2814
+ pass
2815
+ return False
2816
+ return self.changed_content(target, prev_ni)
2817
+
2818
+ def changed_timestamp_newer(self, target, prev_ni):
2819
+ try:
2820
+ return self.get_timestamp() > target.get_timestamp()
2821
+ except AttributeError:
2822
+ return 1
2823
+
2824
+ def changed_timestamp_match(self, target, prev_ni):
2825
+ try:
2826
+ return self.get_timestamp() != prev_ni.timestamp
2827
+ except AttributeError:
2828
+ return 1
2829
+
2830
+ def decide_source(self, target, prev_ni):
2831
+ return target.get_build_env().decide_source(self, target, prev_ni)
2832
+
2833
+ def decide_target(self, target, prev_ni):
2834
+ return target.get_build_env().decide_target(self, target, prev_ni)
2835
+
2836
+ # Initialize this Node's decider function to decide_source() because
2837
+ # every file is a source file until it has a Builder attached...
2838
+ changed_since_last_build = decide_source
2839
+
2840
+ def is_up_to_date(self):
2841
+ T = 0
2842
+ if T: Trace('is_up_to_date(%s):' % self)
2843
+ if not self.exists():
2844
+ if T: Trace(' not self.exists():')
2845
+ # The file doesn't exist locally...
2846
+ r = self.rfile()
2847
+ if r != self:
2848
+ # ...but there is one in a Repository...
2849
+ if not self.changed(r):
2850
+ if T: Trace(' changed(%s):' % r)
2851
+ # ...and it's even up-to-date...
2852
+ if self._local:
2853
+ # ...and they'd like a local copy.
2854
+ e = LocalCopy(self, r, None)
2855
+ if isinstance(e, SCons.Errors.BuildError):
2856
+ raise
2857
+ self.store_info()
2858
+ if T: Trace(' 1\n')
2859
+ return 1
2860
+ self.changed()
2861
+ if T: Trace(' None\n')
2862
+ return None
2863
+ else:
2864
+ r = self.changed()
2865
+ if T: Trace(' self.exists(): %s\n' % r)
2866
+ return not r
2867
+
2868
+ memoizer_counters.append(SCons.Memoize.CountValue('rfile'))
2869
+
2870
+ def rfile(self):
2871
+ try:
2872
+ return self._memo['rfile']
2873
+ except KeyError:
2874
+ pass
2875
+ result = self
2876
+ if not self.exists():
2877
+ norm_name = _my_normcase(self.name)
2878
+ for dir in self.dir.get_all_rdirs():
2879
+ try: node = dir.entries[norm_name]
2880
+ except KeyError: node = dir.file_on_disk(self.name)
2881
+ if node and node.exists() and \
2882
+ (isinstance(node, File) or isinstance(node, Entry) \
2883
+ or not node.is_derived()):
2884
+ result = node
2885
+ # Copy over our local attributes to the repository
2886
+ # Node so we identify shared object files in the
2887
+ # repository and don't assume they're static.
2888
+ #
2889
+ # This isn't perfect; the attribute would ideally
2890
+ # be attached to the object in the repository in
2891
+ # case it was built statically in the repository
2892
+ # and we changed it to shared locally, but that's
2893
+ # rarely the case and would only occur if you
2894
+ # intentionally used the same suffix for both
2895
+ # shared and static objects anyway. So this
2896
+ # should work well in practice.
2897
+ result.attributes = self.attributes
2898
+ break
2899
+ self._memo['rfile'] = result
2900
+ return result
2901
+
2902
+ def rstr(self):
2903
+ return str(self.rfile())
2904
+
2905
+ def get_cachedir_csig(self):
2906
+ """
2907
+ Fetch a Node's content signature for purposes of computing
2908
+ another Node's cachesig.
2909
+
2910
+ This is a wrapper around the normal get_csig() method that handles
2911
+ the somewhat obscure case of using CacheDir with the -n option.
2912
+ Any files that don't exist would normally be "built" by fetching
2913
+ them from the cache, but the normal get_csig() method will try
2914
+ to open up the local file, which doesn't exist because the -n
2915
+ option meant we didn't actually pull the file from cachedir.
2916
+ But since the file *does* actually exist in the cachedir, we
2917
+ can use its contents for the csig.
2918
+ """
2919
+ try:
2920
+ return self.cachedir_csig
2921
+ except AttributeError:
2922
+ pass
2923
+
2924
+ cachedir, cachefile = self.get_build_env().get_CacheDir().cachepath(self)
2925
+ if not self.exists() and cachefile and os.path.exists(cachefile):
2926
+ self.cachedir_csig = SCons.Util.MD5filesignature(cachefile, \
2927
+ SCons.Node.FS.File.md5_chunksize * 1024)
2928
+ else:
2929
+ self.cachedir_csig = self.get_csig()
2930
+ return self.cachedir_csig
2931
+
2932
+ def get_cachedir_bsig(self):
2933
+ try:
2934
+ return self.cachesig
2935
+ except AttributeError:
2936
+ pass
2937
+
2938
+ # Add the path to the cache signature, because multiple
2939
+ # targets built by the same action will all have the same
2940
+ # build signature, and we have to differentiate them somehow.
2941
+ children = self.children()
2942
+ executor = self.get_executor()
2943
+ # sigs = [n.get_cachedir_csig() for n in children]
2944
+ sigs = [n.get_cachedir_csig() for n in children]
2945
+ sigs.append(SCons.Util.MD5signature(executor.get_contents()))
2946
+ sigs.append(self.path)
2947
+ result = self.cachesig = SCons.Util.MD5collect(sigs)
2948
+ return result
2949
+
2950
+
2951
+ default_fs = None
2952
+
2953
+ def get_default_fs():
2954
+ global default_fs
2955
+ if not default_fs:
2956
+ default_fs = FS()
2957
+ return default_fs
2958
+
2959
+ class FileFinder(object):
2960
+ """
2961
+ """
2962
+ if SCons.Memoize.use_memoizer:
2963
+ __metaclass__ = SCons.Memoize.Memoized_Metaclass
2964
+
2965
+ memoizer_counters = []
2966
+
2967
+ def __init__(self):
2968
+ self._memo = {}
2969
+
2970
+ def filedir_lookup(self, p, fd=None):
2971
+ """
2972
+ A helper method for find_file() that looks up a directory for
2973
+ a file we're trying to find. This only creates the Dir Node if
2974
+ it exists on-disk, since if the directory doesn't exist we know
2975
+ we won't find any files in it... :-)
2976
+
2977
+ It would be more compact to just use this as a nested function
2978
+ with a default keyword argument (see the commented-out version
2979
+ below), but that doesn't work unless you have nested scopes,
2980
+ so we define it here just so this work under Python 1.5.2.
2981
+ """
2982
+ if fd is None:
2983
+ fd = self.default_filedir
2984
+ dir, name = os.path.split(fd)
2985
+ drive, d = os.path.splitdrive(dir)
2986
+ if not name and d[:1] in ('/', os.sep):
2987
+ #return p.fs.get_root(drive).dir_on_disk(name)
2988
+ return p.fs.get_root(drive)
2989
+ if dir:
2990
+ p = self.filedir_lookup(p, dir)
2991
+ if not p:
2992
+ return None
2993
+ norm_name = _my_normcase(name)
2994
+ try:
2995
+ node = p.entries[norm_name]
2996
+ except KeyError:
2997
+ return p.dir_on_disk(name)
2998
+ if isinstance(node, Dir):
2999
+ return node
3000
+ if isinstance(node, Entry):
3001
+ node.must_be_same(Dir)
3002
+ return node
3003
+ return None
3004
+
3005
+ def _find_file_key(self, filename, paths, verbose=None):
3006
+ return (filename, paths)
3007
+
3008
+ memoizer_counters.append(SCons.Memoize.CountDict('find_file', _find_file_key))
3009
+
3010
+ def find_file(self, filename, paths, verbose=None):
3011
+ """
3012
+ find_file(str, [Dir()]) -> [nodes]
3013
+
3014
+ filename - a filename to find
3015
+ paths - a list of directory path *nodes* to search in. Can be
3016
+ represented as a list, a tuple, or a callable that is
3017
+ called with no arguments and returns the list or tuple.
3018
+
3019
+ returns - the node created from the found file.
3020
+
3021
+ Find a node corresponding to either a derived file or a file
3022
+ that exists already.
3023
+
3024
+ Only the first file found is returned, and none is returned
3025
+ if no file is found.
3026
+ """
3027
+ memo_key = self._find_file_key(filename, paths)
3028
+ try:
3029
+ memo_dict = self._memo['find_file']
3030
+ except KeyError:
3031
+ memo_dict = {}
3032
+ self._memo['find_file'] = memo_dict
3033
+ else:
3034
+ try:
3035
+ return memo_dict[memo_key]
3036
+ except KeyError:
3037
+ pass
3038
+
3039
+ if verbose and not callable(verbose):
3040
+ if not SCons.Util.is_String(verbose):
3041
+ verbose = "find_file"
3042
+ _verbose = u' %s: ' % verbose
3043
+ verbose = lambda s: sys.stdout.write(_verbose + s)
3044
+
3045
+ filedir, filename = os.path.split(filename)
3046
+ if filedir:
3047
+ # More compact code that we can't use until we drop
3048
+ # support for Python 1.5.2:
3049
+ #
3050
+ #def filedir_lookup(p, fd=filedir):
3051
+ # """
3052
+ # A helper function that looks up a directory for a file
3053
+ # we're trying to find. This only creates the Dir Node
3054
+ # if it exists on-disk, since if the directory doesn't
3055
+ # exist we know we won't find any files in it... :-)
3056
+ # """
3057
+ # dir, name = os.path.split(fd)
3058
+ # if dir:
3059
+ # p = filedir_lookup(p, dir)
3060
+ # if not p:
3061
+ # return None
3062
+ # norm_name = _my_normcase(name)
3063
+ # try:
3064
+ # node = p.entries[norm_name]
3065
+ # except KeyError:
3066
+ # return p.dir_on_disk(name)
3067
+ # if isinstance(node, Dir):
3068
+ # return node
3069
+ # if isinstance(node, Entry):
3070
+ # node.must_be_same(Dir)
3071
+ # return node
3072
+ # if isinstance(node, Dir) or isinstance(node, Entry):
3073
+ # return node
3074
+ # return None
3075
+ #paths = [_f for _f in map(filedir_lookup, paths) if _f]
3076
+
3077
+ self.default_filedir = filedir
3078
+ paths = [_f for _f in map(self.filedir_lookup, paths) if _f]
3079
+
3080
+ result = None
3081
+ for dir in paths:
3082
+ if verbose:
3083
+ verbose("looking for '%s' in '%s' ...\n" % (filename, dir))
3084
+ node, d = dir.srcdir_find_file(filename)
3085
+ if node:
3086
+ if verbose:
3087
+ verbose("... FOUND '%s' in '%s'\n" % (filename, d))
3088
+ result = node
3089
+ break
3090
+
3091
+ memo_dict[memo_key] = result
3092
+
3093
+ return result
3094
+
3095
+ find_file = FileFinder().find_file
3096
+
3097
+
3098
+ def invalidate_node_memos(targets):
3099
+ """
3100
+ Invalidate the memoized values of all Nodes (files or directories)
3101
+ that are associated with the given entries. Has been added to
3102
+ clear the cache of nodes affected by a direct execution of an
3103
+ action (e.g. Delete/Copy/Chmod). Existing Node caches become
3104
+ inconsistent if the action is run through Execute(). The argument
3105
+ `targets` can be a single Node object or filename, or a sequence
3106
+ of Nodes/filenames.
3107
+ """
3108
+ from traceback import extract_stack
3109
+
3110
+ # First check if the cache really needs to be flushed. Only
3111
+ # actions run in the SConscript with Execute() seem to be
3112
+ # affected. XXX The way to check if Execute() is in the stacktrace
3113
+ # is a very dirty hack and should be replaced by a more sensible
3114
+ # solution.
3115
+ for f in extract_stack():
3116
+ if f[2] == 'Execute' and f[0][-14:] == 'Environment.py':
3117
+ break
3118
+ else:
3119
+ # Dont have to invalidate, so return
3120
+ return
3121
+
3122
+ if not SCons.Util.is_List(targets):
3123
+ targets = [targets]
3124
+
3125
+ for entry in targets:
3126
+ # If the target is a Node object, clear the cache. If it is a
3127
+ # filename, look up potentially existing Node object first.
3128
+ try:
3129
+ entry.clear_memoized_values()
3130
+ except AttributeError:
3131
+ # Not a Node object, try to look up Node by filename. XXX
3132
+ # This creates Node objects even for those filenames which
3133
+ # do not correspond to an existing Node object.
3134
+ node = get_default_fs().Entry(entry)
3135
+ if node:
3136
+ node.clear_memoized_values()
3137
+
3138
+ # Local Variables:
3139
+ # tab-width:4
3140
+ # indent-tabs-mode:nil
3141
+ # End:
3142
+ # vim: set expandtab tabstop=4 shiftwidth=4: