From baee03c569c91b745a1e025660b19a718db16e7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Frings-F=C3=BCrst?= Date: Thu, 28 Sep 2017 12:18:58 +0200 Subject: New upstream version 3.0.0 --- LICENSE | 2 +- QMTest/README.txt | 4 +- QMTest/SConscript | 6 +- QMTest/TestCmd.py | 481 ++++++++---- QMTest/TestCmdTests.py | 266 +++---- QMTest/TestCommon.py | 84 +-- QMTest/TestCommonTests.py | 13 +- QMTest/TestRuntest.py | 4 +- QMTest/TestSCons.py | 363 ++++++---- QMTest/TestSConsMSVS.py | 26 +- QMTest/TestSCons_time.py | 21 +- QMTest/TestSConsign.py | 7 +- QMTest/scons_tdb.py | 20 +- README.rst | 44 +- SConstruct | 208 +++--- bin/Command.py | 7 +- bin/SConsDoc.py | 45 +- bin/SConsExamples.py | 164 ++--- bin/calibrate.py | 8 +- bin/caller-tree.py | 11 +- bin/docs-create-example-outputs.py | 9 +- bin/docs-update-generated.py | 3 +- bin/docs-validate.py | 9 +- bin/import-test.py | 4 +- bin/install_python.py | 7 +- bin/install_scons.py | 12 +- bin/linecount.py | 34 +- bin/memlogs.py | 10 +- bin/memoicmp.py | 30 +- bin/objcounts.py | 14 +- bin/restore.sh | 28 +- bin/scons-diff.py | 15 +- bin/scons-proc.py | 25 +- bin/scons-test.py | 65 +- bin/scons-unzip.py | 3 +- bin/scons_dev_master.py | 26 +- bin/sfsum | 11 +- bin/svn-bisect.py | 14 +- bin/update-release-info.py | 35 +- bin/xmlagenda.py | 3 +- bootstrap.py | 14 +- doc/SConscript | 109 +-- doc/design/SConstruct | 2 +- doc/design/acks.xml | 2 +- doc/design/bground.xml | 2 +- doc/design/chtml.xsl | 2 +- doc/design/copyright.xml | 2 +- doc/design/engine.xml | 2 +- doc/design/goals.xml | 2 +- doc/design/html.xsl | 2 +- doc/design/install.xml | 2 +- doc/design/intro.xml | 2 +- doc/design/issues.xml | 2 +- doc/design/main.xml | 2 +- doc/design/native.xml | 2 +- doc/design/overview.xml | 2 +- doc/design/pdf.xsl | 2 +- doc/design/scons_title.xsl | 2 +- doc/design/summary.xml | 2 +- doc/developer/SConstruct | 2 +- doc/developer/architecture.xml | 2 +- doc/developer/branches.xml | 2 +- doc/developer/copyright.xml | 2 +- doc/developer/cycle.xml | 2 +- doc/developer/main.xml | 2 +- doc/developer/packaging.xml | 2 +- doc/developer/preface.xml | 2 +- doc/developer/sourcetree.xml | 2 +- doc/developer/testing.xml | 2 +- doc/generated/builders.gen | 87 ++- doc/generated/builders.mod | 4 + doc/generated/examples/caching_ex-random_1.xml | 6 +- doc/generated/examples/environments_ex3_1.xml | 22 +- doc/generated/examples/environments_missing2_1.xml | 2 +- doc/generated/examples/java_jar1_1.xml | 2 +- .../examples/mergeflags_MergeFlags1_1.xml | 9 +- .../examples/mergeflags_MergeFlags2_1.xml | 9 +- .../examples/mergeflags_MergeFlags3_1.xml | 10 +- doc/generated/examples/misc_Flatten2_1.xml | 2 +- doc/generated/examples/parseflags_ex1_1.xml | 12 +- doc/generated/examples/parseflags_ex1_2.xml | 13 +- doc/generated/examples/parseflags_ex2_1.xml | 10 +- doc/generated/examples/parseflags_ex3_1.xml | 12 +- doc/generated/examples/parseflags_ex4_1.xml | 12 +- doc/generated/examples/sourcecode_bitkeeper_1.xml | 6 +- doc/generated/examples/sourcecode_cvs_1.xml | 6 +- doc/generated/examples/sourcecode_rcs_1.xml | 6 +- doc/generated/examples/sourcecode_sccs_1.xml | 6 +- doc/generated/examples/tasks_ex1_1.xml | 2 +- doc/generated/examples/troubleshoot_Dump_1.xml | 78 +- doc/generated/examples/troubleshoot_Dump_2.xml | 110 +-- doc/generated/examples/troubleshoot_Dump_ENV_1.xml | 12 +- doc/generated/examples/troubleshoot_Dump_ENV_2.xml | 14 +- doc/generated/examples/troubleshoot_explain1_3.xml | 2 +- .../examples/troubleshoot_stacktrace_2.xml | 6 +- doc/generated/functions.gen | 251 +------ doc/generated/functions.mod | 24 +- doc/generated/tools.gen | 79 +- doc/generated/tools.mod | 18 +- doc/generated/variables.gen | 805 +++++++++++---------- doc/generated/variables.mod | 78 +- doc/man/SConstruct | 2 +- doc/man/epub.xsl | 2 +- doc/man/html.xsl | 2 +- doc/man/pdf.xsl | 2 +- doc/man/scons-time.xml | 6 +- doc/man/scons.xml | 58 +- doc/man/scons_title.xsl | 2 +- doc/man/sconsign.xml | 6 +- doc/python10/SConstruct | 2 +- doc/python10/abstract.xml | 2 +- doc/python10/acks.xml | 2 +- doc/python10/copyright.xml | 2 +- doc/python10/design.xml | 2 +- doc/python10/future.xml | 2 +- doc/python10/install.xml | 2 +- doc/python10/intro.xml | 2 +- doc/python10/main.xml | 2 +- doc/python10/process.xml | 2 +- doc/python10/summary.xml | 2 +- doc/reference/Alias.xml | 2 +- doc/reference/CFile.xml | 2 +- doc/reference/CXXFile.xml | 2 +- doc/reference/Command.xml | 2 +- doc/reference/Install.xml | 2 +- doc/reference/InstallAs.xml | 2 +- doc/reference/Library.xml | 2 +- doc/reference/Object.xml | 2 +- doc/reference/PCH.xml | 2 +- doc/reference/PDF.xml | 2 +- doc/reference/PostScript.xml | 2 +- doc/reference/Program.xml | 2 +- doc/reference/RES.xml | 2 +- doc/reference/SConstruct | 2 +- doc/reference/SharedLibrary.xml | 2 +- doc/reference/SharedObject.xml | 2 +- doc/reference/StaticLibrary.xml | 2 +- doc/reference/StaticObject.xml | 2 +- doc/reference/chtml.xsl | 2 +- doc/reference/copyright.xml | 2 +- doc/reference/errors.xml | 2 +- doc/reference/html.xsl | 2 +- doc/reference/main.xml | 2 +- doc/reference/pdf.xsl | 2 +- doc/reference/preface.xml | 2 +- doc/reference/scons_title.xsl | 2 +- doc/scons.mod | 3 +- doc/user/README | 2 +- doc/user/SConstruct | 2 +- doc/user/actions.xml | 2 +- doc/user/add-method.xml | 2 +- doc/user/alias.xml | 2 +- doc/user/ant.xml | 2 +- doc/user/build-install.xml | 4 +- doc/user/builders-built-in.xml | 2 +- doc/user/builders-commands.xml | 2 +- doc/user/builders-writing.xml | 6 +- doc/user/builders.xml | 2 +- doc/user/caching.xml | 2 +- doc/user/chtml.xsl | 2 +- doc/user/command-line.xml | 16 +- doc/user/copyright.xml | 2 +- doc/user/depends.xml | 2 +- doc/user/environments.xml | 201 ++++- doc/user/epub.xsl | 2 +- doc/user/errors.xml | 2 +- doc/user/example.xml | 2 +- doc/user/factories.xml | 2 +- doc/user/file-removal.xml | 2 +- doc/user/functions.xml | 2 +- doc/user/gettext.xml | 2 +- doc/user/hierarchy.xml | 2 +- doc/user/html.xsl | 2 +- doc/user/install.xml | 2 +- doc/user/java.xml | 2 +- doc/user/less-simple.xml | 2 +- doc/user/libraries.xml | 2 +- doc/user/main.xml | 6 +- doc/user/make.xml | 2 +- doc/user/mergeflags.xml | 2 +- doc/user/misc.xml | 32 +- doc/user/nodes.xml | 14 +- doc/user/output.xml | 10 +- doc/user/parseconfig.xml | 2 +- doc/user/parseflags.xml | 2 +- doc/user/pdf.xsl | 2 +- doc/user/preface.xml | 2 +- doc/user/python.xml | 2 +- doc/user/repositories.xml | 2 +- doc/user/run.xml | 2 +- doc/user/scanners.xml | 2 +- doc/user/sconf.xml | 12 +- doc/user/scons_title.xsl | 2 +- doc/user/separate.xml | 2 +- doc/user/sideeffect.xml | 2 +- doc/user/simple.xml | 8 +- doc/user/sourcecode.xml | 2 +- doc/user/tasks.xml | 2 +- doc/user/tools.xml | 2 +- doc/user/troubleshoot.xml | 2 +- doc/user/variables.xml | 2 +- doc/user/variants.xml | 2 +- shippable.yml | 7 + src/Announce.txt | 44 +- src/CHANGES.txt | 168 ++++- src/LICENSE.txt | 2 +- src/README.txt | 14 +- src/RELEASE.txt | 35 +- src/engine/MANIFEST-xml.in | 1 + src/engine/MANIFEST.in | 20 +- src/engine/SCons/Action.py | 378 +++++++--- src/engine/SCons/Action.xml | 2 +- src/engine/SCons/ActionTests.py | 280 ++++--- src/engine/SCons/Builder.py | 49 +- src/engine/SCons/BuilderTests.py | 47 +- src/engine/SCons/CacheDir.py | 4 +- src/engine/SCons/CacheDirTests.py | 8 +- src/engine/SCons/Conftest.py | 45 +- src/engine/SCons/Debug.py | 8 +- src/engine/SCons/Defaults.py | 23 +- src/engine/SCons/Defaults.xml | 2 +- src/engine/SCons/DefaultsTests.py | 6 +- src/engine/SCons/Environment.py | 80 +- src/engine/SCons/Environment.xml | 31 +- src/engine/SCons/EnvironmentTests.py | 74 +- src/engine/SCons/EnvironmentValues.py | 97 +++ src/engine/SCons/EnvironmentValuesTest.py | 16 + src/engine/SCons/Errors.py | 128 ++-- src/engine/SCons/ErrorsTests.py | 16 +- src/engine/SCons/Executor.py | 25 +- src/engine/SCons/ExecutorTests.py | 41 +- src/engine/SCons/Job.py | 8 +- src/engine/SCons/JobTests.py | 4 +- src/engine/SCons/Memoize.py | 20 +- src/engine/SCons/MemoizeTests.py | 5 +- src/engine/SCons/Node/Alias.py | 4 +- src/engine/SCons/Node/AliasTests.py | 4 +- src/engine/SCons/Node/FS.py | 321 ++++---- src/engine/SCons/Node/FSTests.py | 113 ++- src/engine/SCons/Node/NodeTests.py | 4 +- src/engine/SCons/Node/Python.py | 21 +- src/engine/SCons/Node/PythonTests.py | 10 +- src/engine/SCons/Node/__init__.py | 118 ++- src/engine/SCons/Options/BoolOption.py | 4 +- src/engine/SCons/Options/EnumOption.py | 4 +- src/engine/SCons/Options/ListOption.py | 4 +- src/engine/SCons/Options/PackageOption.py | 4 +- src/engine/SCons/Options/PathOption.py | 4 +- src/engine/SCons/Options/__init__.py | 14 +- src/engine/SCons/PathList.py | 8 +- src/engine/SCons/PathListTests.py | 4 +- src/engine/SCons/Platform/PlatformTests.py | 4 +- src/engine/SCons/Platform/__init__.py | 25 +- src/engine/SCons/Platform/__init__.xml | 2 +- src/engine/SCons/Platform/aix.py | 6 +- src/engine/SCons/Platform/cygwin.py | 6 +- src/engine/SCons/Platform/darwin.py | 10 +- src/engine/SCons/Platform/hpux.py | 6 +- src/engine/SCons/Platform/irix.py | 6 +- src/engine/SCons/Platform/os2.py | 6 +- src/engine/SCons/Platform/posix.py | 6 +- src/engine/SCons/Platform/posix.xml | 2 +- src/engine/SCons/Platform/sunos.py | 6 +- src/engine/SCons/Platform/sunos.xml | 2 +- src/engine/SCons/Platform/win32.py | 113 ++- src/engine/SCons/Platform/win32.xml | 2 +- src/engine/SCons/SConf.py | 51 +- src/engine/SCons/SConfTests.py | 61 +- src/engine/SCons/SConsign.py | 39 +- src/engine/SCons/SConsignTests.py | 4 +- src/engine/SCons/Scanner/C.py | 11 +- src/engine/SCons/Scanner/CTests.py | 4 +- src/engine/SCons/Scanner/D.py | 20 +- src/engine/SCons/Scanner/DTests.py | 282 ++++++++ src/engine/SCons/Scanner/Dir.py | 6 +- src/engine/SCons/Scanner/DirTests.py | 4 +- src/engine/SCons/Scanner/Fortran.py | 4 +- src/engine/SCons/Scanner/FortranTests.py | 4 +- src/engine/SCons/Scanner/IDL.py | 4 +- src/engine/SCons/Scanner/IDLTests.py | 4 +- src/engine/SCons/Scanner/LaTeX.py | 129 ++-- src/engine/SCons/Scanner/LaTeXTests.py | 19 +- src/engine/SCons/Scanner/Prog.py | 4 +- src/engine/SCons/Scanner/ProgTests.py | 6 +- src/engine/SCons/Scanner/RC.py | 27 +- src/engine/SCons/Scanner/RCTests.py | 4 +- src/engine/SCons/Scanner/SWIG.py | 4 +- src/engine/SCons/Scanner/ScannerTests.py | 38 +- src/engine/SCons/Scanner/__init__.py | 42 +- src/engine/SCons/Scanner/__init__.xml | 2 +- src/engine/SCons/Script/Interactive.py | 36 +- src/engine/SCons/Script/Main.py | 91 ++- src/engine/SCons/Script/Main.xml | 14 +- src/engine/SCons/Script/MainTests.py | 4 +- src/engine/SCons/Script/SConsOptions.py | 28 +- src/engine/SCons/Script/SConscript.py | 35 +- src/engine/SCons/Script/SConscript.xml | 2 +- src/engine/SCons/Script/SConscriptTests.py | 4 +- src/engine/SCons/Script/__init__.py | 23 +- src/engine/SCons/Sig.py | 63 -- src/engine/SCons/Subst.py | 39 +- src/engine/SCons/Subst.xml | 2 +- src/engine/SCons/SubstTests.py | 83 ++- src/engine/SCons/Taskmaster.py | 96 ++- src/engine/SCons/TaskmasterTests.py | 43 +- src/engine/SCons/Tool/386asm.py | 6 +- src/engine/SCons/Tool/386asm.xml | 2 +- src/engine/SCons/Tool/BitKeeper.py | 66 -- src/engine/SCons/Tool/BitKeeper.xml | 123 ---- src/engine/SCons/Tool/CVS.py | 72 -- src/engine/SCons/Tool/CVS.xml | 159 ---- src/engine/SCons/Tool/DCommon.py | 17 +- src/engine/SCons/Tool/DCommon.xml | 71 ++ src/engine/SCons/Tool/FortranCommon.py | 17 +- src/engine/SCons/Tool/GettextCommon.py | 654 +++++++++-------- src/engine/SCons/Tool/JavaCommon.py | 4 +- src/engine/SCons/Tool/JavaCommonTests.py | 4 +- src/engine/SCons/Tool/MSCommon/__init__.py | 7 +- src/engine/SCons/Tool/MSCommon/arch.py | 4 +- src/engine/SCons/Tool/MSCommon/common.py | 100 +-- src/engine/SCons/Tool/MSCommon/netframework.py | 14 +- src/engine/SCons/Tool/MSCommon/sdk.py | 51 +- src/engine/SCons/Tool/MSCommon/vc.py | 162 +++-- src/engine/SCons/Tool/MSCommon/vs.py | 31 +- src/engine/SCons/Tool/Perforce.py | 99 --- src/engine/SCons/Tool/Perforce.xml | 129 ---- src/engine/SCons/Tool/PharLapCommon.py | 4 +- src/engine/SCons/Tool/RCS.py | 63 -- src/engine/SCons/Tool/RCS.xml | 142 ---- src/engine/SCons/Tool/SCCS.py | 63 -- src/engine/SCons/Tool/SCCS.xml | 133 ---- src/engine/SCons/Tool/Subversion.py | 70 -- src/engine/SCons/Tool/Subversion.xml | 135 ---- src/engine/SCons/Tool/ToolTests.py | 4 +- src/engine/SCons/Tool/__init__.py | 286 +++++--- src/engine/SCons/Tool/__init__.xml | 2 +- src/engine/SCons/Tool/aixc++.py | 40 +- src/engine/SCons/Tool/aixc++.xml | 2 +- src/engine/SCons/Tool/aixcc.py | 6 +- src/engine/SCons/Tool/aixcc.xml | 2 +- src/engine/SCons/Tool/aixcxx.py | 77 ++ src/engine/SCons/Tool/aixf77.py | 6 +- src/engine/SCons/Tool/aixf77.xml | 2 +- src/engine/SCons/Tool/aixlink.py | 12 +- src/engine/SCons/Tool/aixlink.xml | 2 +- src/engine/SCons/Tool/applelink.py | 14 +- src/engine/SCons/Tool/applelink.xml | 2 +- src/engine/SCons/Tool/ar.py | 8 +- src/engine/SCons/Tool/ar.xml | 2 +- src/engine/SCons/Tool/as.py | 4 +- src/engine/SCons/Tool/as.xml | 2 +- src/engine/SCons/Tool/bcc32.py | 4 +- src/engine/SCons/Tool/bcc32.xml | 2 +- src/engine/SCons/Tool/c++.py | 64 +- src/engine/SCons/Tool/c++.xml | 2 +- src/engine/SCons/Tool/cc.py | 4 +- src/engine/SCons/Tool/cc.xml | 2 +- src/engine/SCons/Tool/clang.py | 83 +++ src/engine/SCons/Tool/clang.xml | 39 + src/engine/SCons/Tool/clangxx.py | 91 +++ src/engine/SCons/Tool/clangxx.xml | 41 ++ src/engine/SCons/Tool/cvf.py | 6 +- src/engine/SCons/Tool/cvf.xml | 2 +- src/engine/SCons/Tool/cxx.py | 100 +++ src/engine/SCons/Tool/cyglink.py | 50 +- src/engine/SCons/Tool/cyglink.xml | 2 +- src/engine/SCons/Tool/default.py | 4 +- src/engine/SCons/Tool/default.xml | 2 +- src/engine/SCons/Tool/dmd.py | 48 +- src/engine/SCons/Tool/dmd.xml | 314 +++++++- src/engine/SCons/Tool/docbook/__init__.py | 29 +- src/engine/SCons/Tool/docbook/__init__.xml | 2 +- .../docbook-xsl-1.76.1/extensions/docbook.py | 11 +- .../docbook/docbook-xsl-1.76.1/extensions/xslt.py | 13 +- src/engine/SCons/Tool/dvi.py | 4 +- src/engine/SCons/Tool/dvi.xml | 2 +- src/engine/SCons/Tool/dvipdf.py | 8 +- src/engine/SCons/Tool/dvipdf.xml | 2 +- src/engine/SCons/Tool/dvips.py | 4 +- src/engine/SCons/Tool/dvips.xml | 2 +- src/engine/SCons/Tool/f03.py | 6 +- src/engine/SCons/Tool/f03.xml | 2 +- src/engine/SCons/Tool/f08.py | 8 +- src/engine/SCons/Tool/f08.xml | 2 +- src/engine/SCons/Tool/f77.py | 4 +- src/engine/SCons/Tool/f77.xml | 2 +- src/engine/SCons/Tool/f90.py | 4 +- src/engine/SCons/Tool/f90.xml | 2 +- src/engine/SCons/Tool/f95.py | 6 +- src/engine/SCons/Tool/f95.xml | 2 +- src/engine/SCons/Tool/filesystem.py | 6 +- src/engine/SCons/Tool/fortran.py | 4 +- src/engine/SCons/Tool/fortran.xml | 2 +- src/engine/SCons/Tool/g++.py | 43 +- src/engine/SCons/Tool/g++.xml | 2 +- src/engine/SCons/Tool/g77.py | 4 +- src/engine/SCons/Tool/g77.xml | 2 +- src/engine/SCons/Tool/gas.py | 9 +- src/engine/SCons/Tool/gas.xml | 2 +- src/engine/SCons/Tool/gcc.py | 10 +- src/engine/SCons/Tool/gcc.xml | 2 +- src/engine/SCons/Tool/gdc.py | 34 +- src/engine/SCons/Tool/gdc.xml | 356 +++++---- src/engine/SCons/Tool/gettext.py | 48 -- src/engine/SCons/Tool/gettext.xml | 2 +- src/engine/SCons/Tool/gettext_tool.py | 48 ++ src/engine/SCons/Tool/gfortran.py | 6 +- src/engine/SCons/Tool/gfortran.xml | 2 +- src/engine/SCons/Tool/gnulink.py | 6 +- src/engine/SCons/Tool/gnulink.xml | 2 +- src/engine/SCons/Tool/gs.py | 8 +- src/engine/SCons/Tool/gs.xml | 2 +- src/engine/SCons/Tool/gxx.py | 79 ++ src/engine/SCons/Tool/hpc++.py | 47 +- src/engine/SCons/Tool/hpc++.xml | 2 +- src/engine/SCons/Tool/hpcc.py | 6 +- src/engine/SCons/Tool/hpcc.xml | 2 +- src/engine/SCons/Tool/hpcxx.py | 87 +++ src/engine/SCons/Tool/hplink.py | 6 +- src/engine/SCons/Tool/hplink.xml | 2 +- src/engine/SCons/Tool/icc.py | 6 +- src/engine/SCons/Tool/icc.xml | 2 +- src/engine/SCons/Tool/icl.py | 4 +- src/engine/SCons/Tool/icl.xml | 2 +- src/engine/SCons/Tool/ifl.py | 6 +- src/engine/SCons/Tool/ifl.xml | 2 +- src/engine/SCons/Tool/ifort.py | 6 +- src/engine/SCons/Tool/ifort.xml | 2 +- src/engine/SCons/Tool/ilink.py | 4 +- src/engine/SCons/Tool/ilink.xml | 2 +- src/engine/SCons/Tool/ilink32.py | 4 +- src/engine/SCons/Tool/ilink32.xml | 2 +- src/engine/SCons/Tool/install.py | 25 +- src/engine/SCons/Tool/install.xml | 2 +- src/engine/SCons/Tool/intelc.py | 25 +- src/engine/SCons/Tool/intelc.xml | 2 +- src/engine/SCons/Tool/ipkg.py | 28 +- src/engine/SCons/Tool/jar.py | 4 +- src/engine/SCons/Tool/jar.xml | 2 +- src/engine/SCons/Tool/javac.py | 4 +- src/engine/SCons/Tool/javac.xml | 2 +- src/engine/SCons/Tool/javacTests.py | 2 +- src/engine/SCons/Tool/javah.py | 4 +- src/engine/SCons/Tool/javah.xml | 2 +- src/engine/SCons/Tool/latex.py | 8 +- src/engine/SCons/Tool/latex.xml | 2 +- src/engine/SCons/Tool/ldc.py | 47 +- src/engine/SCons/Tool/ldc.xml | 312 +++++++- src/engine/SCons/Tool/lex.py | 4 +- src/engine/SCons/Tool/lex.xml | 2 +- src/engine/SCons/Tool/link.py | 70 +- src/engine/SCons/Tool/link.xml | 2 +- src/engine/SCons/Tool/linkloc.py | 8 +- src/engine/SCons/Tool/linkloc.xml | 2 +- src/engine/SCons/Tool/m4.py | 4 +- src/engine/SCons/Tool/m4.xml | 2 +- src/engine/SCons/Tool/masm.py | 4 +- src/engine/SCons/Tool/masm.xml | 2 +- src/engine/SCons/Tool/midl.py | 18 +- src/engine/SCons/Tool/midl.xml | 2 +- src/engine/SCons/Tool/mingw.py | 7 +- src/engine/SCons/Tool/mingw.xml | 2 +- src/engine/SCons/Tool/msgfmt.py | 6 +- src/engine/SCons/Tool/msgfmt.xml | 2 +- src/engine/SCons/Tool/msginit.py | 8 +- src/engine/SCons/Tool/msginit.xml | 2 +- src/engine/SCons/Tool/msgmerge.py | 6 +- src/engine/SCons/Tool/msgmerge.xml | 2 +- src/engine/SCons/Tool/mslib.py | 6 +- src/engine/SCons/Tool/mslib.xml | 2 +- src/engine/SCons/Tool/mslink.py | 19 +- src/engine/SCons/Tool/mslink.xml | 2 +- src/engine/SCons/Tool/mssdk.py | 6 +- src/engine/SCons/Tool/mssdk.xml | 2 +- src/engine/SCons/Tool/msvc.py | 25 +- src/engine/SCons/Tool/msvc.xml | 27 +- src/engine/SCons/Tool/msvs.py | 214 +++--- src/engine/SCons/Tool/msvs.xml | 12 +- src/engine/SCons/Tool/msvsTests.py | 17 +- src/engine/SCons/Tool/mwcc.py | 4 +- src/engine/SCons/Tool/mwcc.xml | 2 +- src/engine/SCons/Tool/mwld.py | 4 +- src/engine/SCons/Tool/mwld.xml | 2 +- src/engine/SCons/Tool/nasm.py | 4 +- src/engine/SCons/Tool/nasm.xml | 2 +- src/engine/SCons/Tool/packaging.xml | 2 +- src/engine/SCons/Tool/packaging/__init__.py | 16 +- src/engine/SCons/Tool/packaging/__init__.xml | 2 +- src/engine/SCons/Tool/packaging/ipk.py | 6 +- src/engine/SCons/Tool/packaging/msi.py | 6 +- src/engine/SCons/Tool/packaging/rpm.py | 17 +- src/engine/SCons/Tool/packaging/src_tarbz2.py | 4 +- src/engine/SCons/Tool/packaging/src_targz.py | 4 +- src/engine/SCons/Tool/packaging/src_zip.py | 4 +- src/engine/SCons/Tool/packaging/tarbz2.py | 4 +- src/engine/SCons/Tool/packaging/targz.py | 4 +- src/engine/SCons/Tool/packaging/zip.py | 4 +- src/engine/SCons/Tool/pdf.py | 4 +- src/engine/SCons/Tool/pdf.xml | 2 +- src/engine/SCons/Tool/pdflatex.py | 6 +- src/engine/SCons/Tool/pdflatex.xml | 2 +- src/engine/SCons/Tool/pdftex.py | 6 +- src/engine/SCons/Tool/pdftex.xml | 2 +- src/engine/SCons/Tool/qt.py | 25 +- src/engine/SCons/Tool/qt.xml | 2 +- src/engine/SCons/Tool/rmic.py | 4 +- src/engine/SCons/Tool/rmic.xml | 2 +- src/engine/SCons/Tool/rpcgen.py | 4 +- src/engine/SCons/Tool/rpcgen.xml | 2 +- src/engine/SCons/Tool/rpm.py | 6 +- src/engine/SCons/Tool/rpmutils.py | 14 +- src/engine/SCons/Tool/sgiar.py | 4 +- src/engine/SCons/Tool/sgiar.xml | 2 +- src/engine/SCons/Tool/sgic++.py | 23 +- src/engine/SCons/Tool/sgic++.xml | 2 +- src/engine/SCons/Tool/sgicc.py | 6 +- src/engine/SCons/Tool/sgicc.xml | 2 +- src/engine/SCons/Tool/sgicxx.py | 61 ++ src/engine/SCons/Tool/sgilink.py | 6 +- src/engine/SCons/Tool/sgilink.xml | 2 +- src/engine/SCons/Tool/sunar.py | 4 +- src/engine/SCons/Tool/sunar.xml | 2 +- src/engine/SCons/Tool/sunc++.py | 105 +-- src/engine/SCons/Tool/sunc++.xml | 2 +- src/engine/SCons/Tool/suncc.py | 6 +- src/engine/SCons/Tool/suncc.xml | 2 +- src/engine/SCons/Tool/suncxx.py | 144 ++++ src/engine/SCons/Tool/sunf77.py | 6 +- src/engine/SCons/Tool/sunf77.xml | 2 +- src/engine/SCons/Tool/sunf90.py | 6 +- src/engine/SCons/Tool/sunf90.xml | 2 +- src/engine/SCons/Tool/sunf95.py | 6 +- src/engine/SCons/Tool/sunf95.xml | 2 +- src/engine/SCons/Tool/sunlink.py | 6 +- src/engine/SCons/Tool/sunlink.xml | 2 +- src/engine/SCons/Tool/swig.py | 14 +- src/engine/SCons/Tool/swig.xml | 2 +- src/engine/SCons/Tool/tar.py | 4 +- src/engine/SCons/Tool/tar.xml | 2 +- src/engine/SCons/Tool/tex.py | 115 +-- src/engine/SCons/Tool/tex.xml | 2 +- src/engine/SCons/Tool/textfile.py | 115 +-- src/engine/SCons/Tool/textfile.xml | 4 +- src/engine/SCons/Tool/tlib.py | 4 +- src/engine/SCons/Tool/tlib.xml | 2 +- src/engine/SCons/Tool/wix.py | 4 +- src/engine/SCons/Tool/wixTests.py | 4 +- src/engine/SCons/Tool/xgettext.py | 555 +++++++------- src/engine/SCons/Tool/xgettext.xml | 2 +- src/engine/SCons/Tool/yacc.py | 4 +- src/engine/SCons/Tool/yacc.xml | 2 +- src/engine/SCons/Tool/zip.py | 46 +- src/engine/SCons/Tool/zip.xml | 2 +- src/engine/SCons/Util.py | 256 +++++-- src/engine/SCons/UtilTests.py | 59 +- src/engine/SCons/Variables/BoolVariable.py | 14 +- src/engine/SCons/Variables/BoolVariableTests.py | 4 +- src/engine/SCons/Variables/EnumVariable.py | 28 +- src/engine/SCons/Variables/EnumVariableTests.py | 4 +- src/engine/SCons/Variables/ListVariable.py | 16 +- src/engine/SCons/Variables/ListVariableTests.py | 4 +- src/engine/SCons/Variables/PackageVariable.py | 28 +- src/engine/SCons/Variables/PackageVariableTests.py | 4 +- src/engine/SCons/Variables/PathVariable.py | 13 +- src/engine/SCons/Variables/PathVariableTests.py | 20 +- src/engine/SCons/Variables/VariablesTests.py | 14 +- src/engine/SCons/Variables/__init__.py | 43 +- src/engine/SCons/Warnings.py | 4 +- src/engine/SCons/WarningsTests.py | 4 +- src/engine/SCons/__init__.py | 12 +- src/engine/SCons/__main__.py | 4 + src/engine/SCons/compat/__init__.py | 92 ++- src/engine/SCons/compat/_scons_dbm.py | 4 +- src/engine/SCons/cpp.py | 26 +- src/engine/SCons/cppTests.py | 6 +- src/engine/SCons/dblite.py | 438 +++++------ src/engine/SCons/exitfuncs.py | 4 +- src/script/scons-configure-cache.py | 280 +++---- src/script/scons-time.py | 55 +- src/script/scons.bat | 6 +- src/script/scons.py | 22 +- src/script/sconsign.py | 82 ++- src/setup.cfg | 3 + src/setup.py | 320 ++++---- src/test_aegistests.py | 81 --- src/test_files.py | 13 +- src/test_interrupts.py | 12 +- src/test_pychecker.py | 7 +- src/test_setup.py | 11 +- src/test_strings.py | 17 +- 590 files changed, 9775 insertions(+), 7832 deletions(-) create mode 100644 shippable.yml create mode 100644 src/engine/SCons/EnvironmentValues.py create mode 100644 src/engine/SCons/EnvironmentValuesTest.py create mode 100644 src/engine/SCons/Scanner/DTests.py delete mode 100644 src/engine/SCons/Sig.py delete mode 100644 src/engine/SCons/Tool/BitKeeper.py delete mode 100644 src/engine/SCons/Tool/BitKeeper.xml delete mode 100644 src/engine/SCons/Tool/CVS.py delete mode 100644 src/engine/SCons/Tool/CVS.xml create mode 100644 src/engine/SCons/Tool/DCommon.xml delete mode 100644 src/engine/SCons/Tool/Perforce.py delete mode 100644 src/engine/SCons/Tool/Perforce.xml delete mode 100644 src/engine/SCons/Tool/RCS.py delete mode 100644 src/engine/SCons/Tool/RCS.xml delete mode 100644 src/engine/SCons/Tool/SCCS.py delete mode 100644 src/engine/SCons/Tool/SCCS.xml delete mode 100644 src/engine/SCons/Tool/Subversion.py delete mode 100644 src/engine/SCons/Tool/Subversion.xml create mode 100644 src/engine/SCons/Tool/aixcxx.py create mode 100644 src/engine/SCons/Tool/clang.py create mode 100644 src/engine/SCons/Tool/clang.xml create mode 100644 src/engine/SCons/Tool/clangxx.py create mode 100644 src/engine/SCons/Tool/clangxx.xml create mode 100644 src/engine/SCons/Tool/cxx.py delete mode 100644 src/engine/SCons/Tool/gettext.py create mode 100644 src/engine/SCons/Tool/gettext_tool.py create mode 100644 src/engine/SCons/Tool/gxx.py create mode 100644 src/engine/SCons/Tool/hpcxx.py create mode 100644 src/engine/SCons/Tool/sgicxx.py create mode 100644 src/engine/SCons/Tool/suncxx.py create mode 100644 src/engine/SCons/__main__.py delete mode 100644 src/test_aegistests.py diff --git a/LICENSE b/LICENSE index c730cc2..ff04f2e 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2001 - 2016 The SCons Foundation +Copyright (c) 2001 - 2017 The SCons Foundation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/QMTest/README.txt b/QMTest/README.txt index 4c7f413..c644565 100644 --- a/QMTest/README.txt +++ b/QMTest/README.txt @@ -54,5 +54,5 @@ the pieces here are local to SCons. from this infrastructure, in no small part because we're not really using it as originally envisioned. -Copyright (c) 2001 - 2016 The SCons Foundation -QMTest/README.txt rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog +Copyright (c) 2001 - 2017 The SCons Foundation +QMTest/README.txt rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog diff --git a/QMTest/SConscript b/QMTest/SConscript index e4c9108..4107862 100644 --- a/QMTest/SConscript +++ b/QMTest/SConscript @@ -3,7 +3,7 @@ # # -# Copyright (c) 2001 - 2016 The SCons Foundation +# Copyright (c) 2001 - 2017 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -44,12 +44,12 @@ files = [ def copy(target, source, env): t = str(target[0]) s = str(source[0]) - c = open(s, 'rb').read() + c = open(s, 'r').read() # Note: We construct the __ VERSION __ substitution string at # run-time so it doesn't get replaced when this file gets copied # into the tree for packaging. c = c.replace('__' + 'VERSION' + '__', env['VERSION']) - open(t, 'wb').write(c) + open(t, 'w').write(c) for file in files: # Guarantee that real copies of these files always exist in diff --git a/QMTest/TestCmd.py b/QMTest/TestCmd.py index cd559b7..0aab9a8 100644 --- a/QMTest/TestCmd.py +++ b/QMTest/TestCmd.py @@ -285,7 +285,7 @@ version. # PARTICULAR PURPOSE. THE CODE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, # AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. -from __future__ import division +from __future__ import division, print_function __author__ = "Steven Knight " __revision__ = "TestCmd.py 1.3.D001 2010/06/03 12:58:27 knight" @@ -306,8 +306,15 @@ import time import traceback import types + +IS_PY3 = sys.version_info[0] == 3 +IS_WINDOWS = sys.platform == 'win32' + + class null(object): pass + + _Null = null() try: @@ -328,12 +335,28 @@ __all__ = [ 'match_re_dotall', 'python', '_python_', - 'TestCmd' + 'TestCmd', + 'to_bytes', + 'to_str', ] + def is_List(e): return isinstance(e, (list, UserList)) + +def to_bytes(s): + if isinstance(s, bytes) or bytes is str: + return s + return bytes(s, 'utf-8') + + +def to_str(s): + if bytes is str or is_String(s): + return s + return str(s, 'utf-8') + + try: eval('unicode') except NameError: @@ -351,12 +374,13 @@ else: re_space = re.compile('\s') + def _caller(tblist, skip): string = "" arr = [] for file, line, name, text in tblist: if file[-10:] == "TestCmd.py": - break + break arr = [(file, line, name, text)] + arr atfrom = "at" for file, line, name, text in arr[skip:]: @@ -368,7 +392,8 @@ def _caller(tblist, skip): atfrom = "\tfrom" return string -def fail_test(self = None, condition = 1, function = None, skip = 0, message=None): + +def fail_test(self=None, condition=1, function=None, skip=0, message=None): """Cause the test to fail. By default, the fail_test() method reports that the test FAILED @@ -392,14 +417,15 @@ def fail_test(self = None, condition = 1, function = None, skip = 0, message=Non at = _caller(traceback.extract_stack(), skip) if message: - msg = "\t%s\n"%message + msg = "\t%s\n" % message else: msg = "" sys.stderr.write("FAILED test" + of + desc + sep + at + msg) sys.exit(1) -def no_result(self = None, condition = 1, function = None, skip = 0): + +def no_result(self=None, condition=1, function=None, skip=0): """Causes a test to exit with no valid result. By default, the no_result() method reports NO RESULT for the test @@ -426,7 +452,8 @@ def no_result(self = None, condition = 1, function = None, skip = 0): sys.exit(2) -def pass_test(self = None, condition = 1, function = None): + +def pass_test(self=None, condition=1, function=None): """Causes a test to pass. By default, the pass_test() method reports PASSED for the test @@ -440,13 +467,18 @@ def pass_test(self = None, condition = 1, function = None): sys.stderr.write("PASSED\n") sys.exit(0) -def match_exact(lines = None, matches = None): + +def match_exact(lines=None, matches=None, newline=os.sep): """ """ + + if isinstance(lines, bytes) or bytes is str: + newline = to_bytes(newline) + if not is_List(lines): - lines = lines.split("\n") + lines = lines.split(newline) if not is_List(matches): - matches = matches.split("\n") + matches = matches.split(newline) if len(lines) != len(matches): return for i in range(len(lines)): @@ -454,7 +486,8 @@ def match_exact(lines = None, matches = None): return return 1 -def match_caseinsensitive(lines = None, matches = None): + +def match_caseinsensitive(lines=None, matches=None): """ """ if not is_List(lines): @@ -468,7 +501,8 @@ def match_caseinsensitive(lines = None, matches = None): return return 1 -def match_re(lines = None, res = None): + +def match_re(lines=None, res=None): """ """ if not is_List(lines): @@ -477,21 +511,23 @@ def match_re(lines = None, res = None): if not is_List(res): res = res.split("\n") if len(lines) != len(res): - print "match_re: expected %d lines, found %d"%(len(res), len(lines)) + print("match_re: expected %d lines, found %d" % (len(res), len(lines))) return for i in range(len(lines)): s = "^" + res[i] + "$" try: expr = re.compile(s) - except re.error, e: + except re.error as e: msg = "Regular expression error in %s: %s" raise re.error(msg % (repr(s), e.args[0])) if not expr.search(lines[i]): - print "match_re: mismatch at line %d:\n search re='%s'\n line='%s'"%(i,s,lines[i]) + print("match_re: mismatch at line %d:\n search re='%s'\n line='%s'" % ( + i, s, lines[i])) return return 1 -def match_re_dotall(lines = None, res = None): + +def match_re_dotall(lines=None, res=None): """ """ if not isinstance(lines, str): @@ -501,11 +537,12 @@ def match_re_dotall(lines = None, res = None): s = "^" + res + "$" try: expr = re.compile(s, re.DOTALL) - except re.error, e: + except re.error as e: msg = "Regular expression error in %s: %s" raise re.error(msg % (repr(s), e.args[0])) return expr.match(lines) + def simple_diff(a, b, fromfile='', tofile='', fromfiledate='', tofiledate='', n=3, lineterm='\n'): """ @@ -513,26 +550,30 @@ def simple_diff(a, b, fromfile='', tofile='', (diff -c) and difflib.unified_diff (diff -u) but which prints output like the simple, unadorned 'diff" command. """ + a = [to_str(q) for q in a] + b = [to_str(q) for q in b] sm = difflib.SequenceMatcher(None, a, b) + def comma(x1, x2): - return x1+1 == x2 and str(x2) or '%s,%s' % (x1+1, x2) + return x1 + 1 == x2 and str(x2) or '%s,%s' % (x1 + 1, x2) result = [] for op, a1, a2, b1, b2 in sm.get_opcodes(): if op == 'delete': result.append("%sd%d" % (comma(a1, a2), b1)) - result.extend([ '< ' + l for l in a[a1:a2] ]) + result.extend(['< ' + l for l in a[a1:a2]]) elif op == 'insert': result.append("%da%s" % (a1, comma(b1, b2))) - result.extend([ '> ' + l for l in b[b1:b2] ]) + result.extend(['> ' + l for l in b[b1:b2]]) elif op == 'replace': result.append("%sc%s" % (comma(a1, a2), comma(b1, b2))) - result.extend([ '< ' + l for l in a[a1:a2] ]) + result.extend(['< ' + l for l in a[a1:a2]]) result.append('---') - result.extend([ '> ' + l for l in b[b1:b2] ]) + result.extend(['> ' + l for l in b[b1:b2]]) return result + def diff_re(a, b, fromfile='', tofile='', - fromfiledate='', tofiledate='', n=3, lineterm='\n'): + fromfiledate='', tofiledate='', n=3, lineterm='\n'): """ A simple "diff" of two sets of lines when the expected lines are regular expressions. This is a really dumb thing that @@ -543,33 +584,34 @@ def diff_re(a, b, fromfile='', tofile='', result = [] diff = len(a) - len(b) if diff < 0: - a = a + ['']*(-diff) + a = a + [''] * (-diff) elif diff > 0: - b = b + ['']*diff + b = b + [''] * diff i = 0 for aline, bline in zip(a, b): s = "^" + aline + "$" try: expr = re.compile(s) - except re.error, e: + except re.error as e: msg = "Regular expression error in %s: %s" raise re.error(msg % (repr(s), e.args[0])) if not expr.search(bline): - result.append("%sc%s" % (i+1, i+1)) + result.append("%sc%s" % (i + 1, i + 1)) result.append('< ' + repr(a[i])) result.append('---') result.append('> ' + repr(b[i])) - i = i+1 + i = i + 1 return result + if os.name == 'posix': def escape(arg): "escape shell special characters" slash = '\\' special = '"$' - arg = arg.replace(slash, slash+slash) + arg = arg.replace(slash, slash + slash) for c in special: - arg = arg.replace(c, slash+c) + arg = arg.replace(c, slash + c) if re_space.search(arg): arg = '"' + arg + '"' return arg @@ -627,14 +669,13 @@ else: st = os.stat(f) except OSError: continue - if stat.S_IMODE(st[stat.ST_MODE]) & 0111: + if stat.S_IMODE(st[stat.ST_MODE]) & 0o111: return f return None default_sleep_seconds = 1 - import subprocess try: @@ -642,6 +683,7 @@ try: except AttributeError: if sys.platform == 'win32': import win32process + def terminate(self): win32process.TerminateProcess(self._handle, 1) else: @@ -651,53 +693,64 @@ except AttributeError: setattr(subprocess.Popen, 'terminate', method) - # From Josiah Carlson, # ASPN : Python Cookbook : Module to allow Asynchronous subprocess use on Windows and Posix platforms # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/440554 PIPE = subprocess.PIPE -if subprocess.mswindows: +if sys.platform == 'win32': # and subprocess.mswindows: try: from win32file import ReadFile, WriteFile from win32pipe import PeekNamedPipe except ImportError: # If PyWin32 is not available, try ctypes instead # XXX These replicate _just_enough_ PyWin32 behaviour for our purposes - import ctypes; from ctypes.wintypes import DWORD + import ctypes + from ctypes.wintypes import DWORD + def ReadFile(hFile, bufSize, ol=None): assert ol is None lpBuffer = ctypes.create_string_buffer(bufSize) bytesRead = DWORD() bErr = ctypes.windll.kernel32.ReadFile( - hFile, lpBuffer, bufSize, ctypes.byref(bytesRead), ol) - if not bErr: raise ctypes.WinError() + hFile, lpBuffer, bufSize, ctypes.byref(bytesRead), ol) + if not bErr: + raise ctypes.WinError() return (0, ctypes.string_at(lpBuffer, bytesRead.value)) + def WriteFile(hFile, data, ol=None): assert ol is None bytesWritten = DWORD() bErr = ctypes.windll.kernel32.WriteFile( - hFile, data, len(data), ctypes.byref(bytesWritten), ol) - if not bErr: raise ctypes.WinError() + hFile, data, len(data), ctypes.byref(bytesWritten), ol) + if not bErr: + raise ctypes.WinError() return (0, bytesWritten.value) + def PeekNamedPipe(hPipe, size): assert size == 0 bytesAvail = DWORD() bErr = ctypes.windll.kernel32.PeekNamedPipe( - hPipe, None, size, None, ctypes.byref(bytesAvail), None) - if not bErr: raise ctypes.WinError() + hPipe, None, size, None, ctypes.byref(bytesAvail), None) + if not bErr: + raise ctypes.WinError() return ("", bytesAvail.value, None) import msvcrt else: import select import fcntl - try: fcntl.F_GETFL - except AttributeError: fcntl.F_GETFL = 3 + try: + fcntl.F_GETFL + except AttributeError: + fcntl.F_GETFL = 3 + + try: + fcntl.F_SETFL + except AttributeError: + fcntl.F_SETFL = 4 - try: fcntl.F_SETFL - except AttributeError: fcntl.F_SETFL = 4 class Popen(subprocess.Popen): def recv(self, maxsize=None): @@ -720,8 +773,9 @@ class Popen(subprocess.Popen): getattr(self, which).close() setattr(self, which, None) - if subprocess.mswindows: + if sys.platform == 'win32': # and subprocess.mswindows: def send(self, input): + input = to_bytes(input) if not self.stdin: return None @@ -730,7 +784,7 @@ class Popen(subprocess.Popen): (errCode, written) = WriteFile(x, input) except ValueError: return self._close('stdin') - except (subprocess.pywintypes.error, Exception), why: + except (subprocess.pywintypes.error, Exception) as why: if why.args[0] in (109, errno.ESHUTDOWN): return self._close('stdin') raise @@ -751,12 +805,12 @@ class Popen(subprocess.Popen): (errCode, read) = ReadFile(x, nAvail, None) except ValueError: return self._close(which) - except (subprocess.pywintypes.error, Exception), why: + except (subprocess.pywintypes.error, Exception) as why: if why.args[0] in (109, errno.ESHUTDOWN): return self._close(which) raise - #if self.universal_newlines: + # if self.universal_newlines: # read = self._translate_newlines(read) return read @@ -769,9 +823,10 @@ class Popen(subprocess.Popen): return 0 try: - written = os.write(self.stdin.fileno(), input) - except OSError, why: - if why.args[0] == errno.EPIPE: #broken pipe + written = os.write(self.stdin.fileno(), + bytearray(input, 'utf-8')) + except OSError as why: + if why.args[0] == errno.EPIPE: # broken pipe return self._close('stdin') raise @@ -788,7 +843,7 @@ class Popen(subprocess.Popen): flags = None else: if not conn.closed: - fcntl.fcntl(conn, fcntl.F_SETFL, flags| os.O_NONBLOCK) + fcntl.fcntl(conn, fcntl.F_SETFL, flags | os.O_NONBLOCK) try: if not select.select([conn], [], [], 0)[0]: @@ -798,19 +853,21 @@ class Popen(subprocess.Popen): if not r: return self._close(which) - #if self.universal_newlines: + # if self.universal_newlines: # r = self._translate_newlines(r) return r finally: if not conn.closed and not flags is None: fcntl.fcntl(conn, fcntl.F_SETFL, flags) + disconnect_message = "Other end disconnected!" + def recv_some(p, t=.1, e=1, tr=5, stderr=0): if tr < 1: tr = 1 - x = time.time()+t + x = time.time() + t y = [] r = '' pr = p.recv @@ -826,9 +883,10 @@ def recv_some(p, t=.1, e=1, tr=5, stderr=0): elif r: y.append(r) else: - time.sleep(max((x-time.time())/tr, 0)) + time.sleep(max((x - time.time()) / tr, 0)) return ''.join(y) + def send_all(p, data): while len(data): sent = p.send(data) @@ -836,16 +894,19 @@ def send_all(p, data): raise Exception(disconnect_message) data = memoryview(data)[sent:] + _Cleanup = [] + def _clean(): global _Cleanup - cleanlist = [ c for c in _Cleanup if c ] + cleanlist = [c for c in _Cleanup if c] del _Cleanup[:] cleanlist.reverse() for test in cleanlist: test.cleanup() + atexit.register(_clean) @@ -853,21 +914,21 @@ class TestCmd(object): """Class TestCmd """ - def __init__(self, description = None, - program = None, - interpreter = None, - workdir = None, - subdir = None, - verbose = None, - match = None, - match_stdout = None, - match_stderr = None, - diff = None, - diff_stdout = None, - diff_stderr = None, - combine = 0, - universal_newlines = 1, - timeout = None): + def __init__(self, description=None, + program=None, + interpreter=None, + workdir=None, + subdir=None, + verbose=None, + match=None, + match_stdout=None, + match_stderr=None, + diff=None, + diff_stdout=None, + diff_stderr=None, + combine=0, + universal_newlines=True, + timeout=None): self.external = os.environ.get('SCONS_EXTERNAL_TEST', 0) self._cwd = os.getcwd() self.description_set(description) @@ -875,7 +936,7 @@ class TestCmd(object): self.interpreter_set(interpreter) if verbose is None: try: - verbose = max( 0, int(os.environ.get('TESTCMD_VERBOSE', 0)) ) + verbose = max(0, int(os.environ.get('TESTCMD_VERBOSE', 0))) except ValueError: verbose = 0 self.verbose_set(verbose) @@ -887,7 +948,8 @@ class TestCmd(object): self.set_diff_function(diff, diff_stdout, diff_stderr) self._dirlist = [] self._preserve = {'pass_test': 0, 'fail_test': 0, 'no_result': 0} - if 'PRESERVE' in os.environ and not os.environ['PRESERVE'] is '': + preserve_value = os.environ.get('PRESERVE', False) + if preserve_value not in [0, '0', 'False']: self._preserve['pass_test'] = os.environ['PRESERVE'] self._preserve['fail_test'] = os.environ['PRESERVE'] self._preserve['no_result'] = os.environ['PRESERVE'] @@ -910,7 +972,7 @@ class TestCmd(object): self.condition = 'no_result' self.workdir_set(workdir) self.subdir(subdir) - self.script_srcdir = None + self.fixture_dirs = [] def __del__(self): self.cleanup() @@ -941,7 +1003,7 @@ class TestCmd(object): path = self.canonicalize(path) os.chmod(path, mode) - def cleanup(self, condition = None): + def cleanup(self, condition=None): """Removes any temporary working directories for the specified TestCmd environment. If the environment variable PRESERVE was set when the TestCmd environment was created, temporary working @@ -964,22 +1026,22 @@ class TestCmd(object): condition = self.condition if self._preserve[condition]: for dir in self._dirlist: - print unicode("Preserved directory " + dir + "\n"), + print(u"Preserved directory " + dir + "\n") else: list = self._dirlist[:] list.reverse() for dir in list: self.writable(dir, 1) - shutil.rmtree(dir, ignore_errors = 1) + shutil.rmtree(dir, ignore_errors=1) self._dirlist = [] global _Cleanup if self in _Cleanup: _Cleanup.remove(self) - def command_args(self, program = None, - interpreter = None, - arguments = None): + def command_args(self, program=None, + interpreter=None, + arguments=None): if not self.external: if program: if isinstance(program, str) and not os.path.isabs(program): @@ -1030,10 +1092,10 @@ class TestCmd(object): if diff_function is None: diff_function = self.simple_diff if name is not None: - print self.banner(name) + print(self.banner(name)) args = (a.splitlines(), b.splitlines()) + args for line in diff_function(*args, **kw): - print line + print(line) def diff_stderr(self, a, b, *args, **kw): """Compare actual and expected file contents. @@ -1061,17 +1123,17 @@ class TestCmd(object): unified_diff = staticmethod(difflib.unified_diff) - def fail_test(self, condition = 1, function = None, skip = 0, message = None): + def fail_test(self, condition=1, function=None, skip=0, message=None): """Cause the test to fail. """ if not condition: return self.condition = 'fail_test' - fail_test(self = self, - condition = condition, - function = function, - skip = skip, - message = message) + fail_test(self=self, + condition=condition, + function=function, + skip=skip, + message=message) def interpreter_set(self, interpreter): """Set the program to be used to interpret the program @@ -1133,24 +1195,24 @@ class TestCmd(object): match_re_dotall = staticmethod(match_re_dotall) - def no_result(self, condition = 1, function = None, skip = 0): + def no_result(self, condition=1, function=None, skip=0): """Report that the test could not be run. """ if not condition: return self.condition = 'no_result' - no_result(self = self, - condition = condition, - function = function, - skip = skip) + no_result(self=self, + condition=condition, + function=function, + skip=skip) - def pass_test(self, condition = 1, function = None): + def pass_test(self, condition=1, function=None): """Cause the test to pass. """ if not condition: return self.condition = 'pass_test' - pass_test(self = self, condition = condition, function = function) + pass_test(self=self, condition=condition, function=function) def preserve(self, *conditions): """Arrange for the temporary working directories for the @@ -1172,7 +1234,7 @@ class TestCmd(object): program = os.path.join(self._cwd, program) self.program = program - def read(self, file, mode = 'rb'): + def read(self, file, mode='rb', newline=None): """Reads and returns the contents of the specified file name. The file name may be a list, in which case the elements are concatenated with the os.path.join() method. The file is @@ -1184,7 +1246,10 @@ class TestCmd(object): file = self.canonicalize(file) if mode[0] != 'r': raise ValueError("mode must begin with 'r'") - return open(file, mode).read() + if IS_PY3 and 'b' not in mode: + return open(file, mode, newline=newline).read() + else: + return open(file, mode).read() def rmdir(self, dir): """Removes the specified dir name. @@ -1234,10 +1299,15 @@ class TestCmd(object): assumed to be under the temporary working directory, it gets created automatically, if it does not already exist. """ - if srcdir and self.script_srcdir and not os.path.isabs(srcdir): - spath = os.path.join(self.script_srcdir, srcdir) + + if srcdir and self.fixture_dirs and not os.path.isabs(srcdir): + for dir in self.fixture_dirs: + spath = os.path.join(dir, srcdir) + if os.path.isdir(spath): + break else: spath = srcdir + if dstdir: dstdir = self.canonicalize(dstdir) else: @@ -1248,7 +1318,7 @@ class TestCmd(object): if len(dstlist) > 0 and dstlist[0] == ".": dstlist = dstlist[1:] for idx in range(len(dstlist)): - self.subdir(dstlist[:idx+1]) + self.subdir(dstlist[:idx + 1]) if dstdir and self.workdir: dstdir = os.path.join(self.workdir, dstdir) @@ -1271,13 +1341,15 @@ class TestCmd(object): automatically, if it does not already exist. """ srcpath, srctail = os.path.split(srcfile) - if srcpath: - if self.script_srcdir and not os.path.isabs(srcpath): - spath = os.path.join(self.script_srcdir, srcfile) - else: - spath = srcfile + + if srcpath and (not self.fixture_dirs or os.path.isabs(srcpath)): + spath = srcfile else: - spath = os.path.join(self.script_srcdir, srcfile) + for dir in self.fixture_dirs: + spath = os.path.join(dir, srcfile) + if os.path.isfile(spath): + break + if not dstfile: if srctail: dpath = os.path.join(self.workdir, srctail) @@ -1291,17 +1363,17 @@ class TestCmd(object): if len(dstlist) > 0 and dstlist[0] == ".": dstlist = dstlist[1:] for idx in range(len(dstlist)): - self.subdir(dstlist[:idx+1]) + self.subdir(dstlist[:idx + 1]) dpath = os.path.join(self.workdir, dstfile) shutil.copy(spath, dpath) - def start(self, program = None, - interpreter = None, - arguments = None, - universal_newlines = None, - timeout = _Null, - **kw): + def start(self, program=None, + interpreter=None, + arguments=None, + universal_newlines=None, + timeout=_Null, + **kw): """ Starts a program or script for the test environment. @@ -1310,7 +1382,7 @@ class TestCmd(object): """ cmd = self.command_args(program, interpreter, arguments) if self.verbose: - cmd_string = ' '.join([ self.escape(c) for c in cmd ]) + cmd_string = ' '.join([self.escape(c) for c in cmd]) sys.stderr.write(cmd_string + "\n") if universal_newlines is None: universal_newlines = self.universal_newlines @@ -1334,14 +1406,56 @@ class TestCmd(object): if timeout: self.timer = threading.Timer(float(timeout), self._timeout) self.timer.start() + + if IS_PY3 and sys.platform == 'win32': + # Set this otherwist stdout/stderr pipes default to + # windows default locale cp1252 which will throw exception + # if using non-ascii characters. + # For example test/Install/non-ascii-name.py + os.environ['PYTHONIOENCODING'] = 'utf-8' + + # It seems that all pythons up to py3.6 still set text mode if you set encoding. + # TODO: File enhancement request on python to propagate universal_newlines even + # if encoding is set.hg c p = Popen(cmd, stdin=stdin, stdout=subprocess.PIPE, stderr=stderr_value, - universal_newlines=universal_newlines) + env=os.environ, + universal_newlines=False) + self.process = p return p + @staticmethod + def fix_binary_stream(stream): + """ + Handle stdout/stderr from popen when we specify universal_newlines = False. + This will read from the pipes in binary mode, not decode the output, + and not convert line endings to \n. + We do this because in py3 (3.5) with universal_newlines=True, it will + choose the default system locale to decode the output, and this breaks unicode + output. Specifically breaking test/option--tree.py which outputs a unicode char. + + py 3.6 allows us to pass an encoding param to popen thus not requiring the decode + nor end of line handling, because we propagate universal_newlines as specified. + + TODO: Do we need to pass universal newlines into this function? + """ + + if not stream: + return stream + # TODO: Run full tests on both platforms and see if this fixes failures + # It seems that py3.6 still sets text mode if you set encoding. + elif sys.version_info[0] == 3:# TODO and sys.version_info[1] < 6: + stream = stream.decode('utf-8') + stream = stream.replace('\r\n', '\n') + elif sys.version_info[0] == 2: + stream = stream.replace('\r\n', '\n') + + return stream + + def finish(self, popen=None, **kw): """ Finishes and waits for the process being run under control of @@ -1351,6 +1465,10 @@ class TestCmd(object): if popen is None: popen = self.process stdout, stderr = popen.communicate() + + stdout = self.fix_binary_stream(stdout) + stderr = self.fix_binary_stream(stderr) + if self.timer: self.timer.cancel() self.timer = None @@ -1359,13 +1477,13 @@ class TestCmd(object): self._stdout.append(stdout or '') self._stderr.append(stderr or '') - def run(self, program = None, - interpreter = None, - arguments = None, - chdir = None, - stdin = None, - universal_newlines = None, - timeout = _Null): + def run(self, program=None, + interpreter=None, + arguments=None, + chdir=None, + stdin=None, + universal_newlines=None, + timeout=_Null): """Runs a test of the program or script for the test environment. Standard output and error output are saved for future retrieval via the stdout() and stderr() methods. @@ -1379,6 +1497,9 @@ class TestCmd(object): if not interpreter: interpreter = self.interpreter + if universal_newlines is None: + universal_newlines = self.universal_newlines + if chdir: oldcwd = os.getcwd() if not os.path.isabs(chdir): @@ -1386,14 +1507,18 @@ class TestCmd(object): if self.verbose: sys.stderr.write("chdir(" + chdir + ")\n") os.chdir(chdir) - p = self.start(program = program, - interpreter = interpreter, - arguments = arguments, - universal_newlines = universal_newlines, - timeout = timeout, - stdin = stdin) + p = self.start(program=program, + interpreter=interpreter, + arguments=arguments, + universal_newlines=universal_newlines, + timeout=timeout, + stdin=stdin) if is_List(stdin): stdin = ''.join(stdin) + + if stdin and IS_PY3:# and sys.version_info[1] < 6: + stdin = to_bytes(stdin) + # TODO(sgk): figure out how to re-use the logic in the .finish() # method above. Just calling it from here causes problems with # subclasses that redefine .finish(). We could abstract this @@ -1405,6 +1530,11 @@ class TestCmd(object): self.timer = None self.status = p.returncode self.process = None + + stdout = self.fix_binary_stream(stdout) + stderr = self.fix_binary_stream(stderr) + + self._stdout.append(stdout or '') self._stderr.append(stderr or '') @@ -1424,7 +1554,7 @@ class TestCmd(object): write(err) write('============ END STDERR\n') - def sleep(self, seconds = default_sleep_seconds): + def sleep(self, seconds=default_sleep_seconds): """Sleeps at least the specified number of seconds. If no number is specified, sleeps at least the minimum number of seconds necessary to advance file time stamps on the current @@ -1432,7 +1562,7 @@ class TestCmd(object): """ time.sleep(seconds) - def stderr(self, run = None): + def stderr(self, run=None): """Returns the error output from the specified run number. If there is no specified run number, then returns the error output of the last run. If the run number is less than zero, @@ -1446,7 +1576,7 @@ class TestCmd(object): run = run - 1 return self._stderr[run] - def stdout(self, run = None): + def stdout(self, run=None): """Returns the standard output from the specified run number. If there is no specified run number, then returns the standard output of the last run. If the run number is less than zero, @@ -1494,6 +1624,11 @@ class TestCmd(object): is an absolute path name. The target is *not* assumed to be under the temporary working directory. """ + if sys.platform == 'win32': + # Skip this on windows as we're not enabling it due to + # it requiring user permissions which aren't always present + # and we don't have a good way to detect those permissions yet. + return link = self.canonicalize(link) try: os.symlink(target, link) @@ -1525,7 +1660,7 @@ class TestCmd(object): # Uppercase the drive letter since the case of drive # letters is pretty much random on win32: - drive,rest = os.path.splitdrive(path) + drive, rest = os.path.splitdrive(path) if drive: path = drive.upper() + rest @@ -1605,14 +1740,22 @@ class TestCmd(object): if read: def do_chmod(fname): - try: st = os.stat(fname) - except OSError: pass - else: os.chmod(fname, stat.S_IMODE(st[stat.ST_MODE]|stat.S_IREAD)) + try: + st = os.stat(fname) + except OSError: + pass + else: + os.chmod(fname, stat.S_IMODE( + st[stat.ST_MODE] | stat.S_IREAD)) else: def do_chmod(fname): - try: st = os.stat(fname) - except OSError: pass - else: os.chmod(fname, stat.S_IMODE(st[stat.ST_MODE]&~stat.S_IREAD)) + try: + st = os.stat(fname) + except OSError: + pass + else: + os.chmod(fname, stat.S_IMODE( + st[stat.ST_MODE] & ~stat.S_IREAD)) if os.path.isfile(top): # If it's a file, that's easy, just chmod it. @@ -1646,25 +1789,36 @@ class TestCmd(object): if write: def do_chmod(fname): - try: os.chmod(fname, stat.S_IWRITE) - except OSError: pass + try: + os.chmod(fname, stat.S_IWRITE) + except OSError: + pass else: def do_chmod(fname): - try: os.chmod(fname, stat.S_IREAD) - except OSError: pass + try: + os.chmod(fname, stat.S_IREAD) + except OSError: + pass else: if write: def do_chmod(fname): - try: st = os.stat(fname) - except OSError: pass - else: os.chmod(fname, stat.S_IMODE(st[stat.ST_MODE]|0200)) + try: + st = os.stat(fname) + except OSError: + pass + else: + os.chmod(fname, stat.S_IMODE(st[stat.ST_MODE] | 0o200)) else: def do_chmod(fname): - try: st = os.stat(fname) - except OSError: pass - else: os.chmod(fname, stat.S_IMODE(st[stat.ST_MODE]&~0200)) + try: + st = os.stat(fname) + except OSError: + pass + else: + os.chmod(fname, stat.S_IMODE( + st[stat.ST_MODE] & ~0o200)) if os.path.isfile(top): do_chmod(top) @@ -1687,14 +1841,22 @@ class TestCmd(object): if execute: def do_chmod(fname): - try: st = os.stat(fname) - except OSError: pass - else: os.chmod(fname, stat.S_IMODE(st[stat.ST_MODE]|stat.S_IEXEC)) + try: + st = os.stat(fname) + except OSError: + pass + else: + os.chmod(fname, stat.S_IMODE( + st[stat.ST_MODE] | stat.S_IEXEC)) else: def do_chmod(fname): - try: st = os.stat(fname) - except OSError: pass - else: os.chmod(fname, stat.S_IMODE(st[stat.ST_MODE]&~stat.S_IEXEC)) + try: + st = os.stat(fname) + except OSError: + pass + else: + os.chmod(fname, stat.S_IMODE( + st[stat.ST_MODE] & ~stat.S_IEXEC)) if os.path.isfile(top): # If it's a file, that's easy, just chmod it. @@ -1719,7 +1881,7 @@ class TestCmd(object): do_chmod(os.path.join(dirpath, name)) do_chmod(top) - def write(self, file, content, mode = 'wb'): + def write(self, file, content, mode='wb'): """Writes the specified content text (second argument) to the specified file name (first argument). The file name may be a list, in which case the elements are concatenated with the @@ -1731,7 +1893,12 @@ class TestCmd(object): file = self.canonicalize(file) if mode[0] != 'w': raise ValueError("mode must begin with 'w'") - open(file, mode).write(content) + with open(file, mode) as f: + try: + f.write(content) + except TypeError as e: + # python 3 default strings are not bytes, but unicode + f.write(bytes(content, 'utf-8')) # Local Variables: # tab-width:4 diff --git a/QMTest/TestCmdTests.py b/QMTest/TestCmdTests.py index 1044ed1..b9226fd 100644 --- a/QMTest/TestCmdTests.py +++ b/QMTest/TestCmdTests.py @@ -26,13 +26,14 @@ import os import shutil import signal import stat -import StringIO +from StringIO import StringIO import sys import tempfile import time import types import unittest -import UserList +from UserList import UserList + # Strip the current directory so we get the right TestCmd.py module. sys.path = sys.path[1:] @@ -131,11 +132,11 @@ class TestCmdTestCase(unittest.TestCase): run_env.write(t.scriptout_path, textout) run_env.write(t.scripterr_path, texterr) - os.chmod(t.script_path, 0644) # XXX UNIX-specific - os.chmod(t.scriptx_path, 0755) # XXX UNIX-specific - os.chmod(t.script1_path, 0644) # XXX UNIX-specific - os.chmod(t.scriptout_path, 0644) # XXX UNIX-specific - os.chmod(t.scripterr_path, 0644) # XXX UNIX-specific + os.chmod(t.script_path, 0o644) # XXX UNIX-specific + os.chmod(t.scriptx_path, 0o755) # XXX UNIX-specific + os.chmod(t.script1_path, 0o644) # XXX UNIX-specific + os.chmod(t.scriptout_path, 0o644) # XXX UNIX-specific + os.chmod(t.scripterr_path, 0o644) # XXX UNIX-specific t.orig_cwd = os.getcwd() @@ -220,8 +221,8 @@ class cleanup_TestCase(TestCmdTestCase): test = TestCmd.TestCmd(workdir = '') wdir = test.workdir test.write('file2', "Test file #2\n") - os.chmod(test.workpath('file2'), 0400) - os.chmod(wdir, 0500) + os.chmod(test.workpath('file2'), 0o400) + os.chmod(wdir, 0o500) test.cleanup() assert not os.path.exists(wdir) @@ -244,11 +245,12 @@ class cleanup_TestCase(TestCmdTestCase): def test_atexit(self): """Test cleanup() when atexit is used""" - self.popen_python("""import sys + self.popen_python("""from __future__ import print_function +import sys sys.path = ['%s'] + sys.path import atexit def my_exitfunc(): - print "my_exitfunc()" + print("my_exitfunc()") atexit.register(my_exitfunc) import TestCmd result = TestCmd.TestCmd(workdir = '') @@ -257,10 +259,11 @@ sys.exit(0) def test_exitfunc(self): """Test cleanup() when sys.exitfunc is set""" - self.popen_python("""import sys + self.popen_python("""from __future__ import print_function +import sys sys.path = ['%s'] + sys.path def my_exitfunc(): - print "my_exitfunc()" + print("my_exitfunc()") sys.exitfunc = my_exitfunc import TestCmd result = TestCmd.TestCmd(workdir = '') @@ -286,35 +289,35 @@ class chmod_TestCase(TestCmdTestCase): test.chmod(['sub', 'file2'], stat.S_IWRITE) file1_mode = stat.S_IMODE(os.stat(wdir_file1)[stat.ST_MODE]) - assert file1_mode == 0444, '0%o' % file1_mode + assert file1_mode == 0o444, '0%o' % file1_mode file2_mode = stat.S_IMODE(os.stat(wdir_sub_file2)[stat.ST_MODE]) - assert file2_mode == 0666, '0%o' % file2_mode + assert file2_mode == 0o666, '0%o' % file2_mode test.chmod('file1', stat.S_IWRITE) test.chmod(wdir_sub_file2, stat.S_IREAD) file1_mode = stat.S_IMODE(os.stat(wdir_file1)[stat.ST_MODE]) - assert file1_mode == 0666, '0%o' % file1_mode + assert file1_mode == 0o666, '0%o' % file1_mode file2_mode = stat.S_IMODE(os.stat(wdir_sub_file2)[stat.ST_MODE]) - assert file2_mode == 0444, '0%o' % file2_mode + assert file2_mode == 0o444, '0%o' % file2_mode else: - test.chmod(wdir_file1, 0700) - test.chmod(['sub', 'file2'], 0760) + test.chmod(wdir_file1, 0o700) + test.chmod(['sub', 'file2'], 0o760) file1_mode = stat.S_IMODE(os.stat(wdir_file1)[stat.ST_MODE]) - assert file1_mode == 0700, '0%o' % file1_mode + assert file1_mode == 0o700, '0%o' % file1_mode file2_mode = stat.S_IMODE(os.stat(wdir_sub_file2)[stat.ST_MODE]) - assert file2_mode == 0760, '0%o' % file2_mode + assert file2_mode == 0o760, '0%o' % file2_mode - test.chmod('file1', 0765) - test.chmod(wdir_sub_file2, 0567) + test.chmod('file1', 0o765) + test.chmod(wdir_sub_file2, 0o567) file1_mode = stat.S_IMODE(os.stat(wdir_file1)[stat.ST_MODE]) - assert file1_mode == 0765, '0%o' % file1_mode + assert file1_mode == 0o765, '0%o' % file1_mode file2_mode = stat.S_IMODE(os.stat(wdir_sub_file2)[stat.ST_MODE]) - assert file2_mode == 0567, '0%o' % file2_mode + assert file2_mode == 0o567, '0%o' % file2_mode @@ -593,13 +596,14 @@ sys.exit(0) def test_diff_stderr_not_affecting_diff_stdout(self): """Test diff_stderr() not affecting diff_stdout() behavior""" - self.popen_python(r"""import sys + self.popen_python(r"""from __future__ import print_function +import sys sys.path = ['%s'] + sys.path import TestCmd test = TestCmd.TestCmd(diff_stderr='diff_re') -print "diff_stderr:" +print("diff_stderr:") test.diff_stderr('a\nb.\nc\n', 'a\nbb\nc\n') -print "diff_stdout:" +print("diff_stdout:") test.diff_stdout('a\nb.\nc\n', 'a\nbb\nc\n') sys.exit(0) """ % self.orig_cwd, @@ -699,13 +703,14 @@ sys.exit(0) def test_diff_stdout_not_affecting_diff_stderr(self): """Test diff_stdout() not affecting diff_stderr() behavior""" - self.popen_python(r"""import sys + self.popen_python(r"""from __future__ import print_function +import sys sys.path = ['%s'] + sys.path import TestCmd test = TestCmd.TestCmd(diff_stdout='diff_re') -print "diff_stdout:" +print("diff_stdout:") test.diff_stdout('a\nb.\nc\n', 'a\nbb\nc\n') -print "diff_stderr:" +print("diff_stderr:") test.diff_stderr('a\nb.\nc\n', 'a\nbb\nc\n') sys.exit(0) """ % self.orig_cwd, @@ -1032,14 +1037,14 @@ class match_exact_TestCase(TestCmdTestCase): assert test.match_exact("abcde\n", "abcde\n") assert not test.match_exact(["12345\n", "abcde\n"], ["1[0-9]*5\n", "a.*e\n"]) assert test.match_exact(["12345\n", "abcde\n"], ["12345\n", "abcde\n"]) - assert not test.match_exact(UserList.UserList(["12345\n", "abcde\n"]), + assert not test.match_exact(UserList(["12345\n", "abcde\n"]), ["1[0-9]*5\n", "a.*e\n"]) - assert test.match_exact(UserList.UserList(["12345\n", "abcde\n"]), + assert test.match_exact(UserList(["12345\n", "abcde\n"]), ["12345\n", "abcde\n"]) assert not test.match_exact(["12345\n", "abcde\n"], - UserList.UserList(["1[0-9]*5\n", "a.*e\n"])) + UserList(["1[0-9]*5\n", "a.*e\n"])) assert test.match_exact(["12345\n", "abcde\n"], - UserList.UserList(["12345\n", "abcde\n"])) + UserList(["12345\n", "abcde\n"])) assert not test.match_exact("12345\nabcde\n", "1[0-9]*5\na.*e\n") assert test.match_exact("12345\nabcde\n", "12345\nabcde\n") lines = ["vwxyz\n", "67890\n"] @@ -1098,28 +1103,28 @@ sys.exit(0) ["1.*j\n"]) assert test.match_re_dotall(["12345\n", "abcde\n", "fghij\n"], ["12345\n", "abcde\n", "fghij\n"]) - assert test.match_re_dotall(UserList.UserList(["12345\n", - "abcde\n", - "fghij\n"]), + assert test.match_re_dotall(UserList(["12345\n", + "abcde\n", + "fghij\n"]), ["1[0-9]*5\n", "a.*e\n", "f.*j\n"]) - assert test.match_re_dotall(UserList.UserList(["12345\n", - "abcde\n", - "fghij\n"]), + assert test.match_re_dotall(UserList(["12345\n", + "abcde\n", + "fghij\n"]), ["1.*j\n"]) - assert test.match_re_dotall(UserList.UserList(["12345\n", - "abcde\n", - "fghij\n"]), + assert test.match_re_dotall(UserList(["12345\n", + "abcde\n", + "fghij\n"]), ["12345\n", "abcde\n", "fghij\n"]) assert test.match_re_dotall(["12345\n", "abcde\n", "fghij\n"], - UserList.UserList(["1[0-9]*5\n", - "a.*e\n", - "f.*j\n"])) + UserList(["1[0-9]*5\n", + "a.*e\n", + "f.*j\n"])) assert test.match_re_dotall(["12345\n", "abcde\n", "fghij\n"], - UserList.UserList(["1.*j\n"])) + UserList(["1.*j\n"])) assert test.match_re_dotall(["12345\n", "abcde\n", "fghij\n"], - UserList.UserList(["12345\n", - "abcde\n", - "fghij\n"])) + UserList(["12345\n", + "abcde\n", + "fghij\n"])) assert test.match_re_dotall("12345\nabcde\nfghij\n", "1[0-9]*5\na.*e\nf.*j\n") assert test.match_re_dotall("12345\nabcde\nfghij\n", "1.*j\n") @@ -1176,14 +1181,14 @@ sys.exit(0) assert test.match_re("abcde\n", "abcde\n") assert test.match_re(["12345\n", "abcde\n"], ["1[0-9]*5\n", "a.*e\n"]) assert test.match_re(["12345\n", "abcde\n"], ["12345\n", "abcde\n"]) - assert test.match_re(UserList.UserList(["12345\n", "abcde\n"]), + assert test.match_re(UserList(["12345\n", "abcde\n"]), ["1[0-9]*5\n", "a.*e\n"]) - assert test.match_re(UserList.UserList(["12345\n", "abcde\n"]), + assert test.match_re(UserList(["12345\n", "abcde\n"]), ["12345\n", "abcde\n"]) assert test.match_re(["12345\n", "abcde\n"], - UserList.UserList(["1[0-9]*5\n", "a.*e\n"])) + UserList(["1[0-9]*5\n", "a.*e\n"])) assert test.match_re(["12345\n", "abcde\n"], - UserList.UserList(["12345\n", "abcde\n"])) + UserList(["12345\n", "abcde\n"])) assert test.match_re("12345\nabcde\n", "1[0-9]*5\na.*e\n") assert test.match_re("12345\nabcde\n", "12345\nabcde\n") lines = ["vwxyz\n", "67890\n"] @@ -1463,7 +1468,7 @@ class preserve_TestCase(TestCmdTestCase): def test_preserve(self): """Test preserve()""" def cleanup_test(test, cond=None, stdout=""): - io = StringIO.StringIO() + io = StringIO() save = sys.stdout sys.stdout = io try: @@ -1603,7 +1608,7 @@ class read_TestCase(TestCmdTestCase): _file_matches(wdir_foo_file3, test.read(['foo', 'file3']), "Test\nfile\n#3.\n") _file_matches(wdir_foo_file3, - test.read(UserList.UserList(['foo', 'file3'])), + test.read(UserList(['foo', 'file3'])), "Test\nfile\n#3.\n") _file_matches(wdir_file4, test.read('file4', mode = 'r'), "Test\nfile\n#4.\n") @@ -1861,24 +1866,24 @@ class run_verbose_TestCase(TestCmdTestCase): interpreter = 'python', workdir = '', verbose = 1) - - sys.stdout = StringIO.StringIO() - sys.stderr = StringIO.StringIO() - + + sys.stdout = StringIO() + sys.stderr = StringIO() + test.run(arguments = ['arg1 arg2']) o = sys.stdout.getvalue() assert o == '', o e = sys.stderr.getvalue() expect = 'python "%s" "arg1 arg2"\n' % t.script_path assert expect == e, (expect, e) - + testx = TestCmd.TestCmd(program = t.scriptx, workdir = '', verbose = 1) - - sys.stdout = StringIO.StringIO() - sys.stderr = StringIO.StringIO() - + + sys.stdout = StringIO() + sys.stderr = StringIO() + testx.run(arguments = ['arg1 arg2']) expect = '"%s" "arg1 arg2"\n' % t.scriptx_path o = sys.stdout.getvalue() @@ -1912,10 +1917,10 @@ class run_verbose_TestCase(TestCmdTestCase): interpreter = 'python', workdir = '', verbose = 2) - - sys.stdout = StringIO.StringIO() - sys.stderr = StringIO.StringIO() - + + sys.stdout = StringIO() + sys.stderr = StringIO() + test.run(arguments = ['arg1 arg2']) line_fmt = "script: %s: %s: ['arg1 arg2']\n" @@ -1929,14 +1934,14 @@ class run_verbose_TestCase(TestCmdTestCase): expect = 'python "%s" "arg1 arg2"\n' % t.script_path e = sys.stderr.getvalue() assert e == expect, (e, expect) - + testx = TestCmd.TestCmd(program = t.scriptx, workdir = '', verbose = 2) - - sys.stdout = StringIO.StringIO() - sys.stderr = StringIO.StringIO() - + + sys.stdout = StringIO() + sys.stderr = StringIO() + testx.run(arguments = ['arg1 arg2']) line_fmt = "scriptx.bat: %s: %s: ['arg1 arg2']\n" @@ -1957,10 +1962,10 @@ class run_verbose_TestCase(TestCmdTestCase): interpreter = 'python', workdir = '', verbose = 2) - - sys.stdout = StringIO.StringIO() - sys.stderr = StringIO.StringIO() - + + sys.stdout = StringIO() + sys.stderr = StringIO() + test.run(arguments = ['arg1 arg2']) line_fmt = "scriptout: %s: %s: ['arg1 arg2']\n" @@ -1977,10 +1982,10 @@ class run_verbose_TestCase(TestCmdTestCase): interpreter = 'python', workdir = '', verbose = 3) - - sys.stdout = StringIO.StringIO() - sys.stderr = StringIO.StringIO() - + + sys.stdout = StringIO() + sys.stderr = StringIO() + test.run(arguments = ['arg1 arg2']) line_fmt = "scriptout: %s: %s: ['arg1 arg2']\n" @@ -2001,10 +2006,10 @@ class run_verbose_TestCase(TestCmdTestCase): test = TestCmd.TestCmd(program = t.script, interpreter = 'python', workdir = '') - - sys.stdout = StringIO.StringIO() - sys.stderr = StringIO.StringIO() - + + sys.stdout = StringIO() + sys.stderr = StringIO() + test.run(arguments = ['arg1 arg2']) line_fmt = "script: %s: %s: ['arg1 arg2']\n" @@ -2018,13 +2023,13 @@ class run_verbose_TestCase(TestCmdTestCase): expect = 'python "%s" "arg1 arg2"\n' % t.script_path e = sys.stderr.getvalue() assert e == expect, (e, expect) - + testx = TestCmd.TestCmd(program = t.scriptx, workdir = '') - - sys.stdout = StringIO.StringIO() - sys.stderr = StringIO.StringIO() - + + sys.stdout = StringIO() + sys.stderr = StringIO() + testx.run(arguments = ['arg1 arg2']) line_fmt = "scriptx.bat: %s: %s: ['arg1 arg2']\n" @@ -2047,24 +2052,24 @@ class run_verbose_TestCase(TestCmdTestCase): interpreter = 'python', workdir = '', verbose = 1) - - sys.stdout = StringIO.StringIO() - sys.stderr = StringIO.StringIO() - + + sys.stdout = StringIO() + sys.stderr = StringIO() + test.run(arguments = ['arg1 arg2']) o = sys.stdout.getvalue() assert o == '', o e = sys.stderr.getvalue() expect = 'python "%s" "arg1 arg2"\n' % t.script_path assert expect == e, (expect, e) - + testx = TestCmd.TestCmd(program = t.scriptx, workdir = '', verbose = 1) - - sys.stdout = StringIO.StringIO() - sys.stderr = StringIO.StringIO() - + + sys.stdout = StringIO() + sys.stderr = StringIO() + testx.run(arguments = ['arg1 arg2']) expect = '"%s" "arg1 arg2"\n' % t.scriptx_path o = sys.stdout.getvalue() @@ -2095,18 +2100,19 @@ sys.exit(0) def test_set_diff_function_stdout(self): """Test set_diff_function(): stdout""" - self.popen_python("""import sys + self.popen_python("""from __future__ import print_function +import sys sys.path = ['%s'] + sys.path import TestCmd test = TestCmd.TestCmd() -print "diff:" +print("diff:") test.diff("a\\n", "a\\n") -print "diff_stdout:" +print("diff_stdout:") test.diff_stdout("a\\n", "a\\n") test.set_diff_function(stdout='diff_re') -print "diff:" +print("diff:") test.diff(".\\n", "a\\n") -print "diff_stdout:" +print("diff_stdout:") test.diff_stdout(".\\n", "a\\n") sys.exit(0) """ % self.orig_cwd, @@ -2123,18 +2129,19 @@ diff_stdout: def test_set_diff_function_stderr(self): """Test set_diff_function(): stderr """ - self.popen_python("""import sys + self.popen_python("""from __future__ import print_function +import sys sys.path = ['%s'] + sys.path import TestCmd test = TestCmd.TestCmd() -print "diff:" +print("diff:") test.diff("a\\n", "a\\n") -print "diff_stderr:" +print("diff_stderr:") test.diff_stderr("a\\n", "a\\n") test.set_diff_function(stderr='diff_re') -print "diff:" +print("diff:") test.diff(".\\n", "a\\n") -print "diff_stderr:" +print("diff_stderr:") test.diff_stderr(".\\n", "a\\n") sys.exit(0) """ % self.orig_cwd, @@ -2347,7 +2354,7 @@ while 1: logfp.close() """ % t.recv_out_path t.run_env.write(t.recv_script_path, text) - os.chmod(t.recv_script_path, 0644) # XXX UNIX-specific + os.chmod(t.recv_script_path, 0o644) # XXX UNIX-specific return t def test_start(self): @@ -2695,9 +2702,10 @@ class stdin_TestCase(TestCmdTestCase): def test_stdin(self): """Test stdin()""" run_env = TestCmd.TestCmd(workdir = '') - run_env.write('run', """import fileinput + run_env.write('run', """from __future__ import print_function +import fileinput for line in fileinput.input(): - print 'Y'.join(line[:-1].split('X')) + print('Y'.join(line[:-1].split('X'))) """) run_env.write('input', "X on X this X line X\n") os.chdir(run_env.workdir) @@ -2765,11 +2773,11 @@ class subdir_TestCase(TestCmdTestCase): assert test.subdir('bar') == 1 assert test.subdir(['foo', 'succeed']) == 1 if os.name != "nt": - os.chmod(test.workpath('foo'), 0500) + os.chmod(test.workpath('foo'), 0o500) assert test.subdir(['foo', 'fail']) == 0 assert test.subdir(['sub', 'dir', 'ectory'], 'sub') == 1 assert test.subdir('one', - UserList.UserList(['one', 'two']), + UserList(['one', 'two']), ['one', 'two', 'three']) == 3 assert os.path.isdir(test.workpath('foo')) assert os.path.isdir(test.workpath('bar')) @@ -2962,7 +2970,7 @@ class unlink_TestCase(TestCmdTestCase): test.unlink(['foo', 'file3a']) assert not os.path.exists(wdir_foo_file3a) - test.unlink(UserList.UserList(['foo', 'file3b'])) + test.unlink(UserList(['foo', 'file3b'])) assert not os.path.exists(wdir_foo_file3b) test.unlink([test.workdir, 'foo', 'file4']) @@ -2971,8 +2979,8 @@ class unlink_TestCase(TestCmdTestCase): # Make it so we can't unlink file5. # For UNIX, remove write permission from the dir and the file. # For Windows, open the file. - os.chmod(test.workdir, 0500) - os.chmod(wdir_file5, 0400) + os.chmod(test.workdir, 0o500) + os.chmod(wdir_file5, 0o400) f = open(wdir_file5, 'r') try: @@ -2983,8 +2991,8 @@ class unlink_TestCase(TestCmdTestCase): except: raise finally: - os.chmod(test.workdir, 0700) - os.chmod(wdir_file5, 0600) + os.chmod(test.workdir, 0o700) + os.chmod(wdir_file5, 0o600) f.close() @@ -3208,11 +3216,11 @@ class executable_TestCase(TestCmdTestCase): def make_executable(fname): st = os.stat(fname) - os.chmod(fname, stat.S_IMODE(st[stat.ST_MODE]|0100)) + os.chmod(fname, stat.S_IMODE(st[stat.ST_MODE]|0o100)) def make_non_executable(fname): st = os.stat(fname) - os.chmod(fname, stat.S_IMODE(st[stat.ST_MODE]&~0100)) + os.chmod(fname, stat.S_IMODE(st[stat.ST_MODE]&~0o100)) test.executable(test.workdir, 0) # XXX skip these tests if euid == 0? @@ -3282,7 +3290,7 @@ class write_TestCase(TestCmdTestCase): test.write('file9', "Test file #9.\r\n", mode = 'wb') if os.name != "nt": - os.chmod(test.workdir, 0500) + os.chmod(test.workdir, 0o500) try: test.write('file10', "Test file #10 (should not get created).\n") except IOError: # expect "Permission denied" @@ -3326,14 +3334,16 @@ class variables_TestCase(TestCmdTestCase): 'TestCmd', ] - script = "import TestCmd\n" + \ - '\n'.join([ "print TestCmd.%s\n" % v for v in variables ]) + script = "from __future__ import print_function\n" + \ + "import TestCmd\n" + \ + '\n'.join([ "print(TestCmd.%s\n)" % v for v in variables ]) run_env.run(program=sys.executable, stdin=script) stderr = run_env.stderr() assert stderr == "", stderr - script = "from TestCmd import *\n" + \ - '\n'.join([ "print %s" % v for v in variables ]) + script = "from __future__ import print_function\n" + \ + "from TestCmd import *\n" + \ + '\n'.join([ "print(%s)" % v for v in variables ]) run_env.run(program=sys.executable, stdin=script) stderr = run_env.stderr() assert stderr == "", stderr diff --git a/QMTest/TestCommon.py b/QMTest/TestCommon.py index dc4c97c..a475ddc 100644 --- a/QMTest/TestCommon.py +++ b/QMTest/TestCommon.py @@ -93,6 +93,8 @@ The TestCommon module also provides the following variables # AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. +from __future__ import print_function + __author__ = "Steven Knight " __revision__ = "TestCommon.py 1.3.D001 2010/06/03 12:58:27 knight" __version__ = "1.3" @@ -258,9 +260,9 @@ class TestCommon(TestCmd): existing, missing = separate_files(files) unwritable = [x for x in existing if not is_writable(x)] if missing: - print "Missing files: `%s'" % "', `".join(missing) + print("Missing files: `%s'" % "', `".join(missing)) if unwritable: - print "Unwritable files: `%s'" % "', `".join(unwritable) + print("Unwritable files: `%s'" % "', `".join(unwritable)) self.fail_test(missing + unwritable) def must_contain(self, file, required, mode = 'rb', find = None): @@ -275,11 +277,11 @@ class TestCommon(TestCmd): return None contains = find(file_contents, required) if not contains: - print "File `%s' does not contain required string." % file - print self.banner('Required string ') - print required - print self.banner('%s contents ' % file) - print file_contents + print("File `%s' does not contain required string." % file) + print(self.banner('Required string ')) + print(required) + print(self.banner('%s contents ' % file)) + print(file_contents) self.fail_test(not contains) def must_contain_all(self, output, input, title=None, find=None): @@ -306,10 +308,10 @@ class TestCommon(TestCmd): if find(output, input) is None: if title is None: title = 'output' - print 'Missing expected input from %s:' % title - print input - print self.banner(title + ' ') - print output + print('Missing expected input from {}:'.format(title)) + print(input) + print(self.banner(title + ' ')) + print(output) self.fail_test() def must_contain_all_lines(self, output, lines, title=None, find=None): @@ -444,7 +446,7 @@ class TestCommon(TestCmd): files = [is_List(x) and os.path.join(*x) or x for x in files] missing = [x for x in files if not os.path.exists(x) and not os.path.islink(x) ] if missing: - print "Missing files: `%s'" % "', `".join(missing) + print("Missing files: `%s'" % "', `".join(missing)) self.fail_test(missing) def must_exist_one_of(self, files): @@ -464,24 +466,24 @@ class TestCommon(TestCmd): if glob.glob(xpath): return missing.append(xpath) - print "Missing one of: `%s'" % "', `".join(missing) + print("Missing one of: `%s'" % "', `".join(missing)) self.fail_test(missing) - def must_match(self, file, expect, mode = 'rb', match=None): + def must_match(self, file, expect, mode = 'rb', match=None, message=None, newline=None): """Matches the contents of the specified file (first argument) against the expected contents (second argument). The expected contents are a list of lines or a string which will be split on newlines. """ - file_contents = self.read(file, mode) + file_contents = self.read(file, mode, newline) if not match: match = self.match try: - self.fail_test(not match(file_contents, expect)) + self.fail_test(not match(to_str(file_contents), to_str(expect)), message=message) except KeyboardInterrupt: raise except: - print "Unexpected contents of `%s'" % file + print("Unexpected contents of `%s'" % file) self.diff(expect, file_contents, 'contents ') raise @@ -497,11 +499,11 @@ class TestCommon(TestCmd): return None contains = find(file_contents, banned) if contains: - print "File `%s' contains banned string." % file - print self.banner('Banned string ') - print banned - print self.banner('%s contents ' % file) - print file_contents + print("File `%s' contains banned string." % file) + print(self.banner('Banned string ')) + print(banned) + print(self.banner('%s contents ' % file)) + print(file_contents) self.fail_test(contains) def must_not_contain_any_line(self, output, lines, title=None, find=None): @@ -548,7 +550,7 @@ class TestCommon(TestCmd): files = [is_List(x) and os.path.join(*x) or x for x in files] existing = [x for x in files if os.path.exists(x) or os.path.islink(x)] if existing: - print "Unexpected files exist: `%s'" % "', `".join(existing) + print("Unexpected files exist: `%s'" % "', `".join(existing)) self.fail_test(existing) def must_not_exist_any_of(self, files): @@ -568,7 +570,7 @@ class TestCommon(TestCmd): if glob.glob(xpath): existing.append(xpath) if existing: - print "Unexpected files exist: `%s'" % "', `".join(existing) + print("Unexpected files exist: `%s'" % "', `".join(existing)) self.fail_test(existing) def must_not_be_writable(self, *files): @@ -580,11 +582,11 @@ class TestCommon(TestCmd): """ files = [is_List(x) and os.path.join(*x) or x for x in files] existing, missing = separate_files(files) - writable = list(filter(is_writable, existing)) + writable = [file for file in existing if is_writable(file)] if missing: - print "Missing files: `%s'" % "', `".join(missing) + print("Missing files: `%s'" % "', `".join(missing)) if writable: - print "Writable files: `%s'" % "', `".join(writable) + print("Writable files: `%s'" % "', `".join(writable)) self.fail_test(missing + writable) def _complete(self, actual_stdout, expected_stdout, @@ -597,23 +599,23 @@ class TestCommon(TestCmd): expect = '' if status != 0: expect = " (expected %s)" % str(status) - print "%s returned %s%s" % (self.program, _status(self), expect) - print self.banner('STDOUT ') - print actual_stdout - print self.banner('STDERR ') - print actual_stderr + print("%s returned %s%s" % (self.program, _status(self), expect)) + print(self.banner('STDOUT ')) + print(actual_stdout) + print(self.banner('STDERR ')) + print(actual_stderr) self.fail_test() if (expected_stdout is not None and not match(actual_stdout, expected_stdout)): self.diff(expected_stdout, actual_stdout, 'STDOUT ') if actual_stderr: - print self.banner('STDERR ') - print actual_stderr + print(self.banner('STDERR ')) + print(actual_stderr) self.fail_test() if (expected_stderr is not None and not match(actual_stderr, expected_stderr)): - print self.banner('STDOUT ') - print actual_stdout + print(self.banner('STDOUT ')) + print(actual_stdout) self.diff(expected_stderr, actual_stderr, 'STDERR ') self.fail_test() @@ -633,15 +635,15 @@ class TestCommon(TestCmd): universal_newlines, **kw) except KeyboardInterrupt: raise - except Exception, e: - print self.banner('STDOUT ') + except Exception as e: + print(self.banner('STDOUT ')) try: - print self.stdout() + print(self.stdout()) except IndexError: pass - print self.banner('STDERR ') + print(self.banner('STDERR ')) try: - print self.stderr() + print(self.stderr()) except IndexError: pass cmd_args = self.command_args(program, interpreter, arguments) diff --git a/QMTest/TestCommonTests.py b/QMTest/TestCommonTests.py index 30b7d6a..7949cb8 100644 --- a/QMTest/TestCommonTests.py +++ b/QMTest/TestCommonTests.py @@ -168,10 +168,11 @@ class __init__TestCase(TestCommonTestCase): os.chdir(run_env.workdir) script = lstrip("""\ + from __future__ import print_function from TestCommon import TestCommon tc = TestCommon(workdir='') import os - print os.getcwd() + print(os.getcwd()) """) run_env.run(program=sys.executable, stdin=script) stdout = run_env.stdout()[:-1] @@ -2285,14 +2286,16 @@ class variables_TestCase(TestCommonTestCase): 'dll_suffix', ] - script = "import TestCommon\n" + \ - '\n'.join([ "print TestCommon.%s\n" % v for v in variables ]) + script = "from __future__ import print_function" + \ + "import TestCommon\n" + \ + '\n'.join([ "print(TestCommon.%s)\n" % v for v in variables ]) run_env.run(program=sys.executable, stdin=script) stderr = run_env.stderr() assert stderr == "", stderr - script = "from TestCommon import *\n" + \ - '\n'.join([ "print %s" % v for v in variables ]) + script = "from __future__ import print_function" + \ + "from TestCommon import *\n" + \ + '\n'.join([ "print(%s)" % v for v in variables ]) run_env.run(program=sys.executable, stdin=script) stderr = run_env.stderr() assert stderr == "", stderr diff --git a/QMTest/TestRuntest.py b/QMTest/TestRuntest.py index 4ba11ea..f2256de 100644 --- a/QMTest/TestRuntest.py +++ b/QMTest/TestRuntest.py @@ -12,9 +12,9 @@ from those classes, as well as any overridden or additional methods or attributes defined in this subclass. """ -# Copyright (c) 2001 - 2016 The SCons Foundation +# Copyright (c) 2001 - 2017 The SCons Foundation -__revision__ = "QMTest/TestRuntest.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" +__revision__ = "QMTest/TestRuntest.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog" import os import os.path diff --git a/QMTest/TestSCons.py b/QMTest/TestSCons.py index 1161d50..c0b4ebc 100644 --- a/QMTest/TestSCons.py +++ b/QMTest/TestSCons.py @@ -12,16 +12,17 @@ from those classes, as well as any overridden or additional methods or attributes defined in this subclass. """ -# Copyright (c) 2001 - 2016 The SCons Foundation -from __future__ import division +# Copyright (c) 2001 - 2017 The SCons Foundation +from __future__ import division, print_function -__revision__ = "QMTest/TestSCons.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" +__revision__ = "QMTest/TestSCons.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog" import os import re import shutil import sys import time +import subprocess from TestCommon import * from TestCommon import __all__ @@ -34,7 +35,7 @@ from TestCmd import PIPE # here provides some independent verification that what we packaged # conforms to what we expect. -default_version = '2.5.1' +default_version = '3.0.0' python_version_unsupported = (2, 6, 0) python_version_deprecated = (2, 7, 0) @@ -43,21 +44,22 @@ python_version_deprecated = (2, 7, 0) # line must remain "__ VERSION __" (without the spaces) so the built # version in build/QMTest/TestSCons.py contains the actual version # string of the packages that have been built. -SConsVersion = '2.5.1' +SConsVersion = '3.0.0' if SConsVersion == '__' + 'VERSION' + '__': SConsVersion = default_version -__all__.extend([ 'TestSCons', - 'machine', - 'python', - '_exe', - '_obj', - '_shobj', - 'shobj_', - 'lib_', - '_lib', - 'dll_', - '_dll' +__all__.extend([ + 'TestSCons', + 'machine', + 'python', + '_exe', + '_obj', + '_shobj', + 'shobj_', + 'lib_', + '_lib', + 'dll_', + '_dll' ]) machine_map = { @@ -256,7 +258,7 @@ class TestSCons(TestCommon): # TERM can cause test failures due to control chars in prompts etc. os.environ['TERM'] = 'dumb' - self.ignore_python_version = kw.get('ignore_python_version',1) + self.ignore_python_version = kw.get('ignore_python_version', 1) if kw.get('ignore_python_version', -1) != -1: del kw['ignore_python_version'] @@ -268,7 +270,7 @@ class TestSCons(TestCommon): SCons.Node.FS.default_fs = SCons.Node.FS.FS() try: - self.script_srcdir = os.environ['PYTHON_SCRIPT_DIR'] + self.fixture_dirs = (os.environ['FIXTURE_DIRS']).split(os.pathsep) except KeyError: pass @@ -355,7 +357,7 @@ class TestSCons(TestCommon): # raised so as to not mask possibly serious disk or # network issues. continue - if stat.S_IMODE(st[stat.ST_MODE]) & 0111: + if stat.S_IMODE(st[stat.ST_MODE]) & 0o111: return os.path.normpath(f) else: import SCons.Environment @@ -502,9 +504,9 @@ class TestSCons(TestCommon): self.pass_test() else: # test failed; have to do this by hand... - print self.banner('STDOUT ') - print self.stdout() - print self.diff(warning, stderr, 'STDERR ') + print(self.banner('STDOUT ')) + print(self.stdout()) + print(self.diff(warning, stderr, 'STDERR ')) self.fail_test() return warning @@ -562,21 +564,26 @@ class TestSCons(TestCommon): Returns a Python error line for output comparisons. The exec of the traceback line gives us the correct format for - this version of Python. Before 2.5, this yielded: - - File "", line 1, ? - - Python 2.5 changed this to: + this version of Python. File "", line 1, We stick the requested file name and line number in the right places, abstracting out the version difference. """ - exec 'import traceback; x = traceback.format_stack()[-1]' - x = x.lstrip() - x = x.replace('', file) - x = x.replace('line 1,', 'line %s,' % line) + # This routine used to use traceback to get the proper format + # that doesn't work well with py3. And the format of the + # traceback seems to be stable, so let's just format + # an appropriate string + # + #exec('import traceback; x = traceback.format_stack()[-1]') + # import traceback + # x = traceback.format_stack() + # x = # XXX: .lstrip() + # x = x.replace('', file) + # x = x.replace('line 1,', 'line %s,' % line) + # x="\n".join(x) + x='File "%s", line %s, in \n'%(file,line) return x def normalize_ps(self, s): @@ -591,23 +598,33 @@ class TestSCons(TestCommon): return s + @staticmethod + def to_bytes_re_sub(pattern, repl, str, count=0, flags=0): + """ + Wrapper around re.sub to change pattern and repl to bytes to work with + both python 2 & 3 + """ + pattern = to_bytes(pattern) + repl = to_bytes(repl) + return re.sub(pattern, repl, str, count, flags) + def normalize_pdf(self, s): - s = re.sub(r'/(Creation|Mod)Date \(D:[^)]*\)', - r'/\1Date (D:XXXX)', s) - s = re.sub(r'/ID \[<[0-9a-fA-F]*> <[0-9a-fA-F]*>\]', - r'/ID [ ]', s) - s = re.sub(r'/(BaseFont|FontName) /[A-Z]{6}', - r'/\1 /XXXXXX', s) - s = re.sub(r'/Length \d+ *\n/Filter /FlateDecode\n', - r'/Length XXXX\n/Filter /FlateDecode\n', s) + s = self.to_bytes_re_sub(r'/(Creation|Mod)Date \(D:[^)]*\)', + r'/\1Date (D:XXXX)', s) + s = self.to_bytes_re_sub(r'/ID \[<[0-9a-fA-F]*> <[0-9a-fA-F]*>\]', + r'/ID [ ]', s) + s = self.to_bytes_re_sub(r'/(BaseFont|FontName) /[A-Z]{6}', + r'/\1 /XXXXXX', s) + s = self.to_bytes_re_sub(r'/Length \d+ *\n/Filter /FlateDecode\n', + r'/Length XXXX\n/Filter /FlateDecode\n', s) try: import zlib except ImportError: pass else: - begin_marker = '/FlateDecode\n>>\nstream\n' - end_marker = 'endstream\nendobj' + begin_marker = to_bytes('/FlateDecode\n>>\nstream\n') + end_marker = to_bytes('endstream\nendobj') encoded = [] b = s.find(begin_marker, 0) @@ -622,16 +639,16 @@ class TestSCons(TestCommon): for b, e in encoded: r.append(s[x:b]) d = zlib.decompress(s[b:e]) - d = re.sub(r'%%CreationDate: [^\n]*\n', - r'%%CreationDate: 1970 Jan 01 00:00:00\n', d) - d = re.sub(r'%DVIPSSource: TeX output \d\d\d\d\.\d\d\.\d\d:\d\d\d\d', - r'%DVIPSSource: TeX output 1970.01.01:0000', d) - d = re.sub(r'/(BaseFont|FontName) /[A-Z]{6}', - r'/\1 /XXXXXX', d) + d = self.to_bytes_re_sub(r'%%CreationDate: [^\n]*\n', + r'%%CreationDate: 1970 Jan 01 00:00:00\n', d) + d = self.to_bytes_re_sub(r'%DVIPSSource: TeX output \d\d\d\d\.\d\d\.\d\d:\d\d\d\d', + r'%DVIPSSource: TeX output 1970.01.01:0000', d) + d = self.to_bytes_re_sub(r'/(BaseFont|FontName) /[A-Z]{6}', + r'/\1 /XXXXXX', d) r.append(d) x = e r.append(s[x:]) - s = ''.join(r) + s = to_bytes('').join(r) return s @@ -642,6 +659,21 @@ class TestSCons(TestCommon): result.extend(sorted(glob.glob(p))) return result + def unlink_sconsignfile(self,name='.sconsign.dblite'): + """ + Delete sconsign file. + Note on python it seems to append .p3 to the file name so we take care of that + Parameters + ---------- + name - expected name of sconsign file + + Returns + ------- + None + """ + if sys.version_info[0] == 3: + name += '.p3' + self.unlink(name) def java_ENV(self, version=None): """ @@ -685,12 +717,20 @@ class TestSCons(TestCommon): """ Return java include paths compiling java jni code """ - import glob import sys + + result = [] + if sys.platform[:6] == 'darwin': + java_home = self.java_where_java_home(version) + jni_path = os.path.join(java_home,'include','jni.h') + if os.path.exists(jni_path): + result.append(os.path.dirname(jni_path)) + if not version: version='' jni_dirs = ['/System/Library/Frameworks/JavaVM.framework/Headers/jni.h', - '/usr/lib/jvm/default-java/include/jni.h'] + '/usr/lib/jvm/default-java/include/jni.h', + '/usr/lib/jvm/java-*-oracle/include/jni.h'] else: jni_dirs = ['/System/Library/Frameworks/JavaVM.framework/Versions/%s*/Headers/jni.h'%version] jni_dirs.extend(['/usr/lib/jvm/java-*-sun-%s*/include/jni.h'%version, @@ -700,7 +740,7 @@ class TestSCons(TestCommon): if not dirs: return None d=os.path.dirname(self.paths(jni_dirs)[0]) - result=[d] + result.append(d) if sys.platform == 'win32': result.append(os.path.join(d,'win32')) @@ -708,16 +748,34 @@ class TestSCons(TestCommon): result.append(os.path.join(d,'linux')) return result - - def java_where_java_home(self,version=None): + def java_where_java_home(self, version=None): if sys.platform[:6] == 'darwin': + # osx 10.11, 10.12 + home_tool = '/usr/libexec/java_home' + java_home = False + if os.path.exists(home_tool): + java_home = subprocess.check_output(home_tool).strip() + java_home = java_home.decode() + if version is None: - home = '/System/Library/Frameworks/JavaVM.framework/Home' + if java_home: + return java_home + else: + homes = ['/System/Library/Frameworks/JavaVM.framework/Home', + # osx 10.10 + '/System/Library/Frameworks/JavaVM.framework/Versions/Current/Home'] + for home in homes: + if os.path.exists(home): + return home + else: - home = '/System/Library/Frameworks/JavaVM.framework/Versions/%s/Home' % version - if not os.path.exists(home): - # This works on OSX 10.10 - home = '/System/Library/Frameworks/JavaVM.framework/Versions/Current/' + if java_home.find('jdk%s'%version) != -1: + return java_home + else: + home = '/System/Library/Frameworks/JavaVM.framework/Versions/%s/Home' % version + if not os.path.exists(home): + # This works on OSX 10.10 + home = '/System/Library/Frameworks/JavaVM.framework/Versions/Current/' else: jar = self.java_where_jar(version) home = os.path.normpath('%s/..'%jar) @@ -823,12 +881,12 @@ output = None impl = 0 opt_string = '' for opt, arg in cmd_opts: - if opt == '-o': output = open(arg, 'wb') + if opt == '-o': output = open(arg, 'w') elif opt == '-i': impl = 1 else: opt_string = opt_string + ' ' + opt output.write("/* mymoc.py%s */\\n" % opt_string) for a in args: - contents = open(a, 'rb').read() + contents = open(a, 'r').read() a = a.replace('\\\\', '\\\\\\\\') subst = r'{ my_qt_symbol( "' + a + '\\\\n" ); }' if impl: @@ -849,7 +907,7 @@ source = None opt_string = '' for arg in sys.argv[1:]: if output_arg: - output = open(arg, 'wb') + output = open(arg, 'w') output_arg = 0 elif impl_arg: impl = arg @@ -863,7 +921,7 @@ for arg in sys.argv[1:]: else: if source: sys.exit(1) - source = open(arg, 'rb') + source = open(arg, 'r') sourceFile = arg output.write("/* myuic.py%s */\\n" % opt_string) if impl: @@ -936,7 +994,7 @@ if ARGUMENTS.get('variant_dir', 0): else: builddir = 'build' VariantDir(builddir, '.', duplicate=dup) - print builddir, dup + print(builddir, dup) sconscript = Dir(builddir).File('SConscript') else: sconscript = File('SConscript') @@ -958,32 +1016,6 @@ SConscript( sconscript ) # to use cygwin compilers on cmd.exe -> uncomment following line #Configure_lib = 'm' - def gccFortranLibs(self): - """Test which gcc Fortran startup libraries are required. - This should probably move into SCons itself, but is kind of hacky. - """ - if sys.platform.find('irix') != -1: - return ['ftn'] - - libs = ['g2c'] - cmd = ['gcc','-v'] - - try: - p = Popen(cmd, stdout=PIPE, stderr=PIPE) - stdout, stderr = p.communicate() - except: - return libs - - m = re.search('(gcc\s+version|gcc-Version)\s+(\d\.\d)', stderr) - if m: - gcc_version = m.group(2) - if re.match('4.[^0]', gcc_version): - libs = ['gfortranbegin'] - elif gcc_version in ('3.1', '4.0'): - libs = ['frtbegin'] + libs - - return libs - def skip_if_not_msvc(self, check_platform=True): """ Check whether we are on a Windows platform and skip the test if not. This check can be omitted by setting @@ -1009,53 +1041,113 @@ SConscript( sconscript ) def checkLogAndStdout(self, checks, results, cached, logfile, sconf_dir, sconstruct, - doCheckLog=1, doCheckStdout=1): + doCheckLog=True, doCheckStdout=True): + """ + Used to verify the expected output from using Configure() + via the contents of one or both of stdout or config.log file. + The checks, results, cached parameters all are zipped together + for use in comparing results. + + TODO: Perhaps a better API makes sense? + + Parameters + ---------- + checks : The Configure checks being run + + results : The expected results for each check + + cached : If the corresponding check is expected to be cached + + logfile : Name of the config log + + sconf_dir : Name of the sconf dir + + sconstruct : SConstruct file name + + doCheckLog : check specified log file, defaults to true + + doCheckStdout : Check stdout, defaults to true + + Returns + ------- + + """ class NoMatch(Exception): def __init__(self, p): self.pos = p def matchPart(log, logfile, lastEnd, NoMatch=NoMatch): + """ + Match part of the logfile + """ m = re.match(log, logfile[lastEnd:]) if not m: raise NoMatch(lastEnd) return m.end() + lastEnd + try: - #print len(os.linesep) - ls = os.linesep - nols = "(" - for i in range(len(ls)): - nols = nols + "(" - for j in range(i): - nols = nols + ls[j] - nols = nols + "[^" + ls[i] + "])" - if i < len(ls)-1: - nols = nols + "|" - nols = nols + ")" + + # Build regexp for a character which is not + # a linesep, and in the case of CR/LF + # build it with both CR and CR/LF + # TODO: Not sure why this is a good idea. A static string + # could do the same since we only have two variations + # to do with? + # ls = os.linesep + # nols = "(" + # for i in range(len(ls)): + # nols = nols + "(" + # for j in range(i): + # nols = nols + ls[j] + # nols = nols + "[^" + ls[i] + "])" + # if i < len(ls)-1: + # nols = nols + "|" + # nols = nols + ")" + # + # Replaced above logic with \n as we're reading the file + # using non-binary read. Python will translate \r\n -> \n + # For us. + ls = '\n' + nols = '([^\n])' lastEnd = 0 - logfile = self.read(self.workpath(logfile)) + + # Read the whole logfile + logfile = self.read(self.workpath(logfile), mode='r') + + # Some debug code to keep around.. + # sys.stderr.write("LOGFILE[%s]:%s"%(type(logfile),logfile)) + if (doCheckLog and - logfile.find( "scons: warning: The stored build " - "information has an unexpected class." ) >= 0): + logfile.find("scons: warning: The stored build information has an unexpected class.") >= 0): self.fail_test() + sconf_dir = sconf_dir sconstruct = sconstruct log = r'file\ \S*%s\,line \d+:' % re.escape(sconstruct) + ls - if doCheckLog: lastEnd = matchPart(log, logfile, lastEnd) + if doCheckLog: + lastEnd = matchPart(log, logfile, lastEnd) + log = "\t" + re.escape("Configure(confdir = %s)" % sconf_dir) + ls - if doCheckLog: lastEnd = matchPart(log, logfile, lastEnd) + if doCheckLog: + lastEnd = matchPart(log, logfile, lastEnd) + rdstr = "" cnt = 0 for check,result,cache_desc in zip(checks, results, cached): log = re.escape("scons: Configure: " + check) + ls - if doCheckLog: lastEnd = matchPart(log, logfile, lastEnd) + + if doCheckLog: + lastEnd = matchPart(log, logfile, lastEnd) + log = "" result_cached = 1 for bld_desc in cache_desc: # each TryXXX for ext, flag in bld_desc: # each file in TryBuild file = os.path.join(sconf_dir,"conftest_%d%s" % (cnt, ext)) if flag == self.NCR: + # NCR = Non Cached Rebuild # rebuild will pass if ext in ['.c', '.cpp']: log=log + re.escape(file + " <-") + ls @@ -1064,6 +1156,7 @@ SConscript( sconscript ) log=log + "(" + nols + "*" + ls +")*?" result_cached = 0 if flag == self.CR: + # CR = cached rebuild (up to date)s # up to date log=log + \ re.escape("scons: Configure: \"%s\" is up to date." @@ -1089,33 +1182,36 @@ SConscript( sconscript ) result = "(cached) " + result rdstr = rdstr + re.escape(check) + re.escape(result) + "\n" log=log + re.escape("scons: Configure: " + result) + ls + ls - if doCheckLog: lastEnd = matchPart(log, logfile, lastEnd) + + if doCheckLog: + lastEnd = matchPart(log, logfile, lastEnd) + log = "" if doCheckLog: lastEnd = matchPart(ls, logfile, lastEnd) if doCheckLog and lastEnd != len(logfile): raise NoMatch(lastEnd) - except NoMatch, m: - print "Cannot match log file against log regexp." - print "log file: " - print "------------------------------------------------------" - print logfile[m.pos:] - print "------------------------------------------------------" - print "log regexp: " - print "------------------------------------------------------" - print log - print "------------------------------------------------------" + except NoMatch as m: + print("Cannot match log file against log regexp.") + print("log file: ") + print("------------------------------------------------------") + print(logfile[m.pos:]) + print("------------------------------------------------------") + print("log regexp: ") + print("------------------------------------------------------") + print(log) + print("------------------------------------------------------") self.fail_test() if doCheckStdout: exp_stdout = self.wrap_stdout(".*", rdstr) if not self.match_re_dotall(self.stdout(), exp_stdout): - print "Unexpected stdout: " - print "-----------------------------------------------------" - print repr(self.stdout()) - print "-----------------------------------------------------" - print repr(exp_stdout) - print "-----------------------------------------------------" + print("Unexpected stdout: ") + print("-----------------------------------------------------") + print(repr(self.stdout())) + print("-----------------------------------------------------") + print(repr(exp_stdout)) + print("-----------------------------------------------------") self.fail_test() def get_python_version(self): @@ -1149,12 +1245,15 @@ except AttributeError: try: import distutils.sysconfig exec_prefix = distutils.sysconfig.EXEC_PREFIX - print distutils.sysconfig.get_python_inc() - print os.path.join(exec_prefix, 'libs') + print(distutils.sysconfig.get_python_inc()) + lib_path = os.path.join(exec_prefix, 'libs') + if not os.path.exists(lib_path): + lib_path = os.path.join(exec_prefix, 'lib') + print(lib_path) except: - print os.path.join(sys.prefix, 'include', py_ver) - print os.path.join(sys.prefix, 'lib', py_ver, 'config') -print py_ver + print(os.path.join(sys.prefix, 'include', py_ver)) + print(os.path.join(sys.prefix, 'lib', py_ver, 'config')) +print(py_ver) """) return [python] + self.stdout().strip().split('\n') @@ -1214,6 +1313,12 @@ print py_ver alt_cpp_suffix = '.C' return alt_cpp_suffix + def platform_has_symlink(self): + if not hasattr(os, 'symlink') or sys.platform == 'win32': + return False + else: + return True + class Stat: def __init__(self, name, units, expression, convert=None): diff --git a/QMTest/TestSConsMSVS.py b/QMTest/TestSConsMSVS.py index 537ba17..30eea76 100644 --- a/QMTest/TestSConsMSVS.py +++ b/QMTest/TestSConsMSVS.py @@ -13,13 +13,15 @@ as well as any overridden or additional methods or attributes defined in this subclass. """ -# Copyright (c) 2001 - 2016 The SCons Foundation +# Copyright (c) 2001 - 2017 The SCons Foundation -__revision__ = "QMTest/TestSConsMSVS.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" +__revision__ = "QMTest/TestSConsMSVS.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog" import os import sys import platform +import traceback +from xml.etree import ElementTree from TestSCons import * from TestSCons import __all__ @@ -1037,8 +1039,8 @@ class TestSConsMSVS(TestSCons): input = """\ import SCons import SCons.Tool.MSCommon -print "self.scons_version =", repr(SCons.__%s__) -print "self._msvs_versions =", str(SCons.Tool.MSCommon.query_versions()) +print("self.scons_version =", repr(SCons.__%s__)) +print("self._msvs_versions =", str(SCons.Tool.MSCommon.query_versions())) """ % 'version' self.run(arguments = '-n -q -Q -f -', stdin = input) @@ -1054,7 +1056,7 @@ print "self._msvs_versions =", str(SCons.Tool.MSCommon.query_versions()) enginepath = repr(os.path.join(self._cwd, '..', 'engine')) replace = 'sys.path = [ %s, join(sys' % enginepath - contents = self.read(fname) + contents = self.read(fname, mode='r') contents = contents.replace(orig, replace) self.write(fname, contents) @@ -1149,13 +1151,25 @@ print "self._msvs_versions =", str(SCons.Tool.MSCommon.query_versions()) try: host = _ARCH_TO_CANONICAL[host_platform] - except KeyError, e: + except KeyError as e: # Default to x86 for all other platforms host = 'x86' return host + def validate_msvs_file(self, file): + try: + x = ElementTree.parse(file) + except: + print("--------------------------------------------------------------") + print("--------------------------------------------------------------") + print(traceback.format_exc()) + print("Failed to validate xml in MSVS file: ") + print(file) + print("--------------------------------------------------------------") + print("--------------------------------------------------------------") + self.fail_test() # Local Variables: # tab-width:4 # indent-tabs-mode:nil diff --git a/QMTest/TestSCons_time.py b/QMTest/TestSCons_time.py index e84f7dc..f74906a 100644 --- a/QMTest/TestSCons_time.py +++ b/QMTest/TestSCons_time.py @@ -11,9 +11,9 @@ from those classes, as well as any overridden or additional methods or attributes defined in this subclass. """ -# Copyright (c) 2001 - 2016 The SCons Foundation +# Copyright (c) 2001 - 2017 The SCons Foundation -__revision__ = "QMTest/TestSCons_time.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" +__revision__ = "QMTest/TestSCons_time.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog" import os import os.path @@ -28,8 +28,9 @@ __all__.extend([ 'TestSCons_time', ]) SConstruct = """\ +from __future__ import print_function import os -print "SConstruct file directory:", os.getcwd() +print("SConstruct file directory:", os.getcwd()) """ scons_py = """\ @@ -43,12 +44,12 @@ def write_args(fp, args): write_args(sys.stdout, sys.argv) for arg in sys.argv[1:]: if arg[:10] == '--profile=': - profile = open(arg[10:], 'wb') + profile = open(arg[10:], 'w') profile.write('--profile\\n') write_args(profile, sys.argv) break sys.stdout.write('SCONS_LIB_DIR = ' + os.environ['SCONS_LIB_DIR'] + '\\n') -exec(open('SConstruct', 'rU').read()) +exec(open('SConstruct', 'r').read()) """ aegis_py = """\ @@ -225,7 +226,7 @@ class TestSCons_time(TestCommon): def write_fake_aegis_py(self, name): name = self.workpath(name) self.write(name, aegis_py) - os.chmod(name, 0755) + os.chmod(name, 0o755) return name def write_fake_scons_py(self): @@ -235,7 +236,7 @@ class TestSCons_time(TestCommon): def write_fake_svn_py(self, name): name = self.workpath(name) self.write(name, svn_py) - os.chmod(name, 0755) + os.chmod(name, 0o755) return name def write_sample_directory(self, archive, dir, files): @@ -245,7 +246,7 @@ class TestSCons_time(TestCommon): d, f = os.path.split(path) if not os.path.isdir(d): os.makedirs(d) - open(path, 'wb').write(content) + open(path, 'w').write(content) return dir def write_sample_tarfile(self, archive, dir, files): @@ -270,7 +271,7 @@ class TestSCons_time(TestCommon): tar = tarfile.open(archive, mode[suffix]) for name, content in files: path = os.path.join(dir, name) - open(path, 'wb').write(content) + open(path, 'wb').write(bytearray(content,'utf-8')) tarinfo = tar.gettarinfo(path, path) tarinfo.uid = 111 tarinfo.gid = 111 @@ -295,7 +296,7 @@ class TestSCons_time(TestCommon): zip = zipfile.ZipFile(archive, 'w') for name, content in files: path = os.path.join(dir, name) - open(path, 'wb').write(content) + open(path, 'w').write(content) zip.write(path) zip.close() shutil.rmtree(dir) diff --git a/QMTest/TestSConsign.py b/QMTest/TestSConsign.py index 2016afc..df34aa8 100644 --- a/QMTest/TestSConsign.py +++ b/QMTest/TestSConsign.py @@ -1,6 +1,7 @@ -# Copyright (c) 2001 - 2016 The SCons Foundation +# Copyright (c) 2001 - 2017 The SCons Foundation +from __future__ import print_function -__revision__ = "QMTest/TestSConsign.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" +__revision__ = "QMTest/TestSConsign.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog" __doc__ = """ TestSConsign.py: a testing framework for the "sconsign" script @@ -68,7 +69,7 @@ class TestSConsign(TestSCons): elif os.path.exists(self.script_path('sconsign')): sconsign = 'sconsign' else: - print "Can find neither 'sconsign.py' nor 'sconsign' scripts." + print("Can find neither 'sconsign.py' nor 'sconsign' scripts.") self.no_result() self.set_sconsign(sconsign) diff --git a/QMTest/scons_tdb.py b/QMTest/scons_tdb.py index 18e6a59..c3b082f 100644 --- a/QMTest/scons_tdb.py +++ b/QMTest/scons_tdb.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -# Copyright (c) 2001 - 2016 The SCons Foundation +# Copyright (c) 2001 - 2017 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -20,7 +20,7 @@ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -from __future__ import division +from __future__ import division, print_function """ QMTest classes to support SCons' testing and Aegis-inspired workflow. @@ -28,7 +28,7 @@ QMTest classes to support SCons' testing and Aegis-inspired workflow. Thanks to Stefan Seefeld for the initial code. """ -__revision__ = "QMTest/scons_tdb.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" +__revision__ = "QMTest/scons_tdb.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog" ######################################################################## # Imports @@ -337,14 +337,14 @@ class AegisChangeStream(AegisStream): # We'd like to use the _FormatStatistics() method to do # this, but it's wrapped around the list in Result.outcomes, # so it's simpler to just do it ourselves. - print " %6d tests total\n" % self._num_tests + print(" %6d tests total\n" % self._num_tests) for outcome in AegisTest.aegis_outcomes: if self._outcome_counts[outcome] != 0: - print " %6d (%3.0f%%) tests %s" % ( + print(" %6d (%3.0f%%) tests %s" % ( self._outcome_counts[outcome], self._percent(outcome), outcome - ) + )) class AegisBaselineStream(AegisStream): def WriteResult(self, result): @@ -368,19 +368,19 @@ class AegisBaselineStream(AegisStream): # this, but it's wrapped around the list in Result.outcomes, # so it's simpler to just do it ourselves. if self._outcome_counts[AegisTest.FAIL]: - print " %6d (%3.0f%%) tests as expected" % ( + print(" %6d (%3.0f%%) tests as expected" % ( self._outcome_counts[AegisTest.FAIL], self._percent(AegisTest.FAIL), - ) + )) non_fail_outcomes = list(AegisTest.aegis_outcomes[:]) non_fail_outcomes.remove(AegisTest.FAIL) for outcome in non_fail_outcomes: if self._outcome_counts[outcome] != 0: - print " %6d (%3.0f%%) tests unexpected %s" % ( + print(" %6d (%3.0f%%) tests unexpected %s" % ( self._outcome_counts[outcome], self._percent(outcome), outcome, - ) + )) class AegisBatchStream(FileResultStream): def __init__(self, arguments): diff --git a/README.rst b/README.rst index ca1b081..258d6a1 100644 --- a/README.rst +++ b/README.rst @@ -168,7 +168,7 @@ Or on Windows:: By default, the above commands will do the following: -- Install the version-numbered "scons-2.5.1" and "sconsign-2.5.1" scripts in +- Install the version-numbered "scons-3.0.0" and "sconsign-3.0.0" scripts in the default system script directory (/usr/bin or C:\\Python\*\\Scripts, for example). This can be disabled by specifying the "--no-version-script" option on the command line. @@ -180,23 +180,23 @@ By default, the above commands will do the following: before making it the default on your system. On UNIX or Linux systems, you can have the "scons" and "sconsign" scripts be - hard links or symbolic links to the "scons-2.5.1" and "sconsign-2.5.1" + hard links or symbolic links to the "scons-3.0.0" and "sconsign-3.0.0" scripts by specifying the "--hardlink-scons" or "--symlink-scons" options on the command line. -- Install "scons-2.5.1.bat" and "scons.bat" wrapper scripts in the Python +- Install "scons-3.0.0.bat" and "scons.bat" wrapper scripts in the Python prefix directory on Windows (C:\\Python\*, for example). This can be disabled by specifying the "--no-install-bat" option on the command line. On UNIX or Linux systems, the "--install-bat" option may be specified to - have "scons-2.5.1.bat" and "scons.bat" files installed in the default system + have "scons-3.0.0.bat" and "scons.bat" files installed in the default system script directory, which is useful if you want to install SCons in a shared file system directory that can be used to execute SCons from both UNIX/Linux and Windows systems. - Install the SCons build engine (a Python module) in an appropriate - version-numbered SCons library directory (/usr/lib/scons-2.5.1 or - C:\\Python\*\\scons-2.5.1, for example). See below for more options related to + version-numbered SCons library directory (/usr/lib/scons-3.0.0 or + C:\\Python\*\\scons-3.0.0, for example). See below for more options related to installing the build engine library. - Install the troff-format man pages in an appropriate directory on UNIX or @@ -474,7 +474,7 @@ running all of "runtest.py -a". Building Packages ================= -We use SCons (version 2.5.1 or later) to build its own packages. If you +We use SCons (version 3.0.0 or later) to build its own packages. If you already have an appropriate version of SCons installed on your system, you can build everything by simply running it:: @@ -489,18 +489,18 @@ about `Executing SCons Without Installing`_):: Depending on the utilities installed on your system, any or all of the following packages will be built:: - build/dist/scons-2.5.1-1.noarch.rpm - build/dist/scons-2.5.1-1.src.rpm - build/dist/scons-2.5.1.linux-i686.tar.gz - build/dist/scons-2.5.1.tar.gz - build/dist/scons-2.5.1.win32.exe - build/dist/scons-2.5.1.zip - build/dist/scons-doc-2.5.1.tar.gz - build/dist/scons-local-2.5.1.tar.gz - build/dist/scons-local-2.5.1.zip - build/dist/scons-src-2.5.1.tar.gz - build/dist/scons-src-2.5.1.zip - build/dist/scons_2.5.1-1_all.deb + build/dist/scons-3.0.0-1.noarch.rpm + build/dist/scons-3.0.0-1.src.rpm + build/dist/scons-3.0.0.linux-i686.tar.gz + build/dist/scons-3.0.0.tar.gz + build/dist/scons-3.0.0.win32.exe + build/dist/scons-3.0.0.zip + build/dist/scons-doc-3.0.0.tar.gz + build/dist/scons-local-3.0.0.tar.gz + build/dist/scons-local-3.0.0.zip + build/dist/scons-src-3.0.0.tar.gz + build/dist/scons-src-3.0.0.zip + build/dist/scons_3.0.0-1_all.deb The SConstruct file is supposed to be smart enough to avoid trying to build packages for which you don't have the proper utilities installed. For @@ -664,7 +664,7 @@ section of small examples for getting started using SCons. Additional documentation for SCons is available at: - http://www.scons.org/documentation.php + http://www.scons.org/documentation Licensing @@ -724,7 +724,7 @@ If you find SCons helpful, please consider making a donation (of cash, software, or hardware) to support continued work on the project. Information is available at: - http://www.scons.org/donate.php + http://www.scons.org/donate.html For More Information @@ -760,5 +760,5 @@ many contributors, including but not at all limited to: \... and many others. -Copyright (c) 2001 - 2015 The SCons Foundation +Copyright (c) 2001 - 2017 The SCons Foundation diff --git a/SConstruct b/SConstruct index 16d01d2..68f9e3f 100644 --- a/SConstruct +++ b/SConstruct @@ -3,13 +3,15 @@ # # See the README.rst file for an overview of how SCons is built and tested. -copyright_years = '2001 - 2016' +from __future__ import print_function + +copyright_years = '2001 - 2017' # This gets inserted into the man pages to reflect the month of release. -month_year = 'November 2016' +month_year = 'September 2017' # -# Copyright (c) 2001 - 2016 The SCons Foundation +# Copyright (c) 2001 - 2017 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -39,11 +41,12 @@ import re import stat import sys import tempfile +import time import bootstrap project = 'scons' -default_version = '2.5.1' +default_version = '3.0.0' copyright = "Copyright (c) %s The SCons Foundation" % copyright_years platform = distutils.util.get_platform() @@ -53,7 +56,7 @@ def is_windows(): return True else: return False - + SConsignFile() # @@ -73,7 +76,7 @@ def whereis(file): st = os.stat(f_ext) except: continue - if stat.S_IMODE(st[stat.ST_MODE]) & 0111: + if stat.S_IMODE(st[stat.ST_MODE]) & 0o111: return f_ext return None @@ -96,9 +99,13 @@ zip = whereis('zip') # date = ARGUMENTS.get('DATE') if not date: - import time date = time.strftime("%Y/%m/%d %H:%M:%S", time.localtime(time.time())) +# Datestring for debian +# Should look like: Mon, 03 Nov 2016 13:37:42 -0700 +deb_date = time.strftime("%a, %d %b %Y %H:%M:%S +0000", time.gmtime()) + + developer = ARGUMENTS.get('DEVELOPER') if not developer: for variable in ['USERNAME', 'LOGNAME', 'USER']: @@ -160,8 +167,17 @@ import distutils.command no_winpack_templates = not os.path.exists(os.path.join(os.path.split(distutils.command.__file__)[0],'wininst-9.0.exe')) skip_win_packages = ARGUMENTS.get('SKIP_WIN_PACKAGES',False) or no_winpack_templates + +if sys.version_info[0] > 2: + # TODO: Resolve this issue. Currently fails when run on windows with + # File "/opt/local/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/distutils/command/bdist_wininst.py", line 262, in create_exe + # cfgdata = cfgdata.encode("mbcs") + # LookupError: unknown encoding: mbcs + print("Temporary PY3: Skipping windows package builds") + skip_win_packages = True + if skip_win_packages: - print "Skipping the build of Windows packages..." + print("Skipping the build of Windows packages...") python_ver = sys.version[0:3] @@ -324,22 +340,25 @@ try: import zipfile def zipit(env, target, source): - print "Zipping %s:" % str(target[0]) - def visit(arg, dirname, names): - for name in names: - path = os.path.join(dirname, name) + print("Zipping %s:" % str(target[0])) + def visit(arg, dirname, filenames): + for filename in filenames: + path = os.path.join(dirname, filename) if os.path.isfile(path): arg.write(path) # default ZipFile compression is ZIP_STORED zf = zipfile.ZipFile(str(target[0]), 'w', compression=zipfile.ZIP_DEFLATED) olddir = os.getcwd() os.chdir(env['CD']) - try: os.path.walk(env['PSV'], visit, zf) - finally: os.chdir(olddir) + try: + for dirname, dirnames, filenames in os.walk(env['PSV']): + visit(zf, dirname, filenames) + finally: + os.chdir(olddir) zf.close() def unzipit(env, target, source): - print "Unzipping %s:" % str(source[0]) + print("Unzipping %s:" % str(source[0])) zf = zipfile.ZipFile(str(source[0]), 'r') for name in zf.namelist(): dest = os.path.join(env['UNPACK_ZIP_DIR'], name) @@ -348,19 +367,21 @@ try: os.makedirs(dir) except: pass - print dest,name + print(dest,name) # if the file exists, then delete it before writing # to it so that we don't end up trying to write to a symlink: if os.path.isfile(dest) or os.path.islink(dest): os.unlink(dest) if not os.path.isdir(dest): - open(dest, 'wb').write(zf.read(name)) + with open(dest, 'wb') as fp: + fp.write(zf.read(name)) except ImportError: if unzip and zip: zipit = "cd $CD && $ZIP $ZIPFLAGS $( ${TARGET.abspath} $) $PSV" unzipit = "$UNZIP $UNZIPFLAGS $SOURCES" + def SCons_revision(target, source, env): """Interpolate specific values from the environment into a file. @@ -369,23 +390,38 @@ def SCons_revision(target, source, env): """ t = str(target[0]) s = source[0].rstr() - contents = open(s, 'rb').read() - # Note: We construct the __*__ substitution strings here - # so that they don't get replaced when this file gets - # copied into the tree for packaging. - contents = contents.replace('__BUILD' + '__', env['BUILD']) - contents = contents.replace('__BUILDSYS' + '__', env['BUILDSYS']) - contents = contents.replace('__COPYRIGHT' + '__', env['COPYRIGHT']) - contents = contents.replace('__DATE' + '__', env['DATE']) - contents = contents.replace('__DEVELOPER' + '__', env['DEVELOPER']) - contents = contents.replace('__FILE' + '__', str(source[0]).replace('\\', '/')) - contents = contents.replace('__MONTH_YEAR'+ '__', env['MONTH_YEAR']) - contents = contents.replace('__REVISION' + '__', env['REVISION']) - contents = contents.replace('__VERSION' + '__', env['VERSION']) - contents = contents.replace('__NULL' + '__', '') - open(t, 'wb').write(contents) + + try: + with open(s, 'r') as fp: + contents = fp.read() + + + # Note: We construct the __*__ substitution strings here + # so that they don't get replaced when this file gets + # copied into the tree for packaging. + contents = contents.replace('__BUILD' + '__', env['BUILD']) + contents = contents.replace('__BUILDSYS' + '__', env['BUILDSYS']) + contents = contents.replace('__COPYRIGHT' + '__', env['COPYRIGHT']) + contents = contents.replace('__DATE' + '__', env['DATE']) + contents = contents.replace('__DEB_DATE' + '__', env['DEB_DATE']) + + contents = contents.replace('__DEVELOPER' + '__', env['DEVELOPER']) + contents = contents.replace('__FILE' + '__', str(source[0]).replace('\\', '/')) + contents = contents.replace('__MONTH_YEAR'+ '__', env['MONTH_YEAR']) + contents = contents.replace('__REVISION' + '__', env['REVISION']) + contents = contents.replace('__VERSION' + '__', env['VERSION']) + contents = contents.replace('__NULL' + '__', '') + open(t, 'w').write(contents) + except UnicodeDecodeError as e: + print("Error decoding file:%s just copying no revision edit") + with open(s, 'rb') as fp: + contents = fp.read() + open(t, 'wb').write(contents) + + os.chmod(t, os.stat(s)[0]) + revaction = SCons_revision revbuilder = Builder(action = Action(SCons_revision, varlist=['COPYRIGHT', 'VERSION'])) @@ -434,12 +470,12 @@ env = Environment( BUILDSYS = build_system, COPYRIGHT = copyright, DATE = date, + DEB_DATE = deb_date, DEVELOPER = developer, DISTDIR = os.path.join(build_dir, 'dist'), MONTH_YEAR = month_year, REVISION = revision, VERSION = version, - DH_COMPAT = 2, TAR_HFLAG = tar_hflag, @@ -499,7 +535,8 @@ python_scons = { 'debian_deps' : [ 'debian/changelog', - 'debian/control', + 'debian/compat', + 'debian/control', 'debian/copyright', 'debian/dirs', 'debian/docs', @@ -559,7 +596,7 @@ else: i = install_egg_info(dist) i.finalize_options() import os.path - print os.path.split(i.outputs[0])[1] + print(os.path.split(i.outputs[0])[1]) """ % version try: @@ -576,43 +613,6 @@ finally: except EnvironmentError: pass -# -# The original packaging scheme would have have required us to push -# the Python version number into the package name (python1.5-scons, -# python2.0-scons, etc.), which would have required a definition -# like the following. Leave this here in case we ever decide to do -# this in the future, but note that this would require some modification -# to src/engine/setup.py before it would really work. -# -#python2_scons = { -# 'pkg' : 'python2-' + project, -# 'src_subdir' : 'engine', -# 'inst_subdir' : os.path.join('lib', 'python2.2', 'site-packages'), -# -# 'debian_deps' : [ -# 'debian/changelog', -# 'debian/control', -# 'debian/copyright', -# 'debian/dirs', -# 'debian/docs', -# 'debian/postinst', -# 'debian/prerm', -# 'debian/rules', -# ], -# -# 'files' : [ -# 'LICENSE.txt', -# 'README.txt', -# 'setup.cfg', -# 'setup.py', -# ], -# 'filemap' : { -# 'LICENSE.txt' : '../LICENSE.txt', -# }, -# 'buildermap' : {}, -#} -# - scons_script = { 'pkg' : project + '-script', 'src_subdir' : 'script', @@ -621,6 +621,7 @@ scons_script = { 'debian_deps' : [ 'debian/changelog', + 'debian/compat', 'debian/control', 'debian/copyright', 'debian/dirs', @@ -665,6 +666,7 @@ scons = { 'debian_deps' : [ 'debian/changelog', + 'debian/compat', 'debian/control', 'debian/copyright', 'debian/dirs', @@ -734,7 +736,7 @@ for p in [ scons ]: platform_zip = os.path.join(build, 'dist', "%s.%s.zip" % (pkg_version, platform)) - + # # Update the environment with the relevant information @@ -774,11 +776,16 @@ for p in [ scons ]: for sp in p['subpkgs']: ssubdir = sp['src_subdir'] isubdir = p['subinst_dirs'][sp['pkg']] + + MANIFEST_in = File(os.path.join(src, ssubdir, 'MANIFEST.in')).rstr() MANIFEST_in_list.append(MANIFEST_in) files = bootstrap.parseManifestLines(os.path.join(src, ssubdir), open(MANIFEST_in).readlines()) + raw_files.extend(files) src_files.extend([os.path.join(ssubdir, x) for x in files]) + + for f in files: r = os.path.join(sp['rpm_dir'], f) rpm_files.append(r) @@ -807,14 +814,16 @@ for p in [ scons ]: # # Now run everything in src_file through the sed command we - # concocted to expand SConstruct, 2.5.1, etc. + # concocted to expand SConstruct, 3.0.0, etc. # for b in src_files: s = p['filemap'].get(b, b) if not s[0] == '$' and not os.path.isabs(s): s = os.path.join(src, s) + builder = p['buildermap'].get(b, env.SCons_revision) x = builder(os.path.join(build, b), s) + Local(x) # @@ -829,7 +838,7 @@ for p in [ scons ]: def write_src_files(target, source, **kw): global src_files src_files.sort() - f = open(str(target[0]), 'wb') + f = open(str(target[0]), 'w') for file in src_files: f.write(file + "\n") f.close() @@ -856,11 +865,11 @@ for p in [ scons ]: for target in distutils_targets: dist_target = env.Install('$DISTDIR', target) - AddPostAction(dist_target, Chmod(dist_target, 0644)) + AddPostAction(dist_target, Chmod(dist_target, 0o644)) dist_distutils_targets += dist_target if not gzip: - print "gzip not found in %s; skipping .tar.gz package for %s." % (os.environ['PATH'], pkg) + print("gzip not found in %s; skipping .tar.gz package for %s." % (os.environ['PATH'], pkg)) else: distutils_formats.append('gztar') @@ -872,8 +881,8 @@ for p in [ scons ]: dist_tar_gz = env.Install('$DISTDIR', tar_gz) dist_platform_tar_gz = env.Install('$DISTDIR', platform_tar_gz) Local(dist_tar_gz, dist_platform_tar_gz) - AddPostAction(dist_tar_gz, Chmod(dist_tar_gz, 0644)) - AddPostAction(dist_platform_tar_gz, Chmod(dist_platform_tar_gz, 0644)) + AddPostAction(dist_tar_gz, Chmod(dist_tar_gz, 0o644)) + AddPostAction(dist_platform_tar_gz, Chmod(dist_platform_tar_gz, 0o644)) # # Unpack the tar.gz archive created by the distutils into @@ -923,11 +932,14 @@ for p in [ scons ]: ebuild = os.path.join(gentoo, 'scons-%s.ebuild' % version) digest = os.path.join(gentoo, 'files', 'digest-scons-%s' % version) env.Command(ebuild, os.path.join('gentoo', 'scons.ebuild.in'), SCons_revision) + def Digestify(target, source, env): - import md5 + import hashlib src = source[0].rfile() - contents = open(str(src)).read() - sig = md5.new(contents).hexdigest() + contents = open(str(src),'rb').read() + m = hashlib.md5() + m.update(contents) + sig = m.hexdigest() bytes = os.stat(str(src))[6] open(str(target[0]), 'w').write("MD5 %s %s %d\n" % (sig, src.name, @@ -935,7 +947,7 @@ for p in [ scons ]: env.Command(digest, tar_gz, Digestify) if not zipit: - print "zip not found; skipping .zip package for %s." % pkg + print("zip not found; skipping .zip package for %s." % pkg) else: distutils_formats.append('zip') @@ -947,8 +959,8 @@ for p in [ scons ]: dist_zip = env.Install('$DISTDIR', zip) dist_platform_zip = env.Install('$DISTDIR', platform_zip) Local(dist_zip, dist_platform_zip) - AddPostAction(dist_zip, Chmod(dist_zip, 0644)) - AddPostAction(dist_platform_zip, Chmod(dist_platform_zip, 0644)) + AddPostAction(dist_zip, Chmod(dist_zip, 0o644)) + AddPostAction(dist_platform_zip, Chmod(dist_platform_zip, 0o644)) # # Unpack the zip archive created by the distutils into @@ -1011,10 +1023,10 @@ for p in [ scons ]: list generated from our MANIFEST(s), so we don't have to maintain multiple lists. """ - c = open(str(source[0]), 'rb').read() + c = open(str(source[0]), 'r').read() c = c.replace('__VERSION' + '__', env['VERSION']) c = c.replace('__RPM_FILES' + '__', env['RPM_FILES']) - open(str(target[0]), 'wb').write(c) + open(str(target[0]), 'w').write(c) rpm_files.sort() rpm_files_str = "\n".join(rpm_files) + "\n" @@ -1035,8 +1047,8 @@ for p in [ scons ]: dist_noarch_rpm = env.Install('$DISTDIR', noarch_rpm) dist_src_rpm = env.Install('$DISTDIR', src_rpm) Local(dist_noarch_rpm, dist_src_rpm) - AddPostAction(dist_noarch_rpm, Chmod(dist_noarch_rpm, 0644)) - AddPostAction(dist_src_rpm, Chmod(dist_src_rpm, 0644)) + AddPostAction(dist_noarch_rpm, Chmod(dist_noarch_rpm, 0o644)) + AddPostAction(dist_src_rpm, Chmod(dist_src_rpm, 0o644)) dfiles = [os.path.join(test_rpm_dir, 'usr', x) for x in dst_files] env.Command(dfiles, @@ -1047,9 +1059,9 @@ for p in [ scons ]: # Our Debian packaging builds directly into build/dist, # so we don't need to Install() the .debs. # The built deb is called just x.y.z, not x.y.z.final.0 so strip those off: - deb_version = '.'.join(version.split('.')[0:3]) + deb_version = version #'.'.join(version.split('.')[0:3]) deb = os.path.join(build_dir, 'dist', "%s_%s_all.deb" % (pkg, deb_version)) - # print "Building deb into %s (version=%s)"%(deb, deb_version) + print("Building deb into %s (version=%s)"%(deb, deb_version)) for d in p['debian_deps']: b = env.SCons_revision(os.path.join(build, d), d) env.Depends(deb, b) @@ -1109,8 +1121,8 @@ for p in [ scons ]: dist_local_tar_gz = os.path.join("$DISTDIR/%s.tar.gz" % s_l_v) dist_local_zip = os.path.join("$DISTDIR/%s.zip" % s_l_v) - AddPostAction(dist_local_tar_gz, Chmod(dist_local_tar_gz, 0644)) - AddPostAction(dist_local_zip, Chmod(dist_local_zip, 0644)) + AddPostAction(dist_local_tar_gz, Chmod(dist_local_tar_gz, 0o644)) + AddPostAction(dist_local_zip, Chmod(dist_local_zip, 0o644)) commands = [ Delete(build_dir_local), @@ -1220,7 +1232,7 @@ if hg_status_lines: slines = [l for l in hg_status_lines if l[0] in 'ACM'] sfiles = [l.split()[-1] for l in slines] else: - print "Not building in a Mercurial tree; skipping building src package." + print("Not building in a Mercurial tree; skipping building src package.") if sfiles: remove_patterns = [ @@ -1247,7 +1259,11 @@ if sfiles: Local(src_tar_gz, src_zip) for file in sfiles: - env.SCons_revision(os.path.join(b_ps, file), file) + if file.endswith('jpg') or file.endswith('png'): + # don't revision binary files. + env.Install(os.path.dirname(os.path.join(b_ps,file)), file) + else: + env.SCons_revision(os.path.join(b_ps, file), file) b_ps_files = [os.path.join(b_ps, x) for x in sfiles] cmds = [ @@ -1384,3 +1400,5 @@ for pf, help_text in packaging_flavors: os.path.join(build_dir, 'QMTest'), os.path.join(build_dir, 'runtest.py'), ]) + + diff --git a/bin/Command.py b/bin/Command.py index 8702f51..dadd7a9 100644 --- a/bin/Command.py +++ b/bin/Command.py @@ -4,6 +4,7 @@ # # XXX Describe what the script does here. # +from __future__ import print_function import getopt import os @@ -109,18 +110,18 @@ Usage: script-template.py [-hnq] try: try: opts, args = getopt.getopt(argv[1:], short_options, long_options) - except getopt.error, msg: + except getopt.error as msg: raise Usage(msg) for o, a in opts: if o in ('-h', '--help'): - print helpstr + print(helpstr) sys.exit(0) elif o in ('-n', '--no-exec'): Command.execute = Command.do_not_execute elif o in ('-q', '--quiet'): Command.display = Command.do_not_display - except Usage, err: + except Usage as err: sys.stderr.write(err.msg) sys.stderr.write('use -h to get help') return 2 diff --git a/bin/SConsDoc.py b/bin/SConsDoc.py index ff8a312..cfb4e54 100644 --- a/bin/SConsDoc.py +++ b/bin/SConsDoc.py @@ -24,6 +24,7 @@ # # Module for handling SCons documentation processing. # +from __future__ import print_function __doc__ = """ This module parses home-brew XML files that document various things @@ -51,7 +52,7 @@ Builder example: to indicate a new paragraph. - print "this is example code, it will be offset and indented" + print("this is example code, it will be offset and indented") @@ -71,7 +72,7 @@ Function example: &f-FUNCTION; element. It need not be on a line by itself. - print "this is example code, it will be offset and indented" + print("this is example code, it will be offset and indented") @@ -88,7 +89,7 @@ Construction variable example: &t-VARIABLE; element. It need not be on a line by itself. - print "this is example code, it will be offset and indented" + print("this is example code, it will be offset and indented") @@ -105,7 +106,7 @@ Tool example: &t-TOOL; element. It need not be on a line by itself. - print "this is example code, it will be offset and indented" + print("this is example code, it will be offset and indented") @@ -167,7 +168,7 @@ xsi = "http://www.w3.org/2001/XMLSchema-instance" # Header comment with copyright copyright_comment = """ -Copyright (c) 2001 - 2016 The SCons Foundation +Copyright (c) 2001 - 2017 The SCons Foundation This file is processed by the bin/SConsDoc.py module. See its __doc__ string for a discussion of the format. @@ -208,12 +209,12 @@ class Libxml2ValidityHandler: def error(self, msg, data): if data != ARG: - raise Exception, "Error handler did not receive correct argument" + raise Exception("Error handler did not receive correct argument") self.errors.append(msg) def warning(self, msg, data): if data != ARG: - raise Exception, "Warning handler did not receive correct argument" + raise Exception("Warning handler did not receive correct argument") self.warnings.append(msg) @@ -330,16 +331,16 @@ if not has_libxml2: xmlschema = etree.XMLSchema(xmlschema_context) try: doc = etree.parse(fpath) - except Exception, e: - print "ERROR: %s fails to parse:"%fpath - print e + except Exception as e: + print("ERROR: %s fails to parse:"%fpath) + print(e) return False doc.xinclude() try: xmlschema.assertValid(doc) - except Exception, e: - print "ERROR: %s fails to validate:" % fpath - print e + except Exception as e: + print("ERROR: %s fails to validate:" % fpath) + print(e) return False return True @@ -475,8 +476,8 @@ else: if err or eh.errors: for e in eh.errors: - print e.rstrip("\n") - print "%s fails to validate" % fpath + print(e.rstrip("\n")) + print("%s fails to validate" % fpath) return False return True @@ -597,7 +598,7 @@ class SConsDocTree: # Create xpath context self.xpath_context = self.doc.xpathNewContext() # Register namespaces - for key, val in self.nsmap.iteritems(): + for key, val in self.nsmap.items(): self.xpath_context.xpathRegisterNs(key, val) def __del__(self): @@ -635,8 +636,8 @@ def validate_all_xml(dpaths, xsdfile=default_xsd): fails = [] for idx, fp in enumerate(fpaths): fpath = os.path.join(path, fp) - print "%.2f%s (%d/%d) %s" % (float(idx+1)*100.0/float(len(fpaths)), - perc, idx+1, len(fpaths),fp) + print("%.2f%s (%d/%d) %s" % (float(idx+1)*100.0/float(len(fpaths)), + perc, idx+1, len(fpaths),fp)) if not tf.validateXml(fp, xmlschema_context): fails.append(fp) @@ -665,8 +666,10 @@ class Item(object): if name[0] == '_': name = name[1:] return name.lower() - def __cmp__(self, other): - return cmp(self.sort_name, other.sort_name) + def __eq__(self, other): + return self.sort_name == other.sort_name + def __lt__(self, other): + return self.sort_name < other.sort_name class Builder(Item): pass @@ -808,7 +811,7 @@ def importfile(path): file = open(path, 'r') try: module = imp.load_module(name, file, path, (ext, 'r', kind)) - except ImportError, e: + except ImportError as e: sys.stderr.write("Could not import %s: %s\n" % (path, e)) return None file.close() diff --git a/bin/SConsExamples.py b/bin/SConsExamples.py index 9823a05..50c4c1a 100644 --- a/bin/SConsExamples.py +++ b/bin/SConsExamples.py @@ -1,7 +1,7 @@ # !/usr/bin/env python -# +# # Copyright (c) 2010 The SCons Foundation -# +# # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including @@ -9,10 +9,10 @@ # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: -# +# # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. -# +# # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND @@ -21,18 +21,18 @@ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -# +# +# # This script looks for some XML tags that describe SCons example # configurations and commands to execute in those configurations, and # uses TestCmd.py to execute the commands and insert the output from # those commands into the XML that we output. This way, we can run a # script and update all of our example documentation output without # a lot of laborious by-hand checking. -# +# # An "SCons example" looks like this, and essentially describes a set of # input files (program source files as well as SConscript files): -# +# # # # env = Environment() @@ -42,7 +42,7 @@ # int main() { printf("foo.c\n"); } # # -# +# # The contents within the tag will get written # into a temporary directory whenever example output needs to be # generated. By default, the contents are not inserted into text @@ -50,41 +50,43 @@ # in which case they will get inserted within a tag. # This makes it easy to define the example at the appropriate # point in the text where you intend to show the SConstruct file. -# +# # Note that you should usually give the a "name" # attribute so that you can refer to the example configuration later to # run SCons and generate output. -# +# # If you just want to show a file's contents without worry about running # SCons, there's a shorter tag: -# +# # # env = Environment() # env.Program('foo') # -# +# # This is essentially equivalent to , # but it's more straightforward. -# +# # SCons output is generated from the following sort of tag: -# +# # # scons -Q foo # scons -Q foo # -# +# # You tell it which example to use with the "example" attribute, and then # give it a list of tags to execute. You can also # supply an "os" tag, which specifies the type of operating system this # example is intended to show; if you omit this, default value is "posix". -# +# # The generated XML will show the command line (with the appropriate # command-line prompt for the operating system), execute the command in # a temporary directory with the example files, capture the standard # output from SCons, and insert it into the text as appropriate. # Error output gets passed through to your error output so you # can see if there are any problems executing the command. -# +# + +from __future__ import print_function import os import re @@ -94,9 +96,9 @@ import time import SConsDoc from SConsDoc import tf as stf -# +# # The available types for ExampleFile entries -# +# FT_FILE = 0 # a physical file (=) FT_FILEREF = 1 # a reference (=) @@ -106,7 +108,7 @@ class ExampleFile: self.name = '' self.content = '' self.chmod = '' - + def isFileRef(self): return self.type == FT_FILEREF @@ -130,19 +132,19 @@ class ExampleOutput: self.preserve = None self.suffix = '' self.commands = [] - + class ExampleInfo: def __init__(self): self.name = '' self.files = [] self.folders = [] self.outputs = [] - + def getFileContents(self, fname): for f in self.files: if fname == f.name and not f.isFileRef(): return f.content - + return '' def readExampleInfos(fpath, examples): @@ -150,10 +152,10 @@ def readExampleInfos(fpath, examples): global dictionary examples. """ - # Create doctree + # Create doctree t = SConsDoc.SConsDocTree() t.parseXmlFile(fpath) - + # Parse scons_examples for e in stf.findAll(t.root, "scons_example", SConsDoc.dbxid, t.xpath_context, t.nsmap): @@ -164,7 +166,7 @@ def readExampleInfos(fpath, examples): i = ExampleInfo() i.name = n examples[n] = i - + # Parse file and directory entries for f in stf.findAll(e, "file", SConsDoc.dbxid, t.xpath_context, t.nsmap): @@ -199,8 +201,8 @@ def readExampleInfos(fpath, examples): fi.chmod = stf.getAttribute(f, 'chmod') fi.content = stf.getText(f) examples[e].files.append(fi) - - + + # Parse scons_output for o in stf.findAll(t.root, "scons_output", SConsDoc.dbxid, t.xpath_context, t.nsmap): @@ -238,7 +240,7 @@ def readExampleInfos(fpath, examples): examples[n].outputs.append(eout) def readAllExampleInfos(dpath): - """ Scan for XML files in the given directory and + """ Scan for XML files in the given directory and collect together all relevant infos (files/folders, output commands) in a map, which gets returned. """ @@ -249,13 +251,13 @@ def readAllExampleInfos(dpath): fpath = os.path.join(path, f) if SConsDoc.isSConsXml(fpath): readExampleInfos(fpath, examples) - + return examples generated_examples = os.path.join('doc', 'generated', 'examples') def ensureExampleOutputsExist(dpath): - """ Scan for XML files in the given directory and + """ Scan for XML files in the given directory and ensure that for every example output we have a corresponding output file in the 'generated/examples' folder. @@ -263,9 +265,9 @@ def ensureExampleOutputsExist(dpath): # Ensure that the output folder exists if not os.path.isdir(generated_examples): os.mkdir(generated_examples) - + examples = readAllExampleInfos(dpath) - for key, value in examples.iteritems(): + for key, value in examples.items(): # Process all scons_output tags for o in value.outputs: cpath = os.path.join(generated_examples, @@ -276,7 +278,7 @@ def ensureExampleOutputsExist(dpath): stf.setText(s, "NO OUTPUT YET! Run the script to generate/update all examples.") # Write file stf.writeTree(s, cpath) - + # Process all scons_example_file tags for r in value.files: if r.isFileRef(): @@ -292,22 +294,22 @@ def ensureExampleOutputsExist(dpath): perc = "%" def createAllExampleOutputs(dpath): - """ Scan for XML files in the given directory and + """ Scan for XML files in the given directory and creates all output files for every example in the 'generated/examples' folder. """ # Ensure that the output folder exists if not os.path.isdir(generated_examples): os.mkdir(generated_examples) - + examples = readAllExampleInfos(dpath) total = len(examples) idx = 0 - for key, value in examples.iteritems(): + for key, value in examples.items(): # Process all scons_output tags - print "%.2f%s (%d/%d) %s" % (float(idx + 1) * 100.0 / float(total), - perc, idx + 1, total, key) - + print("%.2f%s (%d/%d) %s" % (float(idx + 1) * 100.0 / float(total), + perc, idx + 1, total, key)) + create_scons_output(value) # Process all scons_example_file tags for r in value.files: @@ -329,10 +331,10 @@ def collectSConsExampleNames(fpath): suffixes = {} failed_suffixes = False - # Create doctree + # Create doctree t = SConsDoc.SConsDocTree() t.parseXmlFile(fpath) - + # Parse it for e in stf.findAll(t.root, "scons_example", SConsDoc.dbxid, t.xpath_context, t.nsmap): @@ -344,40 +346,40 @@ def collectSConsExampleNames(fpath): if n not in suffixes: suffixes[n] = [] else: - print "Error: Example in file '%s' is missing a name!" % fpath + print("Error: Example in file '%s' is missing a name!" % fpath) failed_suffixes = True - + for o in stf.findAll(t.root, "scons_output", SConsDoc.dbxid, t.xpath_context, t.nsmap): n = '' if stf.hasAttribute(o, 'example'): n = stf.getAttribute(o, 'example') else: - print "Error: scons_output in file '%s' is missing an example name!" % fpath + print("Error: scons_output in file '%s' is missing an example name!" % fpath) failed_suffixes = True - + if n not in suffixes: - print "Error: scons_output in file '%s' is referencing non-existent example '%s'!" % (fpath, n) + print("Error: scons_output in file '%s' is referencing non-existent example '%s'!" % (fpath, n)) failed_suffixes = True continue - + s = '' if stf.hasAttribute(o, 'suffix'): s = stf.getAttribute(o, 'suffix') else: - print "Error: scons_output in file '%s' (example '%s') is missing a suffix!" % (fpath, n) + print("Error: scons_output in file '%s' (example '%s') is missing a suffix!" % (fpath, n)) failed_suffixes = True - + if s not in suffixes[n]: suffixes[n].append(s) else: - print "Error: scons_output in file '%s' (example '%s') is using a duplicate suffix '%s'!" % (fpath, n, s) + print("Error: scons_output in file '%s' (example '%s') is using a duplicate suffix '%s'!" % (fpath, n, s)) failed_suffixes = True - + return names, failed_suffixes def exampleNamesAreUnique(dpath): - """ Scan for XML files in the given directory and + """ Scan for XML files in the given directory and check whether the scons_example names are unique. """ unique = True @@ -392,21 +394,21 @@ def exampleNamesAreUnique(dpath): unique = False i = allnames.intersection(names) if i: - print "Not unique in %s are: %s" % (fpath, ', '.join(i)) + print("Not unique in %s are: %s" % (fpath, ', '.join(i))) unique = False - + allnames |= names - + return unique # ############################################################### -# +# # In the second half of this module (starting here) # we define the variables and functions that are required # to actually run the examples, collect their output and # write it into the files in doc/generated/examples... # which then get included by our UserGuide. -# +# # ############################################################### sys.path.append(os.path.join(os.getcwd(), 'QMTest')) @@ -416,6 +418,8 @@ scons_py = os.path.join('bootstrap', 'src', 'script', 'scons.py') if not os.path.exists(scons_py): scons_py = os.path.join('src', 'script', 'scons.py') +scons_py = os.path.join(os.getcwd(), scons_py) + scons_lib_dir = os.path.join(os.getcwd(), 'bootstrap', 'src', 'engine') if not os.path.exists(scons_lib_dir): scons_lib_dir = os.path.join(os.getcwd(), 'src', 'engine') @@ -430,7 +434,7 @@ Prompt = { } # The magick SCons hackery that makes this work. -# +# # So that our examples can still use the default SConstruct file, we # actually feed the following into SCons via stdin and then have it # SConscript() the SConstruct file. This stdin wrapper creates a set @@ -438,7 +442,7 @@ Prompt = { # Surrogates print output like the real tools and behave like them # without actually having to be on the right platform or have the right # tool installed. -# +# # The upshot: The wrapper transparently changes the world out from # under the top-level SConstruct file in an example just so we can get # the command output. @@ -610,10 +614,6 @@ ToolList = { ('ar', ['ARCOM', 'RANLIBCOM'], Cat, []), ('tar', 'TARCOM', Null, []), ('zip', 'ZIPCOM', Null, []), - ('BitKeeper', 'BITKEEPERCOM', Cat, []), - ('CVS', 'CVSCOM', Cat, []), - ('RCS', 'RCS_COCOM', Cat, []), - ('SCCS', 'SCCSCOM', Cat, []), ('javac', 'JAVACCOM', JavaCCom, []), ('javah', 'JAVAHCOM', JavaHCom, []), ('jar', 'JARCOM', JarCom, []), @@ -624,10 +624,6 @@ ToolList = { ('mslib', 'ARCOM', Cat, []), ('tar', 'TARCOM', Null, []), ('zip', 'ZIPCOM', Null, []), - ('BitKeeper', 'BITKEEPERCOM', Cat, []), - ('CVS', 'CVSCOM', Cat, []), - ('RCS', 'RCS_COCOM', Cat, []), - ('SCCS', 'SCCSCOM', Cat, []), ('javac', 'JAVACCOM', JavaCCom, []), ('javah', 'JAVAHCOM', JavaHCom, []), ('jar', 'JARCOM', JarCom, []), @@ -734,7 +730,11 @@ def command_edit(args, c, test, dict): def command_ls(args, c, test, dict): def ls(a): - return [' '.join(sorted([x for x in os.listdir(a) if x[0] != '.']))] + try: + return [' '.join(sorted([x for x in os.listdir(a) if x[0] != '.']))] + except OSError as e: + # This should never happen. Pop into debugger + import pdb; pdb.set_trace() if args: l = [] for a in args: @@ -765,7 +765,7 @@ def ExecuteCommand(args, c, t, dict): def create_scons_output(e): # The real raison d'etre for this script, this is where we # actually execute SCons to fetch the output. - + # Loop over all outputs for the example for o in e.outputs: # Create new test directory @@ -774,19 +774,19 @@ def create_scons_output(e): t.preserve() t.subdir('ROOT', 'WORK') t.rootpath = t.workpath('ROOT').replace('\\', '\\\\') - + for d in e.folders: dir = t.workpath('WORK', d.name) if not os.path.exists(dir): os.makedirs(dir) - + for f in e.files: if f.isFileRef(): continue - # + # # Left-align file's contents, starting on the first # non-empty line - # + # data = f.content.split('\n') i = 0 # Skip empty lines @@ -813,26 +813,26 @@ def create_scons_output(e): if hasattr(f, 'chmod'): if len(f.chmod): os.chmod(path, int(f.chmod, 0)) - + # Regular expressions for making the doc output consistent, # regardless of reported addresses or Python version. - + # Massage addresses in object repr strings to a constant. address_re = re.compile(r' at 0x[0-9a-fA-F]*\>') - + # Massage file names in stack traces (sometimes reported as absolute # paths) to a consistent relative path. engine_re = re.compile(r' File ".*/src/engine/SCons/') - + # Python 2.5 changed the stack trace when the module is read # from standard input from read "... line 7, in ?" to # "... line 7, in ". file_re = re.compile(r'^( *File ".*", line \d+, in) \?$', re.M) - + # Python 2.6 made UserList a new-style class, which changes the # AttributeError message generated by our NodeList subclass. nodelist_re = re.compile(r'(AttributeError:) NodeList instance (has no attribute \S+)') - + # Root element for our subtree sroot = stf.newEtreeNode("screen", True) curchild = None @@ -881,7 +881,7 @@ def create_scons_output(e): curchild.tail = content else: sroot.text = content - + # Construct filename fpath = os.path.join(generated_examples, e.name + '_' + o.suffix + '.xml') diff --git a/bin/calibrate.py b/bin/calibrate.py index 8ed2ece..3f9104e 100644 --- a/bin/calibrate.py +++ b/bin/calibrate.py @@ -20,7 +20,7 @@ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -from __future__ import division +from __future__ import division, print_function import optparse import os @@ -48,7 +48,7 @@ def main(argv=None): for arg in args: if len(args) > 1: - print arg + ':' + print(arg + ':') command = [sys.executable, 'runtest.py'] if opts.package: @@ -67,9 +67,9 @@ def main(argv=None): try: elapsed = float(em.group(1)) except AttributeError: - print output + print(output) raise - print "run %3d: %7.3f: %s" % (run, elapsed, ' '.join(vm.groups())) + print("run %3d: %7.3f: %s" % (run, elapsed, ' '.join(vm.groups()))) if opts.min < elapsed and elapsed < opts.max: good += 1 else: diff --git a/bin/caller-tree.py b/bin/caller-tree.py index 03c1616..18cd9e1 100644 --- a/bin/caller-tree.py +++ b/bin/caller-tree.py @@ -39,6 +39,7 @@ # function at the same time, for example, their counts will intermix. # So use this to get a *general* idea of who's calling what, not for # fine-grained performance tuning. +from __future__ import print_function import sys @@ -74,19 +75,19 @@ for line in sys.stdin.readlines(): stack = [] def print_entry(e, level, calls): - print '%-72s%6s' % ((' '*2*level) + e.file_line_func, calls) + print('%-72s%6s' % ((' '*2*level) + e.file_line_func, calls)) if e in stack: - print (' '*2*(level+1))+'RECURSION' - print + print((' '*2*(level+1))+'RECURSION') + print() elif e.called_by: stack.append(e) for c in e.called_by: print_entry(c[0], level+1, c[1]) stack.pop() else: - print + print() -for e in [ e for e in AllCalls.values() if not e.calls ]: +for e in [ e for e in list(AllCalls.values()) if not e.calls ]: print_entry(e, 0, '') # Local Variables: diff --git a/bin/docs-create-example-outputs.py b/bin/docs-create-example-outputs.py index 6e59d9f..73aa31a 100644 --- a/bin/docs-create-example-outputs.py +++ b/bin/docs-create-example-outputs.py @@ -3,17 +3,18 @@ # Searches through the whole doc/user tree and creates # all output files for the single examples. # +from __future__ import print_function import os import sys import SConsExamples if __name__ == "__main__": - print "Checking whether all example names are unique..." + print("Checking whether all example names are unique...") if SConsExamples.exampleNamesAreUnique(os.path.join('doc','user')): - print "OK" + print("OK") else: - print "Not all example names and suffixes are unique! Please correct the errors listed above and try again." + print("Not all example names and suffixes are unique! Please correct the errors listed above and try again.") sys.exit(1) - + SConsExamples.createAllExampleOutputs(os.path.join('doc','user')) diff --git a/bin/docs-update-generated.py b/bin/docs-update-generated.py index 55f0035..c164baf 100644 --- a/bin/docs-update-generated.py +++ b/bin/docs-update-generated.py @@ -6,6 +6,7 @@ # as well as the entity declarations for them. # Uses scons-proc.py under the hood... # +from __future__ import print_function import os import sys @@ -39,7 +40,7 @@ def generate_all(): try: os.makedirs(gen_folder) except: - print "Couldn't create destination folder %s! Exiting..." % gen_folder + print("Couldn't create destination folder %s! Exiting..." % gen_folder) return # Call scons-proc.py os.system('%s %s -b %s -f %s -t %s -v %s %s' % diff --git a/bin/docs-validate.py b/bin/docs-validate.py index f888c21..342ed43 100644 --- a/bin/docs-validate.py +++ b/bin/docs-validate.py @@ -3,6 +3,7 @@ # Searches through the whole source tree and validates all # documentation files against our own XSD in docs/xsd. # +from __future__ import print_function import sys,os import SConsDoc @@ -10,9 +11,9 @@ import SConsDoc if __name__ == "__main__": if len(sys.argv)>1: if SConsDoc.validate_all_xml((sys.argv[1],)): - print "OK" + print("OK") else: - print "Validation failed! Please correct the errors above and try again." + print("Validation failed! Please correct the errors above and try again.") else: if SConsDoc.validate_all_xml(['src', os.path.join('doc','design'), @@ -22,7 +23,7 @@ if __name__ == "__main__": os.path.join('doc','reference'), os.path.join('doc','user') ]): - print "OK" + print("OK") else: - print "Validation failed! Please correct the errors above and try again." + print("Validation failed! Please correct the errors above and try again.") sys.exit(1) diff --git a/bin/import-test.py b/bin/import-test.py index eb93828..168208f 100644 --- a/bin/import-test.py +++ b/bin/import-test.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -# Copyright (c) 2001 - 2016 The SCons Foundation +# Copyright (c) 2001 - 2017 The SCons Foundation # # tree2test.py - turn a directory tree into TestSCons code # @@ -25,7 +25,7 @@ # """ triple-quotes will need to have their contents edited by hand. # -__revision__ = "bin/import-test.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" +__revision__ = "bin/import-test.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog" import os.path import sys diff --git a/bin/install_python.py b/bin/install_python.py index 86807af..5c947ac 100644 --- a/bin/install_python.py +++ b/bin/install_python.py @@ -6,6 +6,7 @@ # This was written for a Linux system (specifically Ubuntu) but should # be reasonably generic to any POSIX-style system with a /usr/local # hierarchy. +from __future__ import print_function import getopt import os @@ -48,7 +49,7 @@ Usage: install_python.py [-ahnq] [-d DIR] [-p PREFIX] [VERSION ...] try: try: opts, args = getopt.getopt(argv[1:], short_options, long_options) - except getopt.error, msg: + except getopt.error as msg: raise Usage(msg) for o, a in opts: @@ -57,7 +58,7 @@ Usage: install_python.py [-ahnq] [-d DIR] [-p PREFIX] [VERSION ...] elif o in ('-d', '--downloads'): downloads_dir = a elif o in ('-h', '--help'): - print helpstr + print(helpstr) sys.exit(0) elif o in ('-n', '--no-exec'): CommandRunner.execute = CommandRunner.do_not_execute @@ -65,7 +66,7 @@ Usage: install_python.py [-ahnq] [-d DIR] [-p PREFIX] [VERSION ...] prefix = a elif o in ('-q', '--quiet'): CommandRunner.display = CommandRunner.do_not_display - except Usage, err: + except Usage as err: sys.stderr.write(str(err.msg) + '\n') sys.stderr.write('use -h to get help\n') return 2 diff --git a/bin/install_scons.py b/bin/install_scons.py index 00129f6..ac79fd3 100644 --- a/bin/install_scons.py +++ b/bin/install_scons.py @@ -18,12 +18,14 @@ # be reasonably generic to any POSIX-style system with a /usr/local # hierarchy. +from __future__ import print_function + import getopt import os import shutil import sys import tarfile -import urllib +from urllib import urlretrieve from Command import CommandRunner, Usage @@ -129,7 +131,7 @@ Usage: install_scons.py [-ahnq] [-d DIR] [-p PREFIX] [VERSION ...] try: try: opts, args = getopt.getopt(argv[1:], short_options, long_options) - except getopt.error, msg: + except getopt.error as msg: raise Usage(msg) for o, a in opts: @@ -138,7 +140,7 @@ Usage: install_scons.py [-ahnq] [-d DIR] [-p PREFIX] [VERSION ...] elif o in ('-d', '--downloads'): downloads_dir = a elif o in ('-h', '--help'): - print helpstr + print(helpstr) sys.exit(0) elif o in ('-n', '--no-exec'): CommandRunner.execute = CommandRunner.do_not_execute @@ -146,7 +148,7 @@ Usage: install_scons.py [-ahnq] [-d DIR] [-p PREFIX] [VERSION ...] prefix = a elif o in ('-q', '--quiet'): CommandRunner.display = CommandRunner.do_not_display - except Usage, err: + except Usage as err: sys.stderr.write(str(err.msg) + '\n') sys.stderr.write('use -h to get help\n') return 2 @@ -171,7 +173,7 @@ Usage: install_scons.py [-ahnq] [-d DIR] [-p PREFIX] [VERSION ...] if not os.path.exists(tar_gz): if not os.path.exists(downloads_dir): cmd.run('mkdir %(downloads_dir)s') - cmd.run((urllib.urlretrieve, tar_gz_url, tar_gz), + cmd.run((urlretrieve, tar_gz_url, tar_gz), 'wget -O %(tar_gz)s %(tar_gz_url)s') def extract(tar_gz): diff --git a/bin/linecount.py b/bin/linecount.py index 147089a..75723d0 100644 --- a/bin/linecount.py +++ b/bin/linecount.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -# Copyright (c) 2001 - 2016 The SCons Foundation +# Copyright (c) 2001 - 2017 The SCons Foundation # # Count statistics about SCons test and source files. This must be run # against a fully-populated tree (for example, one that's been freshly @@ -21,9 +21,9 @@ # in each category, the number of non-blank lines, and the number of # non-comment lines. The last figure (non-comment) lines is the most # interesting one for most purposes. -from __future__ import division +from __future__ import division, print_function -__revision__ = "bin/linecount.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" +__revision__ = "bin/linecount.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog" import os.path @@ -98,23 +98,23 @@ all_tests = Collection('all tests', src_tests.files + test_tests.files) def ratio(over, under): return "%.2f" % (float(len(over)) / float(len(under))) -print fmt % ('', '', '', '', '', 'non-blank') -print fmt % ('', 'files', 'lines', 'non-blank', 'non-comment', 'non-comment') -print -print fmt % src_Tests_py_tests.printables() -print fmt % src_test_tests.printables() -print -print fmt % src_tests.printables() -print fmt % test_tests.printables() -print -print fmt % all_tests.printables() -print fmt % sources.printables() -print -print fmt % ('ratio:', +print(fmt % ('', '', '', '', '', 'non-blank')) +print(fmt % ('', 'files', 'lines', 'non-blank', 'non-comment', 'non-comment')) +print() +print(fmt % src_Tests_py_tests.printables()) +print(fmt % src_test_tests.printables()) +print() +print(fmt % src_tests.printables()) +print(fmt % test_tests.printables()) +print() +print(fmt % all_tests.printables()) +print(fmt % sources.printables()) +print() +print(fmt % ('ratio:', ratio(all_tests, sources), ratio(all_tests.lines(), sources.lines()), ratio(all_tests.non_blank(), sources.non_blank()), ratio(all_tests.non_comment(), sources.non_comment()), ratio(all_tests.non_blank_non_comment(), sources.non_blank_non_comment()) - ) + )) diff --git a/bin/memlogs.py b/bin/memlogs.py index 9d957c9..b450939 100644 --- a/bin/memlogs.py +++ b/bin/memlogs.py @@ -21,26 +21,28 @@ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +from __future__ import print_function + import getopt import sys filenames = sys.argv[1:] if not filenames: - print """Usage: memlogs.py file [...] + print("""Usage: memlogs.py file [...] Summarizes the --debug=memory numbers from one or more build logs. -""" +""") sys.exit(0) fmt = "%12s %12s %12s %12s %s" -print fmt % ("pre-read", "post-read", "pre-build", "post-build", "") +print(fmt % ("pre-read", "post-read", "pre-build", "post-build", "")) for fname in sys.argv[1:]: lines = [l for l in open(fname).readlines() if l[:7] == 'Memory '] t = tuple([l.split()[-1] for l in lines]) + (fname,) - print fmt % t + print(fmt % t) # Local Variables: # tab-width:4 diff --git a/bin/memoicmp.py b/bin/memoicmp.py index 812af66..63f6538 100644 --- a/bin/memoicmp.py +++ b/bin/memoicmp.py @@ -3,6 +3,8 @@ # A script to compare the --debug=memoizer output found in # two different files. +from __future__ import print_function + import sys def memoize_output(fname): @@ -23,20 +25,20 @@ def memoize_cmp(filea, fileb): ma = memoize_output(filea) mb = memoize_output(fileb) - print 'All output: %s / %s [delta]'%(filea, fileb) - print '----------HITS---------- ---------MISSES---------' + print('All output: %s / %s [delta]'%(filea, fileb)) + print('----------HITS---------- ---------MISSES---------') cfmt='%7d/%-7d [%d]' ma_o = [] mb_o = [] mab = [] - for k in ma.keys(): - if k in mb.keys(): + for k in list(ma.keys()): + if k in list(mb.keys()): if k not in mab: mab.append(k) else: ma_o.append(k) - for k in mb.keys(): - if k in ma.keys(): + for k in list(mb.keys()): + if k in list(ma.keys()): if k not in mab: mab.append(k) else: @@ -45,30 +47,30 @@ def memoize_cmp(filea, fileb): mab.sort() ma_o.sort() mb_o.sort() - + for k in mab: hits = cfmt%(ma[k][0], mb[k][0], mb[k][0]-ma[k][0]) miss = cfmt%(ma[k][1], mb[k][1], mb[k][1]-ma[k][1]) - print '%-24s %-24s %s'%(hits, miss, k) + print('%-24s %-24s %s'%(hits, miss, k)) for k in ma_o: hits = '%7d/ --'%(ma[k][0]) miss = '%7d/ --'%(ma[k][1]) - print '%-24s %-24s %s'%(hits, miss, k) + print('%-24s %-24s %s'%(hits, miss, k)) for k in mb_o: hits = ' -- /%-7d'%(mb[k][0]) miss = ' -- /%-7d'%(mb[k][1]) - print '%-24s %-24s %s'%(hits, miss, k) + print('%-24s %-24s %s'%(hits, miss, k)) + + print('-'*(24+24+1+20)) - print '-'*(24+24+1+20) - if __name__ == "__main__": if len(sys.argv) != 3: - print """Usage: %s file1 file2 + print("""Usage: %s file1 file2 -Compares --debug=memomize output from file1 against file2."""%sys.argv[0] +Compares --debug=memomize output from file1 against file2."""%sys.argv[0]) sys.exit(1) memoize_cmp(sys.argv[1], sys.argv[2]) diff --git a/bin/objcounts.py b/bin/objcounts.py index 0662012..8b550d1 100644 --- a/bin/objcounts.py +++ b/bin/objcounts.py @@ -20,6 +20,7 @@ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +from __future__ import print_function import re import sys @@ -27,10 +28,10 @@ import sys filenames = sys.argv[1:] if len(sys.argv) != 3: - print """Usage: objcounts.py file1 file2 + print("""Usage: objcounts.py file1 file2 Compare the --debug=object counts from two build logs. -""" +""") sys.exit(0) def fetch_counts(fname): @@ -47,7 +48,7 @@ c1 = fetch_counts(sys.argv[1]) c2 = fetch_counts(sys.argv[2]) common = {} -for k in c1.keys(): +for k in list(c1.keys()): try: common[k] = (c1[k], c2[k]) except KeyError: @@ -58,7 +59,7 @@ for k in c1.keys(): if not '.' in k: s = '.'+k l = len(s) - for k2 in c2.keys(): + for k2 in list(c2.keys()): if k2[-l:] == s: common[k2] = (c1[k], c2[k2]) del c1[k] @@ -81,10 +82,9 @@ def diffstr(c1, c2): return " %5s/%-5s %-8s" % (c1, c2, d) def printline(c1, c2, classname): - print \ - diffstr(c1[2], c2[2]) + \ + print(diffstr(c1[2], c2[2]) + \ diffstr(c1[3], c2[3]) + \ - ' ' + classname + ' ' + classname) for k in sorted(common.keys()): c = common[k] diff --git a/bin/restore.sh b/bin/restore.sh index 4b96852..49c95bc 100644 --- a/bin/restore.sh +++ b/bin/restore.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh # -# Simple hack script to restore __revision__, __COPYRIGHT_, 2.5.1 +# Simple hack script to restore __revision__, __COPYRIGHT_, 3.0.0 # and other similar variables to what gets checked in to source. This # comes in handy when people send in diffs based on the released source. # @@ -22,9 +22,9 @@ header() { for i in `find $DIRS -name '*.py'`; do header $i ed $i <" - print " " + print("") + print(" ") sys_keys = ['byteorder', 'exec_prefix', 'executable', 'maxint', 'maxunicode', 'platform', 'prefix', 'version', 'version_info'] for k in sys_keys: - print " <%s>%s" % (k, sys.__dict__[k], k) - print " " + print(" <%s>%s" % (k, sys.__dict__[k], k)) + print(" ") fmt = '%a %b %d %H:%M:%S %Y' - print " " + print(" ") - print " %s" % tempdir + print(" %s" % tempdir) def print_version_info(tag, module): - print " <%s>" % tag - print " %s" % module.__version__ - print " %s" % module.__build__ - print " %s" % module.__buildsys__ - print " %s" % module.__date__ - print " %s" % module.__developer__ - print " " % tag - - print " " + print(" <%s>" % tag) + print(" %s" % module.__version__) + print(" %s" % module.__build__) + print(" %s" % module.__buildsys__) + print(" %s" % module.__date__) + print(" %s" % module.__developer__) + print(" " % tag) + + print(" ") print_version_info("script", scons) print_version_info("engine", SCons) - print " " + print(" ") environ_keys = [ 'PATH', @@ -213,37 +214,37 @@ if format == '--xml': 'USER', ] - print " " + print(" ") for key in sorted(environ_keys): value = os.environ.get(key) if value: - print " " - print " %s" % key - print " %s" % value - print " " - print " " + print(" ") + print(" %s" % key) + print(" %s" % value) + print(" ") + print(" ") command = '"%s" runtest.py -q -o - --xml %s' % (sys.executable, runtest_args) - #print command + #print(command) os.system(command) - print "" + print("") else: def print_version_info(tag, module): - print "\t%s: v%s.%s, %s, by %s on %s" % (tag, + print("\t%s: v%s.%s, %s, by %s on %s" % (tag, module.__version__, module.__build__, module.__date__, module.__developer__, - module.__buildsys__) + module.__buildsys__)) - print "SCons by Steven Knight et al.:" + print("SCons by Steven Knight et al.:") print_version_info("script", scons) print_version_info("engine", SCons) command = '"%s" runtest.py %s' % (sys.executable, runtest_args) - #print command + #print(command) os.system(command) # Local Variables: diff --git a/bin/scons-unzip.py b/bin/scons-unzip.py index d4ec4bf..a64179f 100644 --- a/bin/scons-unzip.py +++ b/bin/scons-unzip.py @@ -7,6 +7,7 @@ # I'm using this to make it more convenient to manage working on multiple # changes on Windows, where I don't have access to my Aegis tools. # +from __future__ import print_function import getopt import os.path @@ -32,7 +33,7 @@ for o, a in opts: outdir = a elif o == '-v' or o == '--verbose': def printname(x): - print x + print(x) if len(args) != 1: sys.stderr.write("scons-unzip.py: \n") diff --git a/bin/scons_dev_master.py b/bin/scons_dev_master.py index 3c41ac0..3d67cb5 100644 --- a/bin/scons_dev_master.py +++ b/bin/scons_dev_master.py @@ -3,6 +3,7 @@ # A script for turning a generic Ubuntu system into a master for # SCons development. +from __future__ import print_function import getopt import sys @@ -10,7 +11,7 @@ import sys from Command import CommandRunner, Usage INITIAL_PACKAGES = [ - 'subversion', + 'mercurial', ] INSTALL_PACKAGES = [ @@ -22,6 +23,14 @@ PYTHON_PACKAGES = [ 'gcc', 'make', 'zlib1g-dev', + 'libreadline-gplv2-dev', + 'libncursesw5-dev', + 'libssl-dev', + 'libsqlite3-dev', + 'tk-dev', + 'libgdbm-dev', + 'libc6-dev', + 'libbz2-dev' ] BUILDING_PACKAGES = [ @@ -85,7 +94,7 @@ TESTING_PACKAGES = [ ] BUILDBOT_PACKAGES = [ - 'buildbot', + 'buildbot-worker', 'cron', ] @@ -122,7 +131,7 @@ Usage: scons_dev_master.py [-hnqy] [--password PASSWORD] [--username USER] buildbot Install packages for running BuildBot """ - scons_url = 'http://scons.tigris.org/svn/scons/trunk' + scons_url = 'https://bdbaddog@bitbucket.org/scons/scons' sudo = 'sudo' password = '""' username = 'guest' @@ -131,12 +140,12 @@ Usage: scons_dev_master.py [-hnqy] [--password PASSWORD] [--username USER] try: try: opts, args = getopt.getopt(argv[1:], short_options, long_options) - except getopt.error, msg: + except getopt.error as msg: raise Usage(msg) for o, a in opts: if o in ('-h', '--help'): - print helpstr + print(helpstr) sys.exit(0) elif o in ('-n', '--no-exec'): CommandRunner.execute = CommandRunner.do_not_execute @@ -148,7 +157,7 @@ Usage: scons_dev_master.py [-hnqy] [--password PASSWORD] [--username USER] username = a elif o in ('-y', '--yes', '--assume-yes'): yesflag = o - except Usage, err: + except Usage as err: sys.stderr.write(str(err.msg) + '\n') sys.stderr.write('use -h to get help\n') return 2 @@ -162,6 +171,7 @@ Usage: scons_dev_master.py [-hnqy] [--password PASSWORD] [--username USER] testing_packages = ' '.join(TESTING_PACKAGES) buildbot_packages = ' '.join(BUILDBOT_PACKAGES) python_packages = ' '.join(PYTHON_PACKAGES) + doc_packages = ' '.join(DOCUMENTATION_PACKAGES) cmd = CommandRunner(locals()) @@ -170,9 +180,11 @@ Usage: scons_dev_master.py [-hnqy] [--password PASSWORD] [--username USER] cmd.run('%(sudo)s apt-get %(yesflag)s upgrade') elif arg == 'checkout': cmd.run('%(sudo)s apt-get %(yesflag)s install %(initial_packages)s') - cmd.run('svn co --username guest --password "" %(scons_url)s') + cmd.run('hg clone" %(scons_url)s') elif arg == 'building': cmd.run('%(sudo)s apt-get %(yesflag)s install %(building_packages)s') + elif arg == 'docs': + cmd.run('%(sudo)s apt-get %(yesflag)s install %(doc_packages)s') elif arg == 'testing': cmd.run('%(sudo)s apt-get %(yesflag)s install %(testing_packages)s') elif arg == 'buildbot': diff --git a/bin/sfsum b/bin/sfsum index 2dfa422..142793a 100644 --- a/bin/sfsum +++ b/bin/sfsum @@ -22,6 +22,7 @@ # # https://sourceforge.net/projects/sitedocs/ # +from __future__ import print_function import xml.sax import xml.sax.saxutils @@ -121,9 +122,9 @@ if __name__ == '__main__': # generalized once we figure out other things for this script to do. bugs = [x for x in Artifacts['Bugs'] if x.status == 'Open'] - print list(Artifacts.keys()) + print(list(Artifacts.keys())) - print "%d open bugs" % len(bugs) + print("%d open bugs" % len(bugs)) # Sort them into a separate list for each assignee. Assigned = {} @@ -141,7 +142,7 @@ if __name__ == '__main__': except KeyError: pass else: - print " %s" % a - b.sort(lambda x, y: cmp(x.artifact_id, y.artifact_id)) + print(" %s" % a) + b.sort(key=lambda x, y: (x.artifact_id, y.artifact_id)) for bug in b: - print " %-6s %s" % (bug.artifact_id, bug.summary) + print(" %-6s %s" % (bug.artifact_id, bug.summary)) diff --git a/bin/svn-bisect.py b/bin/svn-bisect.py index 77bda58..dbf8dd9 100755 --- a/bin/svn-bisect.py +++ b/bin/svn-bisect.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -*- Python -*- -from __future__ import division +from __future__ import division, print_function import sys from math import log, ceil @@ -28,22 +28,22 @@ script = script_args[2:] # print an error message and quit def error(s): - print >>sys.stderr, "******", s, "******" + print("******", s, "******", file=sys.stderr) sys.exit(1) # update to the specified version and run test def testfail(revision): "Return true if test fails" - print "Updating to revision", revision + print("Updating to revision", revision) if subprocess.call(["svn","up","-qr",str(revision)]) != 0: m = "SVN did not update properly to revision %d" raise RuntimeError(m % revision) return subprocess.call(script,shell=False) != 0 # confirm that the endpoints are different -print "****** Checking upper bracket", upper +print("****** Checking upper bracket", upper) upperfails = testfail(upper) -print "****** Checking lower bracket", lower +print("****** Checking lower bracket", lower) lowerfails = testfail(lower) if upperfails == lowerfails: error("Upper and lower revisions must bracket the failure") @@ -51,7 +51,7 @@ if upperfails == lowerfails: # binary search for transition msg = "****** max %d revisions to test (bug bracketed by [%d,%d])" while upper-lower > 1: - print msg % (ceil(log(upper-lower,2)), lower, upper) + print(msg % (ceil(log(upper-lower,2)), lower, upper)) mid = (lower + upper)//2 midfails = testfail(mid) @@ -64,7 +64,7 @@ while upper-lower > 1: # show which revision was first to fail if upperfails != lowerfails: lower = upper -print "The error was caused by revision", lower +print("The error was caused by revision", lower) # Local Variables: # tab-width:4 diff --git a/bin/update-release-info.py b/bin/update-release-info.py index aee481e..a4096d1 100644 --- a/bin/update-release-info.py +++ b/bin/update-release-info.py @@ -36,7 +36,7 @@ In 'post' mode, files are prepared for the next release cycle: src/Announce.txt. """ # -# Copyright (c) 2001 - 2016 The SCons Foundation +# Copyright (c) 2001 - 2017 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -56,8 +56,9 @@ In 'post' mode, files are prepared for the next release cycle: # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +from __future__ import print_function -__revision__ = "bin/update-release-info.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" +__revision__ = "bin/update-release-info.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog" import os import sys @@ -73,14 +74,14 @@ if len(sys.argv) < 2: else: mode = sys.argv[1] if mode not in ['develop', 'release', 'post']: - print("""ERROR: `%s' as a parameter is invalid; it must be one of -\tdevelop, release, or post. The default is develop.""" % mode) + print(("""ERROR: `%s' as a parameter is invalid; it must be one of +\tdevelop, release, or post. The default is develop.""" % mode)) sys.exit(1) # Get configuration information config = dict() -exec open('ReleaseConfig').read() in globals(), config +exec(open('ReleaseConfig').read(), globals(), config) try: version_tuple = config['version_tuple'] @@ -90,9 +91,9 @@ except KeyError: print('''ERROR: Config file must contain at least version_tuple, \tunsupported_python_version, and deprecated_python_version.''') sys.exit(1) -if DEBUG: print 'version tuple', version_tuple -if DEBUG: print 'unsupported Python version', unsupported_version -if DEBUG: print 'deprecated Python version', deprecated_version +if DEBUG: print('version tuple', version_tuple) +if DEBUG: print('unsupported Python version', unsupported_version) +if DEBUG: print('deprecated Python version', deprecated_version) try: release_date = config['release_date'] @@ -102,9 +103,9 @@ else: if len(release_date) == 3: release_date = release_date + time.localtime()[3:6] if len(release_date) != 6: - print '''ERROR: Invalid release date''', release_date + print('''ERROR: Invalid release date''', release_date) sys.exit(1) -if DEBUG: print 'release date', release_date +if DEBUG: print('release date', release_date) if mode == 'develop' and version_tuple[3] != 'alpha': version_tuple == version_tuple[:3] + ('alpha', 0) @@ -119,11 +120,11 @@ if len(version_tuple) > 3: version_type = version_tuple[3] else: version_type = 'final' -if DEBUG: print 'version string', version_string +if DEBUG: print('version string', version_string) if version_type not in ['alpha', 'beta', 'candidate', 'final']: - print("""ERROR: `%s' is not a valid release type in version tuple; -\tit must be one of alpha, beta, candidate, or final""" % version_type) + print(("""ERROR: `%s' is not a valid release type in version tuple; +\tit must be one of alpha, beta, candidate, or final""" % version_type)) sys.exit(1) try: @@ -133,13 +134,13 @@ except KeyError: month_year = 'MONTH YEAR' else: month_year = time.strftime('%B %Y', release_date + (0,0,0)) -if DEBUG: print 'month year', month_year +if DEBUG: print('month year', month_year) try: copyright_years = config['copyright_years'] except KeyError: copyright_years = '2001 - %d'%(release_date[0] + 1) -if DEBUG: print 'copyright years', copyright_years +if DEBUG: print('copyright years', copyright_years) class UpdateFile(object): """ @@ -151,7 +152,7 @@ class UpdateFile(object): ''' if orig is None: orig = file try: - self.content = open(orig, 'rU').read() + self.content = open(orig, 'r').read() except IOError: # Couldn't open file; don't try to write anything in __del__ self.file = None @@ -218,7 +219,7 @@ class UpdateFile(object): XXX ''' if self.file is not None and self.content != self.orig: - print 'Updating ' + self.file + '...' + print('Updating ' + self.file + '...') open(self.file, 'w').write(self.content) if mode == 'post': diff --git a/bin/xmlagenda.py b/bin/xmlagenda.py index b3cd520..fcfe53e 100755 --- a/bin/xmlagenda.py +++ b/bin/xmlagenda.py @@ -18,6 +18,7 @@ # Grab the sort bar on the far left (just above the "1" for row one) # and move it down one row. (Row one becomes a floating header) # Voila! +from __future__ import print_function # The team members # FIXME: These names really should be external to this script @@ -89,7 +90,7 @@ for issue in issues: writer.writerow(['','','','','','','']) for member in team: writer.writerow(['','',member,'','','','']) -print "Exported %d issues to editlist.csv. Ready to upload to Google."%len(issues) +print("Exported %d issues to editlist.csv. Ready to upload to Google."%len(issues)) # Local Variables: # tab-width:4 diff --git a/bootstrap.py b/bootstrap.py index 26ef90e..58fde15 100755 --- a/bootstrap.py +++ b/bootstrap.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -# Copyright (c) 2001 - 2016 The SCons Foundation +# Copyright (c) 2001 - 2017 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -184,9 +184,15 @@ def main(): scons_py = os.path.join('src', 'script', 'scons.py') src_engine = os.path.join('src', 'engine') MANIFEST_in = find(os.path.join(src_engine, 'MANIFEST.in')) - - files = [ scons_py ] + [os.path.join(src_engine, x) - for x in parseManifestLines(os.path.join(script_dir, src_engine), open(MANIFEST_in).readlines())] + MANIFEST_xml_in = find(os.path.join(src_engine, 'MANIFEST-xml.in')) + manifest_files = [os.path.join(src_engine, x) + for x in parseManifestLines(os.path.join(script_dir, src_engine), + open(MANIFEST_in).readlines())] + + manifest_xml_files = [os.path.join(src_engine, x) + for x in parseManifestLines(os.path.join(script_dir, src_engine), + open(MANIFEST_xml_in).readlines())] + files = [ scons_py ] + manifest_files + manifest_xml_files for file in files: src = find(file) diff --git a/doc/SConscript b/doc/SConscript index d49b88c..46d4533 100644 --- a/doc/SConscript +++ b/doc/SConscript @@ -3,7 +3,7 @@ # # -# Copyright (c) 2001 - 2016 The SCons Foundation +# Copyright (c) 2001 - 2017 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -24,6 +24,8 @@ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +from __future__ import print_function + import os.path import re import sys @@ -51,7 +53,7 @@ fop = whereis('fop') xep = whereis('xep') if not fop and not xep: - print "doc: No PDF renderer found (fop|xep)!" + print("doc: No PDF renderer found (fop|xep)!") skip_doc = True # @@ -109,16 +111,17 @@ man_replace_tpl = """.TH "%(uctitle)s" "1" "%(today)s" "SCons %(version)s" "SCon .ad l .SH "NOTE" %(title)s \- This is a replacement file, stemming from an incomplete -packaging process without the required doc modules installed. Please +packaging process without the required doc modules installed. Please update the system and try running bootstrap.py again. """ # # --- Processing --- # + if skip_doc: - print "doc: ...skipping building User Guide." - print " ...creating fake MAN pages." + print("doc: ...skipping building User Guide.") + print(" ...creating fake MAN pages.") # Since the top-level SConstruct requires the MAN # pages to exist for the basic packaging, we create simple @@ -126,7 +129,7 @@ if skip_doc: scdir = os.path.join(build, 'man') if not os.path.isdir(scdir): os.makedirs(scdir) - + import datetime today = datetime.date.today().strftime("%m/%d/%Y") version = env.subst('$VERSION') @@ -140,8 +143,8 @@ if skip_doc: fman.close() else: if not lynx: - print "doc: Warning, lynx is not installed...created release packages won't be complete!" - + print("doc: Warning, lynx is not installed...created release packages won't be complete!") + # # Always create a version.xml file containing the version information # for this run. Ignore it for dependency purposes so we don't @@ -157,7 +160,7 @@ else: # # Builder for copying files to an Install dir, based # on their extension (better: glob matching pattern)... - # + # def _glob_install_action(target, source, env): if not SCons.Util.is_List(target): target = [target] @@ -170,7 +173,7 @@ else: target = [target] if not SCons.Util.is_List(source): source = [source] - + res = [] res_src = [] tdir = env.Dir(target[0]) @@ -185,7 +188,7 @@ else: # # Builder for copying ChunkedHTML files to an Install dir... - # + # def _chunked_install_action(target, source, env): if not SCons.Util.is_List(target): target = [target] @@ -195,13 +198,13 @@ else: spattern = os.path.join(os.path.split(str(source[0]))[0], '*.html') for g in glob.glob(spattern): shutil.copy(g, tdir) - + def _chunked_install_emitter(target, source, env): if not SCons.Util.is_List(target): target = [target] if not SCons.Util.is_List(source): source = [source] - + tdir = env.Dir(target[0]) head, tail = os.path.split(str(source[0])) return os.path.join(str(tdir), tail), source @@ -214,23 +217,23 @@ else: # Ensure that all XML files are valid against our XSD, and # that all example names and example output suffixes are unique # - print "Validating files against SCons XSD..." + print("Validating files against SCons XSD...") if SConsDoc.validate_all_xml(['src'], xsdfile='xsd/scons.xsd'): - print "OK" + print("OK") else: - print "Validation failed! Please correct the errors above and try again." - sys.exit(0) - - print "Checking whether all example names are unique..." + print("Validation failed! Please correct the errors above and try again.") + sys.exit(1) + + print("Checking whether all example names are unique...") if SConsExamples.exampleNamesAreUnique(os.path.join('doc','user')): - print "OK" + print("OK") else: - print "Not all example names and suffixes are unique! Please correct the errors listed above and try again." - sys.exit(0) - + print("Not all example names and suffixes are unique! Please correct the errors listed above and try again.") + sys.exit(1) + # List of prerequisite files in the build/doc folder buildsuite = [] - + def copy_dbfiles(env, toolpath, paths, fpattern, use_builddir=True): """ Helper function, copies a bunch of files matching the given fpattern to a target directory. @@ -251,7 +254,7 @@ else: target_dir = env.Dir(os.path.join(*(toolpath+paths))) buildsuite.extend(env.GlobInstall(target_dir, os.path.join(*(paths + fpattern)))) - + # # Copy generated files (.gen/.mod/.xml) to the build folder # @@ -300,7 +303,7 @@ else: # installing/copying them to the build directory. It basically # links the original sources to the respective build folder, # such that a simple 'python bootstrap.py' rebuilds the - # documentation when a file, like 'doc/user/depends.xml' + # documentation when a file, like 'doc/user/depends.xml' # for example, changes. # Finally, in DOCNODES we store the created PDF and HTML files, # such that we can then install them in the proper places for @@ -315,7 +318,7 @@ else: 'user' : (['chunked','html','pdf','epub','text'], [], []), 'man' : (['man','epub','text'], [], []) } - + # # We have to tell SCons to scan the top-level XML files which # get included by the document XML files in the subdirectories. @@ -327,15 +330,15 @@ else: continue base, ext = os.path.splitext(s) if ext in ['.fig', '.jpg']: - buildsuite.extend(env.Command(os.path.join(build, s), - s, + buildsuite.extend(env.Command(os.path.join(build, s), + s, Copy("$TARGET", "$SOURCE"))) else: revaction([env.File(os.path.join(build, s))], [env.File(s)], env) for doc in docs: - + # # Read MANIFEST file and copy the listed files to the # build directory, while branding them with the @@ -359,7 +362,7 @@ else: else: target_dir = os.path.join(build, doc) if ext in ['.fig', '.jpg', '.svg']: - docs[doc][DOCDEPENDS].extend(env.Command(build_s, doc_s, + docs[doc][DOCDEPENDS].extend(env.Command(build_s, doc_s, Copy("$TARGET", "$SOURCE"))) else: btarget = env.File(build_s) @@ -389,18 +392,18 @@ else: sctargets.append(env.File(os.path.join(scdir, 'scons-%s.pdf' % doc))) if 'epub' in docs[doc][DOCTARGETS]: sctargets.append(env.File(os.path.join(scdir, 'scons-%s.epub' % doc))) - + if 'man' in docs[doc][DOCTARGETS]: for m in man_page_list: sctargets.append(os.path.join(scdir, m)) man, _1 = os.path.splitext(m) - + sctargets.append(os.path.join(scdir, 'scons-%s.pdf' % man)) sctargets.append(os.path.join(scdir, 'scons-%s.html' % man)) - - docs[doc][DOCNODES].extend(env.Command(sctargets, buildsuite + docs[doc][DOCDEPENDS], + + docs[doc][DOCNODES].extend(env.Command(sctargets, buildsuite + docs[doc][DOCDEPENDS], "cd %s && $PYTHON ${SCONS_PY.abspath}%s" % (scdir, cleanopt))) - + install_css = False for doc in docs: @@ -412,13 +415,13 @@ else: epub = os.path.join(build, 'EPUB', 'scons-%s.epub' % doc) text = os.path.join(build, 'TEXT', 'scons-%s.txt' % doc) if 'chunked' in docs[doc][DOCTARGETS]: - installed_chtml = env.ChunkedInstall(env.Dir(htmldir), + installed_chtml = env.ChunkedInstall(env.Dir(htmldir), os.path.join(build, doc,'scons-%s' % doc, 'index.html')) installed_chtml_css = env.Install(env.Dir(htmldir), os.path.join(build, doc, 'scons.css')) env.Depends(installed_chtml, docs[doc][DOCNODES]) env.Depends(installed_chtml_css, docs[doc][DOCNODES]) - + tar_deps.extend([htmlindex, installed_chtml_css]) tar_list.extend([htmldir]) Local(htmlindex) @@ -431,7 +434,7 @@ else: Local(html) env.Ignore(html, version_xml) install_css = True - + if 'pdf' in docs[doc][DOCTARGETS]: env.InstallAs(env.File(pdf), env.File(os.path.join(build, doc,'scons-%s.pdf' % doc))) Local(pdf) @@ -447,14 +450,14 @@ else: tar_deps.append(epub) tar_list.append(epub) - - if ('text' in docs[doc][DOCTARGETS] and lynx and + + if ('text' in docs[doc][DOCTARGETS] and lynx and (('html' in docs[doc][DOCTARGETS]) or (doc == 'man'))): texthtml = os.path.join(build, doc,'index.html') if doc == 'man': # Special handling for single MAN file texthtml = os.path.join(build, doc, 'scons-scons.html') - + env.Command(text, env.File(texthtml), "lynx -dump ${SOURCE.abspath} > $TARGET") Local(text) @@ -462,21 +465,21 @@ else: tar_deps.append(text) tar_list.append(text) - - + + if 'man' in docs[doc][DOCTARGETS]: # # Man page(s) # for m in man_page_list: man, _1 = os.path.splitext(m) - + pdf = os.path.join(build, 'PDF', '%s-man.pdf' % man) html = os.path.join(build, 'HTML' , '%s-man.html' % man) - + env.InstallAs(env.File(pdf), env.File(os.path.join(build, 'man','scons-%s.pdf' % man))) env.InstallAs(env.File(html), env.File(os.path.join(build, 'man','scons-%s.html' % man))) - + tar_deps.extend([pdf, html]) tar_list.extend([pdf, html]) @@ -484,7 +487,7 @@ else: # Install CSS file, common to all single HTMLs if install_css: css_file = os.path.join(build, 'HTML', 'scons.css') - env.InstallAs(env.File(css_file), + env.InstallAs(env.File(css_file), env.File(os.path.join(build, 'user','scons.css'))) tar_deps.extend([css_file]) tar_list.extend([css_file]) @@ -540,7 +543,7 @@ if not epydoc_cli: # http://epydoc.svn.sourceforge.net/viewvc/epydoc/trunk/epydoc/src/epydoc/cli.py elif env['EPYDOCFLAGS'] == '--pdf': - pdf_writer = LatexWriter(docindex, + pdf_writer = LatexWriter(docindex, docformat='restructuredText', prj_name='SCons', prj_url='http://www.scons.org/') @@ -560,9 +563,9 @@ else: # epydoc_cli is found Touch('$TARGET'), ] - + if not epydoc_cli and not epydoc: - print "doc: epydoc not found, skipping building API documentation." + print("doc: epydoc not found, skipping building API documentation.") else: # XXX Should be in common with reading the same thing in # the SConstruct file. @@ -584,7 +587,7 @@ else: tar_list.append(htmldir) if not epydoc_cli: - print "doc: command line epydoc is not found, skipping PDF/PS/Tex output" + print("doc: command line epydoc is not found, skipping PDF/PS/Tex output") else: # PDF and PostScript and TeX are built from the # same invocation. @@ -617,7 +620,7 @@ if tar_deps: tar_list = ' '.join([x.replace(build+'/', '') for x in tar_list]) t = env.Command(dist_doc_tar_gz, tar_deps, "tar cf${TAR_HFLAG} - -C %s %s | gzip > $TARGET" % (build, tar_list)) - AddPostAction(dist_doc_tar_gz, Chmod(dist_doc_tar_gz, 0644)) + AddPostAction(dist_doc_tar_gz, Chmod(dist_doc_tar_gz, 0o644)) Local(t) Alias('doc', t) else: diff --git a/doc/design/SConstruct b/doc/design/SConstruct index d90dcfd..2bec66f 100644 --- a/doc/design/SConstruct +++ b/doc/design/SConstruct @@ -3,7 +3,7 @@ # # -# Copyright (c) 2001 - 2016 The SCons Foundation +# Copyright (c) 2001 - 2017 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the diff --git a/doc/design/acks.xml b/doc/design/acks.xml index 875daf7..f9969f4 100644 --- a/doc/design/acks.xml +++ b/doc/design/acks.xml @@ -12,7 +12,7 @@ @@ -2483,7 +2499,7 @@ foo = Object('foo.c') bar = Object('bar.c') objects = ['begin.o'] + foo + ['middle.o'] + bar + ['end.o'] for object in objects: - print str(object) + print(str(object)) Or you can use the @@ -2497,7 +2513,7 @@ foo = Object('foo.c') bar = Object('bar.c') objects = Flatten(['begin.o', foo, 'middle.o', bar, 'end.o']) for object in objects: - print str(object) + print(str(object)) Note also that because Builder calls return @@ -2541,7 +2557,7 @@ function: bar_obj_list = env.StaticObject('bar.c', CPPDEFINES='-DBAR') -print "The path to bar_obj is:", str(bar_obj_list[0]) +print("The path to bar_obj is:", str(bar_obj_list[0])) Note again that because the Builder call returns a list, @@ -2842,10 +2858,10 @@ of the tuple, respectively. Example: -print "first keyword, value =", ARGLIST[0][0], ARGLIST[0][1] -print "second keyword, value =", ARGLIST[1][0], ARGLIST[1][1] +print("first keyword, value =", ARGLIST[0][0], ARGLIST[0][1]) +print("second keyword, value =", ARGLIST[1][0], ARGLIST[1][1]) third_tuple = ARGLIST[2] -print "third keyword, value =", third_tuple[0], third_tuple[1] +print("third keyword, value =", third_tuple[0], third_tuple[1]) for key, value in ARGLIST: # process key and value @@ -2913,7 +2929,7 @@ for additional information. if 'foo' in BUILD_TARGETS: - print "Don't forget to test the `foo' program!" + print("Don't forget to test the `foo' program!") if 'special/program' in BUILD_TARGETS: SConscript('special') @@ -2951,7 +2967,7 @@ is explicitly being built. if 'foo' in COMMAND_LINE_TARGETS: - print "Don't forget to test the `foo' program!" + print("Don't forget to test the `foo' program!") if 'special/program' in COMMAND_LINE_TARGETS: SConscript('special') @@ -2975,9 +2991,9 @@ function to get at the path name for each Node. Example: -print str(DEFAULT_TARGETS[0]) +print(str(DEFAULT_TARGETS[0])) if 'foo' in map(str, DEFAULT_TARGETS): - print "Don't forget to test the `foo' program!" + print("Don't forget to test the `foo' program!") @@ -2990,13 +3006,13 @@ list change on on each successive call to the function: -print map(str, DEFAULT_TARGETS) # originally [] +print(map(str, DEFAULT_TARGETS)) # originally [] Default('foo') -print map(str, DEFAULT_TARGETS) # now a node ['foo'] +print(map(str, DEFAULT_TARGETS)) # now a node ['foo'] Default('bar') -print map(str, DEFAULT_TARGETS) # now a node ['foo', 'bar'] +print(map(str, DEFAULT_TARGETS)) # now a node ['foo', 'bar'] Default(None) -print map(str, DEFAULT_TARGETS) # back to [] +print(map(str, DEFAULT_TARGETS)) # back to [] Consequently, be sure to use @@ -3525,7 +3541,7 @@ a shared library, only that the compilation (not link) succeeds. env = Environment() conf = Configure( env ) if not conf.CheckCHeader( 'math.h' ): - print 'We really need math.h!' + print('We really need math.h!') Exit(1) if conf.CheckLibWithHeader( 'qt', 'qapp.h', 'c++', 'QApplication qapp(0,0);' ): @@ -3815,7 +3831,7 @@ int main(int argc, char **argv) { env = Environment() conf = Configure( env, custom_tests = { 'CheckQt' : CheckQt } ) if not conf.CheckQt('/usr/lib/qt'): - print 'We really need qt!' + print('We really need qt!') Exit(1) env = conf.Finish() @@ -3995,7 +4011,7 @@ not configured. env = Environment(variables=vars) for key, value in vars.UnknownVariables(): - print "unknown variable: %s=%s" % (key, value) + print("unknown variable: %s=%s" % (key, value)) @@ -4400,7 +4416,7 @@ File('foo.c').srcnode().path # source path of the given source file. # Builders also return File objects: foo = env.Program('foo.c') -print "foo will be built in %s"%foo.path +print("foo will be built in %s"%foo.path) A diff --git a/doc/man/scons_title.xsl b/doc/man/scons_title.xsl index 11de773..cc5ae5e 100644 --- a/doc/man/scons_title.xsl +++ b/doc/man/scons_title.xsl @@ -1,7 +1,7 @@ Node B(Pending) --> Node C (NoState) - ^ | - | | - +-------------------------------------+ + Next candidate \ + \ + Node A (Pending) --> Node B(Pending) --> Node C (NoState) + ^ | + | | + +-------------------------------------+ Now, when the Taskmaster examines the Node C's child Node A, it finds that Node A is in the "pending" state. Therefore, @@ -685,15 +708,14 @@ class Taskmaster(object): Pending children indicate that the Taskmaster has potentially loop back through a cycle. We say potentially because it could also occur when a DAG is evaluated in parallel. For example, - consider the following graph: - + consider the following graph:: - Node A (Pending) --> Node B(Pending) --> Node C (Pending) --> ... - | ^ - | | - +----------> Node D (NoState) --------+ - / - Next candidate / + Node A (Pending) --> Node B(Pending) --> Node C (Pending) --> ... + | ^ + | | + +----------> Node D (NoState) --------+ + / + Next candidate / The Taskmaster first evaluates the nodes A, B, and C and starts building some children of node C. Assuming, that the @@ -761,7 +783,7 @@ class Taskmaster(object): self.ready_exc = None T = self.trace - if T: T.write(u'\n' + self.trace_message('Looking for a node to evaluate')) + if T: T.write(SCons.Util.UnicodeType('\n') + self.trace_message('Looking for a node to evaluate')) while True: node = self.next_candidate() @@ -810,7 +832,7 @@ class Taskmaster(object): self.ready_exc = (SCons.Errors.ExplicitExit, e) if T: T.write(self.trace_message(' SystemExit')) return node - except Exception, e: + except Exception as e: # We had a problem just trying to figure out the # children (like a child couldn't be linked in to a # VariantDir, or a Scanner threw something). Arrange to @@ -840,13 +862,13 @@ class Taskmaster(object): if childstate <= NODE_EXECUTING: children_not_ready.append(child) - # These nodes have not even been visited yet. Add # them to the list so that on some next pass we can # take a stab at evaluating them (or their children). children_not_visited.reverse() self.candidates.extend(self.order(children_not_visited)) - #if T and children_not_visited: + + # if T and children_not_visited: # T.write(self.trace_message(' adding to candidates: %s' % map(str, children_not_visited))) # T.write(self.trace_message(' candidates now: %s\n' % map(str, self.candidates))) @@ -943,13 +965,13 @@ class Taskmaster(object): executor = node.get_executor() if executor is None: return None - + tlist = executor.get_all_targets() task = self.tasker(self, tlist, node in self.original_top, node) try: task.make_ready() - except: + except Exception as e : # We had a problem just trying to get this task ready (like # a child couldn't be linked to a VariantDir when deciding # whether this node is current). Arrange to raise the diff --git a/src/engine/SCons/TaskmasterTests.py b/src/engine/SCons/TaskmasterTests.py index b1bd9d6..fab54cf 100644 --- a/src/engine/SCons/TaskmasterTests.py +++ b/src/engine/SCons/TaskmasterTests.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2001 - 2016 The SCons Foundation +# Copyright (c) 2001 - 2017 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -22,7 +22,7 @@ # from __future__ import division -__revision__ = "src/engine/SCons/TaskmasterTests.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" +__revision__ = "src/engine/SCons/TaskmasterTests.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog" import SCons.compat @@ -697,7 +697,7 @@ class TaskmasterTestCase(unittest.TestCase): tm = SCons.Taskmaster.Taskmaster([n3]) try: t = tm.next_task() - except SCons.Errors.UserError, e: + except SCons.Errors.UserError as e: assert str(e) == "Dependency cycle: n3 -> n1 -> n2 -> n3", str(e) else: assert 'Did not catch expected UserError' @@ -849,14 +849,18 @@ class TaskmasterTestCase(unittest.TestCase): t = tm.next_task() t.exception_set((MyException, "exception value")) exc_caught = None + exc_actually_caught = None + exc_value = None try: t.prepare() - except MyException, e: + except MyException as e: exc_caught = 1 - except: + exc_value = e + except Exception as e: + exc_actually_caught = e pass - assert exc_caught, "did not catch expected MyException" - assert str(e) == "exception value", e + assert exc_caught, "did not catch expected MyException: %s"%exc_actually_caught + assert str(exc_value) == "exception value", exc_value assert built_text is None, built_text # Regression test, make sure we prepare not only @@ -904,7 +908,7 @@ class TaskmasterTestCase(unittest.TestCase): t = tm.next_task() try: t.prepare() - except Exception, e: + except Exception as e: assert str(e) == "Executor.prepare() exception", e else: raise AssertionError("did not catch expected exception") @@ -958,7 +962,7 @@ class TaskmasterTestCase(unittest.TestCase): t = tm.next_task() try: t.execute() - except SCons.Errors.BuildError, e: + except SCons.Errors.BuildError as e: assert e.node == n4, e.node assert e.errstr == "OtherError : ", e.errstr assert len(e.exc_info) == 3, e.exc_info @@ -1065,10 +1069,20 @@ class TaskmasterTestCase(unittest.TestCase): assert t.exception == 3 try: 1//0 - except: pass - t.exception_set(None) + except: + # Moved from below + t.exception_set(None) + #pass + +# import pdb; pdb.set_trace() + + # Having this here works for python 2.x, + # but it is a tuple (None, None, None) when called outside + # an except statement + # t.exception_set(None) + exc_type, exc_value, exc_tb = t.exception - assert exc_type is ZeroDivisionError, exc_type + assert exc_type is ZeroDivisionError, "Expecting ZeroDevisionError got:%s"%exc_type exception_values = [ "integer division or modulo", "integer division or modulo by zero", @@ -1078,13 +1092,14 @@ class TaskmasterTestCase(unittest.TestCase): class Exception1(Exception): pass - t.exception_set((Exception1, None)) + # Previously value was None, but while PY2 None = "", in Py3 None != "", so set to "" + t.exception_set((Exception1, "")) try: t.exception_raise() except: exc_type, exc_value = sys.exc_info()[:2] assert exc_type == Exception1, exc_type - assert str(exc_value) == '', exc_value + assert str(exc_value) == '', "Expecting empty string got:%s (type %s)"%(exc_value,type(exc_value)) else: assert 0, "did not catch expected exception" diff --git a/src/engine/SCons/Tool/386asm.py b/src/engine/SCons/Tool/386asm.py index 8fee694..b318c4b 100644 --- a/src/engine/SCons/Tool/386asm.py +++ b/src/engine/SCons/Tool/386asm.py @@ -10,7 +10,7 @@ selection method. """ # -# Copyright (c) 2001 - 2016 The SCons Foundation +# Copyright (c) 2001 - 2017 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -32,12 +32,12 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "src/engine/SCons/Tool/386asm.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" +__revision__ = "src/engine/SCons/Tool/386asm.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog" from SCons.Tool.PharLapCommon import addPharLapPaths import SCons.Util -as_module = __import__('as', globals(), locals(), []) +as_module = __import__('as', globals(), locals(), [], 1) def generate(env): """Add Builders and construction variables for ar to an Environment.""" diff --git a/src/engine/SCons/Tool/386asm.xml b/src/engine/SCons/Tool/386asm.xml index a29fc0f..80a2cd6 100644 --- a/src/engine/SCons/Tool/386asm.xml +++ b/src/engine/SCons/Tool/386asm.xml @@ -1,6 +1,6 @@ - - -%scons; - -%builders-mod; - -%functions-mod; - -%tools-mod; - -%variables-mod; -]> - - - - - - -Sets construction variables for the BitKeeper -source code control system. - - - -BITKEEPER -BITKEEPERGET -BITKEEPERGETFLAGS -BITKEEPERCOM - - -BITKEEPERCOMSTR - - - - - - -The BitKeeper executable. - - - - - - - -The command line for -fetching source files using BitKeeper. - - - - - - - -The string displayed when fetching -a source file using BitKeeper. -If this is not set, then &cv-link-BITKEEPERCOM; -(the command line) is displayed. - - - - - - - -The command (&cv-link-BITKEEPER;) and subcommand -for fetching source files using BitKeeper. - - - - - - - -Options that are passed to the BitKeeper -get -subcommand. - - - - - - -() - - - -A factory function that -returns a Builder object -to be used to fetch source files -using BitKeeper. -The returned Builder -is intended to be passed to the -&f-SourceCode; -function. - - - -This function is deprecated. For details, see the entry for the -&f-SourceCode; -function. - - - -Example: - - - -env.SourceCode('.', env.BitKeeper()) - - - - - diff --git a/src/engine/SCons/Tool/CVS.py b/src/engine/SCons/Tool/CVS.py deleted file mode 100644 index a8e5a8d..0000000 --- a/src/engine/SCons/Tool/CVS.py +++ /dev/null @@ -1,72 +0,0 @@ -"""SCons.Tool.CVS.py - -Tool-specific initialization for CVS. - -There normally shouldn't be any need to import this module directly. -It will usually be imported through the generic SCons.Tool.Tool() -selection method. - -""" - -# Copyright (c) 2001 - 2016 The SCons Foundation -# -# Permission is hereby granted, free of charge, to any person obtaining -# a copy of this software and associated documentation files (the -# "Software"), to deal in the Software without restriction, including -# without limitation the rights to use, copy, modify, merge, publish, -# distribute, sublicense, and/or sell copies of the Software, and to -# permit persons to whom the Software is furnished to do so, subject to -# the following conditions: -# -# The above copyright notice and this permission notice shall be included -# in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY -# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE -# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -__revision__ = "src/engine/SCons/Tool/CVS.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" - -import SCons.Action -import SCons.Builder -import SCons.Util - -def generate(env): - """Add a Builder factory function and construction variables for - CVS to an Environment.""" - - def CVSFactory(repos, module='', env=env): - """ """ - import SCons.Warnings as W - W.warn(W.DeprecatedSourceCodeWarning, """The CVS() factory is deprecated and there is no replacement.""") - # fail if repos is not an absolute path name? - if module != '': - # Don't use os.path.join() because the name we fetch might - # be across a network and must use POSIX slashes as separators. - module = module + '/' - env['CVSCOM'] = '$CVS $CVSFLAGS co $CVSCOFLAGS -d ${TARGET.dir} $CVSMODULE${TARGET.posix}' - act = SCons.Action.Action('$CVSCOM', '$CVSCOMSTR') - return SCons.Builder.Builder(action = act, - env = env, - CVSREPOSITORY = repos, - CVSMODULE = module) - - env.CVS = CVSFactory - - env['CVS'] = 'cvs' - env['CVSFLAGS'] = SCons.Util.CLVar('-d $CVSREPOSITORY') - env['CVSCOFLAGS'] = SCons.Util.CLVar('') - env['CVSCOM'] = '$CVS $CVSFLAGS co $CVSCOFLAGS ${TARGET.posix}' - -def exists(env): - return env.Detect('cvs') - -# Local Variables: -# tab-width:4 -# indent-tabs-mode:nil -# End: -# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/src/engine/SCons/Tool/CVS.xml b/src/engine/SCons/Tool/CVS.xml deleted file mode 100644 index b6ff10a..0000000 --- a/src/engine/SCons/Tool/CVS.xml +++ /dev/null @@ -1,159 +0,0 @@ - - - - -%scons; - -%builders-mod; - -%functions-mod; - -%tools-mod; - -%variables-mod; -]> - - - - - - -Sets construction variables for the CVS source code -management system. - - - -CVS -CVSCOM -CVSFLAGS -CVSCOFLAGS - - -CVSCOMSTR - - - - - - -The CVS executable. - - - - - - - -Options that are passed to the CVS checkout subcommand. - - - - - - - -The command line used to -fetch source files from a CVS repository. - - - - - - - -The string displayed when fetching -a source file from a CVS repository. -If this is not set, then &cv-link-CVSCOM; -(the command line) is displayed. - - - - - - - -General options that are passed to CVS. -By default, this is set to --d $CVSREPOSITORY -to specify from where the files must be fetched. - - - - - - - -The path to the CVS repository. -This is referenced in the default -&cv-link-CVSFLAGS; value. - - - - - - -(repository, module) - - - -A factory function that -returns a Builder object -to be used to fetch source files -from the specified -CVS -repository. -The returned Builder -is intended to be passed to the -&f-link-SourceCode; -function. - - - -This function is deprecated. For details, see the entry for the -&f-SourceCode; -function. - - - -The optional specified -module -will be added to the beginning -of all repository path names; -this can be used, in essence, -to strip initial directory names -from the repository path names, -so that you only have to -replicate part of the repository -directory hierarchy in your -local build directory. - - - -Examples: - - - -# Will fetch foo/bar/src.c -# from /usr/local/CVSROOT/foo/bar/src.c. -env.SourceCode('.', env.CVS('/usr/local/CVSROOT')) - -# Will fetch bar/src.c -# from /usr/local/CVSROOT/foo/bar/src.c. -env.SourceCode('.', env.CVS('/usr/local/CVSROOT', 'foo')) - -# Will fetch src.c -# from /usr/local/CVSROOT/foo/bar/src.c. -env.SourceCode('.', env.CVS('/usr/local/CVSROOT', 'foo/bar')) - - - - - diff --git a/src/engine/SCons/Tool/DCommon.py b/src/engine/SCons/Tool/DCommon.py index e2750a4..8973853 100644 --- a/src/engine/SCons/Tool/DCommon.py +++ b/src/engine/SCons/Tool/DCommon.py @@ -1,3 +1,5 @@ +from __future__ import print_function + """SCons.Tool.DCommon Common code for the various D tools. @@ -5,8 +7,9 @@ Common code for the various D tools. Coded by Russel Winder (russel@winder.org.uk) 2012-09-06 """ + # -# Copyright (c) 2001 - 2016 The SCons Foundation +# Copyright (c) 2001 - 2017 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -28,10 +31,11 @@ Coded by Russel Winder (russel@winder.org.uk) # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "src/engine/SCons/Tool/DCommon.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" +__revision__ = "src/engine/SCons/Tool/DCommon.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog" import os.path + def isD(env, source): if not source: return 0 @@ -42,6 +46,7 @@ def isD(env, source): return 1 return 0 + def addDPATHToEnv(env, executable): dPath = env.WhereIs(executable) if dPath: @@ -49,6 +54,14 @@ def addDPATHToEnv(env, executable): if os.path.isdir(phobosDir): env.Append(DPATH=[phobosDir]) + +def allAtOnceEmitter(target, source, env): + if env['DC'] in ('ldc2', 'dmd'): + env.SideEffect(str(target[0]) + '.o', target[0]) + env.Clean(target[0], str(target[0]) + '.o') + return target, source + + # Local Variables: # tab-width:4 # indent-tabs-mode:nil diff --git a/src/engine/SCons/Tool/DCommon.xml b/src/engine/SCons/Tool/DCommon.xml new file mode 100644 index 0000000..b1deb82 --- /dev/null +++ b/src/engine/SCons/Tool/DCommon.xml @@ -0,0 +1,71 @@ + + + + + %scons; + + %builders-mod; + + %functions-mod; + + %tools-mod; + + %variables-mod; + ]> + + + + + + + + + + + DRPATHPREFIX. + + + + + + + + DRPATHSUFFIX. + + + + + + + + + DShLibSonameGenerator. + + + + + + + + SHDLIBVERSION. + + + + + + + SHDLIBVERSIONFLAGS. + + + + + + diff --git a/src/engine/SCons/Tool/FortranCommon.py b/src/engine/SCons/Tool/FortranCommon.py index 058f24d..d2126a4 100644 --- a/src/engine/SCons/Tool/FortranCommon.py +++ b/src/engine/SCons/Tool/FortranCommon.py @@ -5,7 +5,7 @@ Stuff for processing Fortran, common to all fortran dialects. """ # -# Copyright (c) 2001 - 2016 The SCons Foundation +# Copyright (c) 2001 - 2017 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -26,8 +26,9 @@ Stuff for processing Fortran, common to all fortran dialects. # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # +from __future__ import print_function -__revision__ = "src/engine/SCons/Tool/FortranCommon.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" +__revision__ = "src/engine/SCons/Tool/FortranCommon.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog" import re import os.path @@ -61,7 +62,7 @@ def isfortran(env, source): def _fortranEmitter(target, source, env): node = source[0].rfile() if not node.exists() and not node.is_derived(): - print "Could not locate " + str(node.name) + print("Could not locate " + str(node.name)) return ([], []) mod_regex = """(?i)^\s*MODULE\s+(?!PROCEDURE)(\w+)""" cre = re.compile(mod_regex,re.M) @@ -167,7 +168,7 @@ def add_fortran_to_env(env): except KeyError: FortranSuffixes = ['.f', '.for', '.ftn'] - #print "Adding %s to fortran suffixes" % FortranSuffixes + #print("Adding %s to fortran suffixes" % FortranSuffixes) try: FortranPPSuffixes = env['FORTRANPPFILESUFFIXES'] except KeyError: @@ -191,7 +192,7 @@ def add_f77_to_env(env): except KeyError: F77Suffixes = ['.f77'] - #print "Adding %s to f77 suffixes" % F77Suffixes + #print("Adding %s to f77 suffixes" % F77Suffixes) try: F77PPSuffixes = env['F77PPFILESUFFIXES'] except KeyError: @@ -206,7 +207,7 @@ def add_f90_to_env(env): except KeyError: F90Suffixes = ['.f90'] - #print "Adding %s to f90 suffixes" % F90Suffixes + #print("Adding %s to f90 suffixes" % F90Suffixes) try: F90PPSuffixes = env['F90PPFILESUFFIXES'] except KeyError: @@ -222,7 +223,7 @@ def add_f95_to_env(env): except KeyError: F95Suffixes = ['.f95'] - #print "Adding %s to f95 suffixes" % F95Suffixes + #print("Adding %s to f95 suffixes" % F95Suffixes) try: F95PPSuffixes = env['F95PPFILESUFFIXES'] except KeyError: @@ -238,7 +239,7 @@ def add_f03_to_env(env): except KeyError: F03Suffixes = ['.f03'] - #print "Adding %s to f95 suffixes" % F95Suffixes + #print("Adding %s to f95 suffixes" % F95Suffixes) try: F03PPSuffixes = env['F03PPFILESUFFIXES'] except KeyError: diff --git a/src/engine/SCons/Tool/GettextCommon.py b/src/engine/SCons/Tool/GettextCommon.py index 596586c..b475d8f 100644 --- a/src/engine/SCons/Tool/GettextCommon.py +++ b/src/engine/SCons/Tool/GettextCommon.py @@ -3,7 +3,7 @@ Used by several tools of `gettext` toolset. """ -# Copyright (c) 2001 - 2016 The SCons Foundation +# Copyright (c) 2001 - 2017 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -24,20 +24,37 @@ Used by several tools of `gettext` toolset. # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -__revision__ = "src/engine/SCons/Tool/GettextCommon.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" +__revision__ = "src/engine/SCons/Tool/GettextCommon.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog" import SCons.Warnings import re + ############################################################################# class XgettextToolWarning(SCons.Warnings.Warning): pass + + class XgettextNotFound(XgettextToolWarning): pass + + class MsginitToolWarning(SCons.Warnings.Warning): pass + + class MsginitNotFound(MsginitToolWarning): pass + + class MsgmergeToolWarning(SCons.Warnings.Warning): pass + + class MsgmergeNotFound(MsgmergeToolWarning): pass + + class MsgfmtToolWarning(SCons.Warnings.Warning): pass + + class MsgfmtNotFound(MsgfmtToolWarning): pass + + ############################################################################# SCons.Warnings.enableWarningClass(XgettextToolWarning) SCons.Warnings.enableWarningClass(XgettextNotFound) @@ -47,367 +64,406 @@ SCons.Warnings.enableWarningClass(MsgmergeToolWarning) SCons.Warnings.enableWarningClass(MsgmergeNotFound) SCons.Warnings.enableWarningClass(MsgfmtToolWarning) SCons.Warnings.enableWarningClass(MsgfmtNotFound) + + ############################################################################# ############################################################################# class _POTargetFactory(object): - """ A factory of `PO` target files. - - Factory defaults differ from these of `SCons.Node.FS.FS`. We set `precious` - (this is required by builders and actions gettext) and `noclean` flags by - default for all produced nodes. - """ - def __init__( self, env, nodefault = True, alias = None, precious = True - , noclean = True ): - """ Object constructor. - - **Arguments** - - - *env* (`SCons.Environment.Environment`) - - *nodefault* (`boolean`) - if `True`, produced nodes will be ignored - from default target `'.'` - - *alias* (`string`) - if provided, produced nodes will be automatically - added to this alias, and alias will be set as `AlwaysBuild` - - *precious* (`boolean`) - if `True`, the produced nodes will be set as - `Precious`. - - *noclen* (`boolean`) - if `True`, the produced nodes will be excluded - from `Clean`. + """ A factory of `PO` target files. + + Factory defaults differ from these of `SCons.Node.FS.FS`. We set `precious` + (this is required by builders and actions gettext) and `noclean` flags by + default for all produced nodes. """ - self.env = env - self.alias = alias - self.precious = precious - self.noclean = noclean - self.nodefault = nodefault - - def _create_node(self, name, factory, directory = None, create = 1): - """ Create node, and set it up to factory settings. """ - import SCons.Util - node = factory(name, directory, create) - node.set_noclean(self.noclean) - node.set_precious(self.precious) - if self.nodefault: - self.env.Ignore('.', node) - if self.alias: - self.env.AlwaysBuild(self.env.Alias(self.alias, node)) - return node - - def Entry(self, name, directory = None, create = 1): - """ Create `SCons.Node.FS.Entry` """ - return self._create_node(name, self.env.fs.Entry, directory, create) - - def File(self, name, directory = None, create = 1): - """ Create `SCons.Node.FS.File` """ - return self._create_node(name, self.env.fs.File, directory, create) + + def __init__(self, env, nodefault=True, alias=None, precious=True + , noclean=True): + """ Object constructor. + + **Arguments** + + - *env* (`SCons.Environment.Environment`) + - *nodefault* (`boolean`) - if `True`, produced nodes will be ignored + from default target `'.'` + - *alias* (`string`) - if provided, produced nodes will be automatically + added to this alias, and alias will be set as `AlwaysBuild` + - *precious* (`boolean`) - if `True`, the produced nodes will be set as + `Precious`. + - *noclen* (`boolean`) - if `True`, the produced nodes will be excluded + from `Clean`. + """ + self.env = env + self.alias = alias + self.precious = precious + self.noclean = noclean + self.nodefault = nodefault + + def _create_node(self, name, factory, directory=None, create=1): + """ Create node, and set it up to factory settings. """ + import SCons.Util + node = factory(name, directory, create) + node.set_noclean(self.noclean) + node.set_precious(self.precious) + if self.nodefault: + self.env.Ignore('.', node) + if self.alias: + self.env.AlwaysBuild(self.env.Alias(self.alias, node)) + return node + + def Entry(self, name, directory=None, create=1): + """ Create `SCons.Node.FS.Entry` """ + return self._create_node(name, self.env.fs.Entry, directory, create) + + def File(self, name, directory=None, create=1): + """ Create `SCons.Node.FS.File` """ + return self._create_node(name, self.env.fs.File, directory, create) + + ############################################################################# ############################################################################# _re_comment = re.compile(r'(#[^\n\r]+)$', re.M) _re_lang = re.compile(r'([a-zA-Z0-9_]+)', re.M) + + ############################################################################# -def _read_linguas_from_files(env, linguas_files = None): - """ Parse `LINGUAS` file and return list of extracted languages """ - import SCons.Util - import SCons.Environment - global _re_comment - global _re_lang - if not SCons.Util.is_List(linguas_files) \ - and not SCons.Util.is_String(linguas_files) \ - and not isinstance(linguas_files, SCons.Node.FS.Base) \ - and linguas_files: - # If, linguas_files==True or such, then read 'LINGUAS' file. - linguas_files = [ 'LINGUAS' ] - if linguas_files is None: - return [] - fnodes = env.arg2nodes(linguas_files) - linguas = [] - for fnode in fnodes: - contents = _re_comment.sub("", fnode.get_text_contents()) - ls = [ l for l in _re_lang.findall(contents) if l ] - linguas.extend(ls) - return linguas +def _read_linguas_from_files(env, linguas_files=None): + """ Parse `LINGUAS` file and return list of extracted languages """ + import SCons.Util + import SCons.Environment + global _re_comment + global _re_lang + if not SCons.Util.is_List(linguas_files) \ + and not SCons.Util.is_String(linguas_files) \ + and not isinstance(linguas_files, SCons.Node.FS.Base) \ + and linguas_files: + # If, linguas_files==True or such, then read 'LINGUAS' file. + linguas_files = ['LINGUAS'] + if linguas_files is None: + return [] + fnodes = env.arg2nodes(linguas_files) + linguas = [] + for fnode in fnodes: + contents = _re_comment.sub("", fnode.get_text_contents()) + ls = [l for l in _re_lang.findall(contents) if l] + linguas.extend(ls) + return linguas + + ############################################################################# ############################################################################# from SCons.Builder import BuilderBase + + ############################################################################# class _POFileBuilder(BuilderBase): - """ `PO` file builder. - - This is multi-target single-source builder. In typical situation the source - is single `POT` file, e.g. `messages.pot`, and there are multiple `PO` - targets to be updated from this `POT`. We must run - `SCons.Builder.BuilderBase._execute()` separatelly for each target to track - dependencies separatelly for each target file. + """ `PO` file builder. - **NOTE**: if we call `SCons.Builder.BuilderBase._execute(.., target, ...)` - with target being list of all targets, all targets would be rebuilt each time - one of the targets from this list is missing. This would happen, for example, - when new language `ll` enters `LINGUAS_FILE` (at this moment there is no - `ll.po` file yet). To avoid this, we override - `SCons.Builder.BuilerBase._execute()` and call it separatelly for each - target. Here we also append to the target list the languages read from - `LINGUAS_FILE`. - """ - # - #* The argument for overriding _execute(): We must use environment with - # builder overrides applied (see BuilderBase.__init__(). Here it comes for - # free. - #* The argument against using 'emitter': The emitter is called too late - # by BuilderBase._execute(). If user calls, for example: - # - # env.POUpdate(LINGUAS_FILE = 'LINGUAS') - # - # the builder throws error, because it is called with target=None, - # source=None and is trying to "generate" sources or target list first. - # If user calls - # - # env.POUpdate(['foo', 'baz'], LINGUAS_FILE = 'LINGUAS') - # - # the env.BuilderWrapper() calls our builder with target=None, - # source=['foo', 'baz']. The BuilderBase._execute() then splits execution - # and execute iterativelly (recursion) self._execute(None, source[i]). - # After that it calls emitter (which is quite too late). The emitter is - # also called in each iteration, what makes things yet worse. - def __init__(self, env, **kw): - if not 'suffix' in kw: - kw['suffix'] = '$POSUFFIX' - if not 'src_suffix' in kw: - kw['src_suffix'] = '$POTSUFFIX' - if not 'src_builder' in kw: - kw['src_builder'] = '_POTUpdateBuilder' - if not 'single_source' in kw: - kw['single_source'] = True - alias = None - if 'target_alias' in kw: - alias = kw['target_alias'] - del kw['target_alias'] - if not 'target_factory' in kw: - kw['target_factory'] = _POTargetFactory(env, alias=alias).File - BuilderBase.__init__(self, **kw) - - def _execute(self, env, target, source, *args, **kw): - """ Execute builder's actions. + This is multi-target single-source builder. In typical situation the source + is single `POT` file, e.g. `messages.pot`, and there are multiple `PO` + targets to be updated from this `POT`. We must run + `SCons.Builder.BuilderBase._execute()` separatelly for each target to track + dependencies separatelly for each target file. - Here we append to `target` the languages read from `$LINGUAS_FILE` and - apply `SCons.Builder.BuilderBase._execute()` separatelly to each target. - The arguments and return value are same as for - `SCons.Builder.BuilderBase._execute()`. + **NOTE**: if we call `SCons.Builder.BuilderBase._execute(.., target, ...)` + with target being list of all targets, all targets would be rebuilt each time + one of the targets from this list is missing. This would happen, for example, + when new language `ll` enters `LINGUAS_FILE` (at this moment there is no + `ll.po` file yet). To avoid this, we override + `SCons.Builder.BuilerBase._execute()` and call it separatelly for each + target. Here we also append to the target list the languages read from + `LINGUAS_FILE`. """ - import SCons.Util - import SCons.Node - linguas_files = None - if env.has_key('LINGUAS_FILE') and env['LINGUAS_FILE']: - linguas_files = env['LINGUAS_FILE'] - # This prevents endless recursion loop (we'll be invoked once for - # each target appended here, we must not extend the list again). - env['LINGUAS_FILE'] = None - linguas = _read_linguas_from_files(env,linguas_files) - if SCons.Util.is_List(target): - target.extend(linguas) - elif target is not None: - target = [target] + linguas - else: - target = linguas - if not target: - # Let the SCons.BuilderBase to handle this patologic situation - return BuilderBase._execute( self, env, target, source, *args, **kw) - # The rest is ours - if not SCons.Util.is_List(target): - target = [ target ] - result = [] - for tgt in target: - r = BuilderBase._execute( self, env, [tgt], source, *args, **kw) - result.extend(r) - if linguas_files is not None: - env['LINGUAS_FILE'] = linguas_files - return SCons.Node.NodeList(result) + + # + # * The argument for overriding _execute(): We must use environment with + # builder overrides applied (see BuilderBase.__init__(). Here it comes for + # free. + # * The argument against using 'emitter': The emitter is called too late + # by BuilderBase._execute(). If user calls, for example: + # + # env.POUpdate(LINGUAS_FILE = 'LINGUAS') + # + # the builder throws error, because it is called with target=None, + # source=None and is trying to "generate" sources or target list first. + # If user calls + # + # env.POUpdate(['foo', 'baz'], LINGUAS_FILE = 'LINGUAS') + # + # the env.BuilderWrapper() calls our builder with target=None, + # source=['foo', 'baz']. The BuilderBase._execute() then splits execution + # and execute iterativelly (recursion) self._execute(None, source[i]). + # After that it calls emitter (which is quite too late). The emitter is + # also called in each iteration, what makes things yet worse. + def __init__(self, env, **kw): + if not 'suffix' in kw: + kw['suffix'] = '$POSUFFIX' + if not 'src_suffix' in kw: + kw['src_suffix'] = '$POTSUFFIX' + if not 'src_builder' in kw: + kw['src_builder'] = '_POTUpdateBuilder' + if not 'single_source' in kw: + kw['single_source'] = True + alias = None + if 'target_alias' in kw: + alias = kw['target_alias'] + del kw['target_alias'] + if not 'target_factory' in kw: + kw['target_factory'] = _POTargetFactory(env, alias=alias).File + BuilderBase.__init__(self, **kw) + + def _execute(self, env, target, source, *args, **kw): + """ Execute builder's actions. + + Here we append to `target` the languages read from `$LINGUAS_FILE` and + apply `SCons.Builder.BuilderBase._execute()` separatelly to each target. + The arguments and return value are same as for + `SCons.Builder.BuilderBase._execute()`. + """ + import SCons.Util + import SCons.Node + linguas_files = None + if 'LINGUAS_FILE' in env and env['LINGUAS_FILE']: + linguas_files = env['LINGUAS_FILE'] + # This prevents endless recursion loop (we'll be invoked once for + # each target appended here, we must not extend the list again). + env['LINGUAS_FILE'] = None + linguas = _read_linguas_from_files(env, linguas_files) + if SCons.Util.is_List(target): + target.extend(linguas) + elif target is not None: + target = [target] + linguas + else: + target = linguas + if not target: + # Let the SCons.BuilderBase to handle this patologic situation + return BuilderBase._execute(self, env, target, source, *args, **kw) + # The rest is ours + if not SCons.Util.is_List(target): + target = [target] + result = [] + for tgt in target: + r = BuilderBase._execute(self, env, [tgt], source, *args, **kw) + result.extend(r) + if linguas_files is not None: + env['LINGUAS_FILE'] = linguas_files + return SCons.Node.NodeList(result) + + ############################################################################# import SCons.Environment + + ############################################################################# def _translate(env, target=None, source=SCons.Environment._null, *args, **kw): - """ Function for `Translate()` pseudo-builder """ - if target is None: target = [] - pot = env.POTUpdate(None, source, *args, **kw) - po = env.POUpdate(target, pot, *args, **kw) - return po + """ Function for `Translate()` pseudo-builder """ + if target is None: target = [] + pot = env.POTUpdate(None, source, *args, **kw) + po = env.POUpdate(target, pot, *args, **kw) + return po + + ############################################################################# ############################################################################# class RPaths(object): - """ Callable object, which returns pathnames relative to SCons current - working directory. - - It seems like `SCons.Node.FS.Base.get_path()` returns absolute paths - for nodes that are outside of current working directory (`env.fs.getcwd()`). - Here, we often have `SConscript`, `POT` and `PO` files within `po/` - directory and source files (e.g. `*.c`) outside of it. When generating `POT` - template file, references to source files are written to `POT` template, so - a translator may later quickly jump to appropriate source file and line from - its `PO` editor (e.g. `poedit`). Relative paths in `PO` file are usually - interpreted by `PO` editor as paths relative to the place, where `PO` file - lives. The absolute paths would make resultant `POT` file nonportable, as - the references would be correct only on the machine, where `POT` file was - recently re-created. For such reason, we need a function, which always - returns relative paths. This is the purpose of `RPaths` callable object. - - The `__call__` method returns paths relative to current working directory, but - we assume, that *xgettext(1)* is run from the directory, where target file is - going to be created. - - Note, that this may not work for files distributed over several hosts or - across different drives on windows. We assume here, that single local - filesystem holds both source files and target `POT` templates. - - Intended use of `RPaths` - in `xgettext.py`:: - - def generate(env): - from GettextCommon import RPaths - ... - sources = '$( ${_concat( "", SOURCES, "", __env__, XgettextRPaths, TARGET, SOURCES)} $)' - env.Append( - ... - XGETTEXTCOM = 'XGETTEXT ... ' + sources, - ... - XgettextRPaths = RPaths(env) - ) - """ - # NOTE: This callable object returns pathnames of dirs/files relative to - # current working directory. The pathname remains relative also for entries - # that are outside of current working directory (node, that - # SCons.Node.FS.File and siblings return absolute path in such case). For - # simplicity we compute path relative to current working directory, this - # seems be enough for our purposes (don't need TARGET variable and - # SCons.Defaults.Variable_Caller stuff). + """ Callable object, which returns pathnames relative to SCons current + working directory. - def __init__(self, env): - """ Initialize `RPaths` callable object. - - **Arguments**: - - - *env* - a `SCons.Environment.Environment` object, defines *current - working dir*. + It seems like `SCons.Node.FS.Base.get_path()` returns absolute paths + for nodes that are outside of current working directory (`env.fs.getcwd()`). + Here, we often have `SConscript`, `POT` and `PO` files within `po/` + directory and source files (e.g. `*.c`) outside of it. When generating `POT` + template file, references to source files are written to `POT` template, so + a translator may later quickly jump to appropriate source file and line from + its `PO` editor (e.g. `poedit`). Relative paths in `PO` file are usually + interpreted by `PO` editor as paths relative to the place, where `PO` file + lives. The absolute paths would make resultant `POT` file nonportable, as + the references would be correct only on the machine, where `POT` file was + recently re-created. For such reason, we need a function, which always + returns relative paths. This is the purpose of `RPaths` callable object. + + The `__call__` method returns paths relative to current working directory, but + we assume, that *xgettext(1)* is run from the directory, where target file is + going to be created. + + Note, that this may not work for files distributed over several hosts or + across different drives on windows. We assume here, that single local + filesystem holds both source files and target `POT` templates. + + Intended use of `RPaths` - in `xgettext.py`:: + + def generate(env): + from GettextCommon import RPaths + ... + sources = '$( ${_concat( "", SOURCES, "", __env__, XgettextRPaths, TARGET, SOURCES)} $)' + env.Append( + ... + XGETTEXTCOM = 'XGETTEXT ... ' + sources, + ... + XgettextRPaths = RPaths(env) + ) """ - self.env = env - # FIXME: I'm not sure, how it should be implemented (what the *args are in - # general, what is **kw). - def __call__(self, nodes, *args, **kw): - """ Return nodes' paths (strings) relative to current working directory. - - **Arguments**: + # NOTE: This callable object returns pathnames of dirs/files relative to + # current working directory. The pathname remains relative also for entries + # that are outside of current working directory (node, that + # SCons.Node.FS.File and siblings return absolute path in such case). For + # simplicity we compute path relative to current working directory, this + # seems be enough for our purposes (don't need TARGET variable and + # SCons.Defaults.Variable_Caller stuff). - - *nodes* ([`SCons.Node.FS.Base`]) - list of nodes. - - *args* - currently unused. - - *kw* - currently unused. + def __init__(self, env): + """ Initialize `RPaths` callable object. + + **Arguments**: + + - *env* - a `SCons.Environment.Environment` object, defines *current + working dir*. + """ + self.env = env + + # FIXME: I'm not sure, how it should be implemented (what the *args are in + # general, what is **kw). + def __call__(self, nodes, *args, **kw): + """ Return nodes' paths (strings) relative to current working directory. + + **Arguments**: + + - *nodes* ([`SCons.Node.FS.Base`]) - list of nodes. + - *args* - currently unused. + - *kw* - currently unused. + + **Returns**: + + - Tuple of strings, which represent paths relative to current working + directory (for given environment). + """ + import os + import SCons.Node.FS + rpaths = () + cwd = self.env.fs.getcwd().get_abspath() + for node in nodes: + rpath = None + if isinstance(node, SCons.Node.FS.Base): + rpath = os.path.relpath(node.get_abspath(), cwd) + # FIXME: Other types possible here? + if rpath is not None: + rpaths += (rpath,) + return rpaths - **Returns**: - - Tuple of strings, which represent paths relative to current working - directory (for given environment). - """ - import os - import SCons.Node.FS - rpaths = () - cwd = self.env.fs.getcwd().get_abspath() - for node in nodes: - rpath = None - if isinstance(node, SCons.Node.FS.Base): - rpath = os.path.relpath(node.get_abspath(), cwd) - # FIXME: Other types possible here? - if rpath is not None: - rpaths += (rpath,) - return rpaths ############################################################################# - + ############################################################################# def _init_po_files(target, source, env): - """ Action function for `POInit` builder. """ - nop = lambda target, source, env : 0 - if env.has_key('POAUTOINIT'): - autoinit = env['POAUTOINIT'] - else: - autoinit = False - # Well, if everything outside works well, this loop should do single - # iteration. Otherwise we are rebuilding all the targets even, if just - # one has changed (but is this our fault?). - for tgt in target: - if not tgt.exists(): - if autoinit: - action = SCons.Action.Action('$MSGINITCOM', '$MSGINITCOMSTR') - else: - msg = 'File ' + repr(str(tgt)) + ' does not exist. ' \ - + 'If you are a translator, you can create it through: \n' \ - + '$MSGINITCOM' - action = SCons.Action.Action(nop, msg) - status = action([tgt], source, env) - if status: return status - return 0 + """ Action function for `POInit` builder. """ + nop = lambda target, source, env: 0 + if 'POAUTOINIT' in env: + autoinit = env['POAUTOINIT'] + else: + autoinit = False + # Well, if everything outside works well, this loop should do single + # iteration. Otherwise we are rebuilding all the targets even, if just + # one has changed (but is this our fault?). + for tgt in target: + if not tgt.exists(): + if autoinit: + action = SCons.Action.Action('$MSGINITCOM', '$MSGINITCOMSTR') + else: + msg = 'File ' + repr(str(tgt)) + ' does not exist. ' \ + + 'If you are a translator, you can create it through: \n' \ + + '$MSGINITCOM' + action = SCons.Action.Action(nop, msg) + status = action([tgt], source, env) + if status: return status + return 0 + + ############################################################################# ############################################################################# def _detect_xgettext(env): - """ Detects *xgettext(1)* binary """ - if env.has_key('XGETTEXT'): - return env['XGETTEXT'] - xgettext = env.Detect('xgettext'); - if xgettext: - return xgettext - raise SCons.Errors.StopError(XgettextNotFound,"Could not detect xgettext") - return None + """ Detects *xgettext(1)* binary """ + if 'XGETTEXT' in env: + return env['XGETTEXT'] + xgettext = env.Detect('xgettext'); + if xgettext: + return xgettext + raise SCons.Errors.StopError(XgettextNotFound, "Could not detect xgettext") + return None + + ############################################################################# def _xgettext_exists(env): - return _detect_xgettext(env) + return _detect_xgettext(env) + + ############################################################################# ############################################################################# def _detect_msginit(env): - """ Detects *msginit(1)* program. """ - if env.has_key('MSGINIT'): - return env['MSGINIT'] - msginit = env.Detect('msginit'); - if msginit: - return msginit - raise SCons.Errors.StopError(MsginitNotFound, "Could not detect msginit") - return None + """ Detects *msginit(1)* program. """ + if 'MSGINIT' in env: + return env['MSGINIT'] + msginit = env.Detect('msginit'); + if msginit: + return msginit + raise SCons.Errors.StopError(MsginitNotFound, "Could not detect msginit") + return None + + ############################################################################# def _msginit_exists(env): - return _detect_msginit(env) + return _detect_msginit(env) + + ############################################################################# ############################################################################# def _detect_msgmerge(env): - """ Detects *msgmerge(1)* program. """ - if env.has_key('MSGMERGE'): - return env['MSGMERGE'] - msgmerge = env.Detect('msgmerge'); - if msgmerge: - return msgmerge - raise SCons.Errors.StopError(MsgmergeNotFound, "Could not detect msgmerge") - return None + """ Detects *msgmerge(1)* program. """ + if 'MSGMERGE' in env: + return env['MSGMERGE'] + msgmerge = env.Detect('msgmerge'); + if msgmerge: + return msgmerge + raise SCons.Errors.StopError(MsgmergeNotFound, "Could not detect msgmerge") + return None + + ############################################################################# def _msgmerge_exists(env): - return _detect_msgmerge(env) + return _detect_msgmerge(env) + + ############################################################################# ############################################################################# def _detect_msgfmt(env): - """ Detects *msgmfmt(1)* program. """ - if env.has_key('MSGFMT'): - return env['MSGFMT'] - msgfmt = env.Detect('msgfmt'); - if msgfmt: - return msgfmt - raise SCons.Errors.StopError(MsgfmtNotFound, "Could not detect msgfmt") - return None + """ Detects *msgmfmt(1)* program. """ + if 'MSGFMT' in env: + return env['MSGFMT'] + msgfmt = env.Detect('msgfmt'); + if msgfmt: + return msgfmt + raise SCons.Errors.StopError(MsgfmtNotFound, "Could not detect msgfmt") + return None + + ############################################################################# def _msgfmt_exists(env): - return _detect_msgfmt(env) + return _detect_msgfmt(env) + + ############################################################################# ############################################################################# def tool_list(platform, env): - """ List tools that shall be generated by top-level `gettext` tool """ - return [ 'xgettext', 'msginit', 'msgmerge', 'msgfmt' ] -############################################################################# + """ List tools that shall be generated by top-level `gettext` tool """ + return ['xgettext', 'msginit', 'msgmerge', 'msgfmt'] +############################################################################# diff --git a/src/engine/SCons/Tool/JavaCommon.py b/src/engine/SCons/Tool/JavaCommon.py index 38f4e47..5c2507d 100644 --- a/src/engine/SCons/Tool/JavaCommon.py +++ b/src/engine/SCons/Tool/JavaCommon.py @@ -5,7 +5,7 @@ Stuff for processing Java. """ # -# Copyright (c) 2001 - 2016 The SCons Foundation +# Copyright (c) 2001 - 2017 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -27,7 +27,7 @@ Stuff for processing Java. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "src/engine/SCons/Tool/JavaCommon.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" +__revision__ = "src/engine/SCons/Tool/JavaCommon.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog" import os import os.path diff --git a/src/engine/SCons/Tool/JavaCommonTests.py b/src/engine/SCons/Tool/JavaCommonTests.py index 6a67370..da405f0 100644 --- a/src/engine/SCons/Tool/JavaCommonTests.py +++ b/src/engine/SCons/Tool/JavaCommonTests.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2001 - 2016 The SCons Foundation +# Copyright (c) 2001 - 2017 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -21,7 +21,7 @@ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "src/engine/SCons/Tool/JavaCommonTests.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" +__revision__ = "src/engine/SCons/Tool/JavaCommonTests.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog" import os.path import sys diff --git a/src/engine/SCons/Tool/MSCommon/__init__.py b/src/engine/SCons/Tool/MSCommon/__init__.py index 6b637fe..989ab08 100644 --- a/src/engine/SCons/Tool/MSCommon/__init__.py +++ b/src/engine/SCons/Tool/MSCommon/__init__.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2001 - 2016 The SCons Foundation +# Copyright (c) 2001 - 2017 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -21,7 +21,7 @@ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "src/engine/SCons/Tool/MSCommon/__init__.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" +__revision__ = "src/engine/SCons/Tool/MSCommon/__init__.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog" __doc__ = """ Common functions for Microsoft Visual Studio and Visual C/C++. @@ -41,7 +41,8 @@ from SCons.Tool.MSCommon.sdk import mssdk_exists, \ from SCons.Tool.MSCommon.vc import msvc_exists, \ msvc_setup_env, \ - msvc_setup_env_once + msvc_setup_env_once, \ + msvc_version_to_maj_min from SCons.Tool.MSCommon.vs import get_default_version, \ get_vs_by_version, \ diff --git a/src/engine/SCons/Tool/MSCommon/arch.py b/src/engine/SCons/Tool/MSCommon/arch.py index 46fb601..96f05a8 100644 --- a/src/engine/SCons/Tool/MSCommon/arch.py +++ b/src/engine/SCons/Tool/MSCommon/arch.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2001 - 2016 The SCons Foundation +# Copyright (c) 2001 - 2017 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -21,7 +21,7 @@ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "src/engine/SCons/Tool/MSCommon/arch.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" +__revision__ = "src/engine/SCons/Tool/MSCommon/arch.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog" __doc__ = """Module to define supported Windows chip architectures. """ diff --git a/src/engine/SCons/Tool/MSCommon/common.py b/src/engine/SCons/Tool/MSCommon/common.py index 1467543..fcf623f 100644 --- a/src/engine/SCons/Tool/MSCommon/common.py +++ b/src/engine/SCons/Tool/MSCommon/common.py @@ -1,5 +1,8 @@ +""" +Common helper functions for working with the Microsoft tool chain. +""" # -# Copyright (c) 2001 - 2016 The SCons Foundation +# Copyright (c) 2001 - 2017 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -20,12 +23,9 @@ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # +from __future__ import print_function -__revision__ = "src/engine/SCons/Tool/MSCommon/common.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" - -__doc__ = """ -Common helper functions for working with the Microsoft tool chain. -""" +__revision__ = "src/engine/SCons/Tool/MSCommon/common.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog" import copy import os @@ -35,17 +35,17 @@ import re import SCons.Util -logfile = os.environ.get('SCONS_MSCOMMON_DEBUG') -if logfile == '-': - def debug(x): - print x -elif logfile: +LOGFILE = os.environ.get('SCONS_MSCOMMON_DEBUG') +if LOGFILE == '-': + def debug(message): + print(message) +elif LOGFILE: try: import logging except ImportError: - debug = lambda x: open(logfile, 'a').write(x + '\n') + debug = lambda message: open(LOGFILE, 'a').write(message + '\n') else: - logging.basicConfig(filename=logfile, level=logging.DEBUG) + logging.basicConfig(filename=LOGFILE, level=logging.DEBUG) debug = logging.debug else: debug = lambda x: None @@ -75,7 +75,7 @@ def is_win64(): # I structured these tests to make it easy to add new ones or # add exceptions in the future, because this is a bit fragile. _is_win64 = False - if os.environ.get('PROCESSOR_ARCHITECTURE','x86') != 'x86': + if os.environ.get('PROCESSOR_ARCHITECTURE', 'x86') != 'x86': _is_win64 = True if os.environ.get('PROCESSOR_ARCHITEW6432'): _is_win64 = True @@ -113,21 +113,30 @@ def normalize_env(env, keys, force=False): Note: the environment is copied.""" normenv = {} if env: - for k in env.keys(): - normenv[k] = copy.deepcopy(env[k]).encode('mbcs') + for k in list(env.keys()): + normenv[k] = copy.deepcopy(env[k]) for k in keys: if k in os.environ and (force or not k in normenv): - normenv[k] = os.environ[k].encode('mbcs') + normenv[k] = os.environ[k] # This shouldn't be necessary, since the default environment should include system32, # but keep this here to be safe, since it's needed to find reg.exe which the MSVC # bat scripts use. - sys32_dir = os.path.join(os.environ.get("SystemRoot", os.environ.get("windir",r"C:\Windows\system32")),"System32") + sys32_dir = os.path.join(os.environ.get("SystemRoot", + os.environ.get("windir", r"C:\Windows\system32")), + "System32") if sys32_dir not in normenv['PATH']: normenv['PATH'] = normenv['PATH'] + os.pathsep + sys32_dir + # Without Wbem in PATH, vcvarsall.bat has a "'wmic' is not recognized" + # error starting with Visual Studio 2017, although the script still + # seems to work anyway. + sys32_wbem_dir = os.path.join(sys32_dir, 'Wbem') + if sys32_wbem_dir not in normenv['PATH']: + normenv['PATH'] = normenv['PATH'] + os.pathsep + sys32_wbem_dir + debug("PATH: %s"%normenv['PATH']) return normenv @@ -144,11 +153,13 @@ def get_output(vcbat, args = None, env = None): # execution to work. This list should really be either directly # controlled by vc.py, or else derived from the common_tools_var # settings in vs.py. - vars = [ + vs_vc_vars = [ 'COMSPEC', -# VS100 and VS110: Still set, but modern MSVC setup scripts will -# discard these if registry has values. However Intel compiler setup -# script still requires these as of 2013/2014. + # VS100 and VS110: Still set, but modern MSVC setup scripts will + # discard these if registry has values. However Intel compiler setup + # script still requires these as of 2013/2014. + 'VS140COMNTOOLS', + 'VS120COMNTOOLS', 'VS110COMNTOOLS', 'VS100COMNTOOLS', 'VS90COMNTOOLS', @@ -157,22 +168,22 @@ def get_output(vcbat, args = None, env = None): 'VS70COMNTOOLS', 'VS60COMNTOOLS', ] - env['ENV'] = normalize_env(env['ENV'], vars, force=False) + env['ENV'] = normalize_env(env['ENV'], vs_vc_vars, force=False) if args: debug("Calling '%s %s'" % (vcbat, args)) popen = SCons.Action._subproc(env, - '"%s" %s & set' % (vcbat, args), - stdin = 'devnull', - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) + '"%s" %s & set' % (vcbat, args), + stdin='devnull', + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) else: debug("Calling '%s'" % vcbat) popen = SCons.Action._subproc(env, - '"%s" & set' % vcbat, - stdin = 'devnull', - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) + '"%s" & set' % vcbat, + stdin='devnull', + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) # Use the .stdout and .stderr attributes directly because the # .communicate() method uses the threading module on Windows @@ -195,10 +206,14 @@ def get_output(vcbat, args = None, env = None): output = stdout.decode("mbcs") return output -def parse_output(output, keep = ("INCLUDE", "LIB", "LIBPATH", "PATH")): +def parse_output(output, keep=("INCLUDE", "LIB", "LIBPATH", "PATH")): + """ + Parse output from running visual c++/studios vcvarsall.bat and running set + To capture the values listed in keep + """ + # dkeep is a dict associating key: path_list, where key is one item from # keep, and pat_list the associated list of paths - dkeep = dict([(i, []) for i in keep]) # rdk will keep the regex to match the .bat file output line starts @@ -207,22 +222,21 @@ def parse_output(output, keep = ("INCLUDE", "LIB", "LIBPATH", "PATH")): rdk[i] = re.compile('%s=(.*)' % i, re.I) def add_env(rmatch, key, dkeep=dkeep): - plist = rmatch.group(1).split(os.pathsep) - for p in plist: + path_list = rmatch.group(1).split(os.pathsep) + for path in path_list: # Do not add empty paths (when a var ends with ;) - if p: - p = p.encode('mbcs') + if path: # XXX: For some reason, VC98 .bat file adds "" around the PATH # values, and it screws up the environment later, so we strip # it. - p = p.strip('"') - dkeep[key].append(p) + path = path.strip('"') + dkeep[key].append(str(path)) for line in output.splitlines(): - for k,v in rdk.items(): - m = v.match(line) - if m: - add_env(m, k) + for k, value in rdk.items(): + match = value.match(line) + if match: + add_env(match, k) return dkeep diff --git a/src/engine/SCons/Tool/MSCommon/netframework.py b/src/engine/SCons/Tool/MSCommon/netframework.py index 8d39cf6..b769c44 100644 --- a/src/engine/SCons/Tool/MSCommon/netframework.py +++ b/src/engine/SCons/Tool/MSCommon/netframework.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2001 - 2016 The SCons Foundation +# Copyright (c) 2001 - 2017 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -20,7 +20,7 @@ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -__revision__ = "src/engine/SCons/Tool/MSCommon/netframework.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" +__revision__ = "src/engine/SCons/Tool/MSCommon/netframework.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog" __doc__ = """ """ @@ -29,7 +29,7 @@ import os import re import SCons.Util -from common import read_reg, debug +from .common import read_reg, debug # Original value recorded by dcournapeau _FRAMEWORKDIR_HKEY_ROOT = r'Software\Microsoft\.NETFramework\InstallRoot' @@ -40,13 +40,13 @@ def find_framework_root(): # XXX: find it from environment (FrameworkDir) try: froot = read_reg(_FRAMEWORKDIR_HKEY_ROOT) - debug("Found framework install root in registry: %s" % froot) - except SCons.Util.WinError, e: - debug("Could not read reg key %s" % _FRAMEWORKDIR_HKEY_ROOT) + debug("Found framework install root in registry: {}".format(froot)) + except SCons.Util.WinError as e: + debug("Could not read reg key {}".format(_FRAMEWORKDIR_HKEY_ROOT)) return None if not os.path.exists(froot): - debug("%s not found on fs" % froot) + debug("{} not found on fs".format(froot)) return None return froot diff --git a/src/engine/SCons/Tool/MSCommon/sdk.py b/src/engine/SCons/Tool/MSCommon/sdk.py index 53bb8aa..8bc9830 100644 --- a/src/engine/SCons/Tool/MSCommon/sdk.py +++ b/src/engine/SCons/Tool/MSCommon/sdk.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2001 - 2016 The SCons Foundation +# Copyright (c) 2001 - 2017 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -21,7 +21,7 @@ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -__revision__ = "src/engine/SCons/Tool/MSCommon/sdk.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" +__revision__ = "src/engine/SCons/Tool/MSCommon/sdk.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog" __doc__ = """Module to detect the Platform/Windows SDK @@ -33,7 +33,7 @@ import os import SCons.Errors import SCons.Util -import common +from . import common debug = common.debug @@ -76,23 +76,23 @@ class SDKDefinition(object): return None hkey = self.HKEY_FMT % self.hkey_data - debug('find_sdk_dir(): checking registry:%s'%hkey) + debug('find_sdk_dir(): checking registry:{}'.format(hkey)) try: sdk_dir = common.read_reg(hkey) - except SCons.Util.WinError, e: - debug('find_sdk_dir(): no SDK registry key %s' % repr(hkey)) + except SCons.Util.WinError as e: + debug('find_sdk_dir(): no SDK registry key {}'.format(repr(hkey))) return None - debug('find_sdk_dir(): Trying SDK Dir: %s'%sdk_dir) + debug('find_sdk_dir(): Trying SDK Dir: {}'.format(sdk_dir)) if not os.path.exists(sdk_dir): - debug('find_sdk_dir(): %s not on file system' % sdk_dir) + debug('find_sdk_dir(): {} not on file system'.format(sdk_dir)) return None ftc = os.path.join(sdk_dir, self.sanity_check_file) if not os.path.exists(ftc): - debug("find_sdk_dir(): sanity check %s not found" % ftc) + debug("find_sdk_dir(): sanity check {} not found".format(ftc)) return None return sdk_dir @@ -105,7 +105,7 @@ class SDKDefinition(object): sdk_dir = self.find_sdk_dir() self._sdk_dir = sdk_dir return sdk_dir - + def get_sdk_vc_script(self,host_arch, target_arch): """ Return the script to initialize the VC compiler installed by SDK """ @@ -113,11 +113,11 @@ class SDKDefinition(object): if (host_arch == 'amd64' and target_arch == 'x86'): # No cross tools needed compiling 32 bits on 64 bit machine host_arch=target_arch - + arch_string=target_arch if (host_arch != target_arch): arch_string='%s_%s'%(host_arch,target_arch) - + debug("sdk.py: get_sdk_vc_script():arch_string:%s host_arch:%s target_arch:%s"%(arch_string, host_arch, target_arch)) @@ -164,6 +164,12 @@ SDK70VCSetupScripts = { 'x86' : r'bin\vcvars32.bat', 'x86_ia64' : r'bin\vcvarsx86_ia64.bat', 'ia64' : r'bin\vcvarsia64.bat'} +SDK100VCSetupScripts = {'x86' : r'bin\vcvars32.bat', + 'amd64' : r'bin\vcvars64.bat', + 'x86_amd64': r'bin\x86_amd64\vcvarsx86_amd64.bat', + 'x86_arm' : r'bin\x86_arm\vcvarsx86_arm.bat'} + + # The list of support SDKs which we know how to detect. # # The first SDK found in the list is the one used by default if there @@ -172,6 +178,16 @@ SDK70VCSetupScripts = { 'x86' : r'bin\vcvars32.bat', # # If you update this list, update the documentation in Tool/mssdk.xml. SupportedSDKList = [ + WindowsSDK('10.0', + sanity_check_file=r'bin\SetEnv.Cmd', + include_subdir='include', + lib_subdir={ + 'x86' : ['lib'], + 'x86_64' : [r'lib\x64'], + 'ia64' : [r'lib\ia64'], + }, + vc_setup_scripts = SDK70VCSetupScripts, + ), WindowsSDK('7.1', sanity_check_file=r'bin\SetEnv.Cmd', include_subdir='include', @@ -308,8 +324,7 @@ def set_sdk_by_directory(env, sdk_dir): def get_sdk_by_version(mssdk): if mssdk not in SupportedSDKMap: - msg = "SDK version %s is not supported" % repr(mssdk) - raise SCons.Errors.UserError(msg) + raise SCons.Errors.UserError("SDK version {} is not supported".format(repr(mssdk))) get_installed_sdks() return InstalledSDKMap.get(mssdk) @@ -327,16 +342,16 @@ def mssdk_setup_env(env): if sdk_dir is None: return sdk_dir = env.subst(sdk_dir) - debug('sdk.py:mssdk_setup_env: Using MSSDK_DIR:%s'%sdk_dir) + debug('sdk.py:mssdk_setup_env: Using MSSDK_DIR:{}'.format(sdk_dir)) elif 'MSSDK_VERSION' in env: sdk_version = env['MSSDK_VERSION'] if sdk_version is None: - msg = "SDK version is specified as None" + msg = "SDK version is specified as None" raise SCons.Errors.UserError(msg) sdk_version = env.subst(sdk_version) mssdk = get_sdk_by_version(sdk_version) if mssdk is None: - msg = "SDK version %s is not installed" % sdk_version + msg = "SDK version %s is not installed" % sdk_version raise SCons.Errors.UserError(msg) sdk_dir = mssdk.get_sdk_dir() debug('sdk.py:mssdk_setup_env: Using MSSDK_VERSION:%s'%sdk_dir) @@ -347,7 +362,7 @@ def mssdk_setup_env(env): debug('sdk.py:mssdk_setup_env thinks msvs_version is None') return msvs_version = env.subst(msvs_version) - import vs + from . import vs msvs = vs.get_vs_by_version(msvs_version) debug('sdk.py:mssdk_setup_env:msvs is :%s'%msvs) if not msvs: diff --git a/src/engine/SCons/Tool/MSCommon/vc.py b/src/engine/SCons/Tool/MSCommon/vc.py index ca8a2da..fba86af 100644 --- a/src/engine/SCons/Tool/MSCommon/vc.py +++ b/src/engine/SCons/Tool/MSCommon/vc.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2001 - 2016 The SCons Foundation +# Copyright (c) 2001 - 2017 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -30,24 +30,25 @@ # * test on 64 bits XP + VS 2005 (and VS 6 if possible) # * SDK # * Assembly -__revision__ = "src/engine/SCons/Tool/MSCommon/vc.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" +__revision__ = "src/engine/SCons/Tool/MSCommon/vc.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog" __doc__ = """Module for Visual C/C++ detection and configuration. """ import SCons.compat import SCons.Util +import subprocess import os import platform from string import digits as string_digits import SCons.Warnings -import common +from . import common debug = common.debug -import sdk +from . import sdk get_installed_sdks = sdk.get_installed_sdks @@ -108,7 +109,7 @@ def get_host_target(env): # PROCESSOR_ARCHITECTURE. if not host_platform: host_platform = os.environ.get('PROCESSOR_ARCHITECTURE', '') - + # Retain user requested TARGET_ARCH req_target_platform = env.get('TARGET_ARCH') debug('vc.py:get_host_target() req_target_platform:%s'%req_target_platform) @@ -118,26 +119,28 @@ def get_host_target(env): target_platform = req_target_platform else: target_platform = host_platform - + try: host = _ARCH_TO_CANONICAL[host_platform.lower()] - except KeyError, e: + except KeyError as e: msg = "Unrecognized host architecture %s" raise ValueError(msg % repr(host_platform)) try: target = _ARCH_TO_CANONICAL[target_platform.lower()] - except KeyError, e: - all_archs = str(_ARCH_TO_CANONICAL.keys()) + except KeyError as e: + all_archs = str(list(_ARCH_TO_CANONICAL.keys())) raise ValueError("Unrecognized target architecture %s\n\tValid architectures: %s" % (target_platform, all_archs)) return (host, target,req_target_platform) # If you update this, update SupportedVSList in Tool/MSCommon/vs.py, and the # MSVC_VERSION documentation in Tool/msvc.xml. -_VCVER = ["14.0", "14.0Exp", "12.0", "12.0Exp", "11.0", "11.0Exp", "10.0", "10.0Exp", "9.0", "9.0Exp","8.0", "8.0Exp","7.1", "7.0", "6.0"] +_VCVER = ["14.1", "14.0", "14.0Exp", "12.0", "12.0Exp", "11.0", "11.0Exp", "10.0", "10.0Exp", "9.0", "9.0Exp","8.0", "8.0Exp","7.1", "7.0", "6.0"] _VCVER_TO_PRODUCT_DIR = { + '14.1' : [ + (SCons.Util.HKEY_LOCAL_MACHINE, r'')], # Visual Studio 2017 doesn't set this registry key anymore '14.0' : [ (SCons.Util.HKEY_LOCAL_MACHINE, r'Microsoft\VisualStudio\14.0\Setup\VC\ProductDir')], '14.0Exp' : [ @@ -183,19 +186,19 @@ _VCVER_TO_PRODUCT_DIR = { (SCons.Util.HKEY_LOCAL_MACHINE, r'Microsoft\VisualStudio\6.0\Setup\Microsoft Visual C++\ProductDir'), ] } - + def msvc_version_to_maj_min(msvc_version): - msvc_version_numeric = ''.join([x for x in msvc_version if x in string_digits + '.']) - - t = msvc_version_numeric.split(".") - if not len(t) == 2: - raise ValueError("Unrecognized version %s (%s)" % (msvc_version,msvc_version_numeric)) - try: - maj = int(t[0]) - min = int(t[1]) - return maj, min - except ValueError, e: - raise ValueError("Unrecognized version %s (%s)" % (msvc_version,msvc_version_numeric)) + msvc_version_numeric = ''.join([x for x in msvc_version if x in string_digits + '.']) + + t = msvc_version_numeric.split(".") + if not len(t) == 2: + raise ValueError("Unrecognized version %s (%s)" % (msvc_version,msvc_version_numeric)) + try: + maj = int(t[0]) + min = int(t[1]) + return maj, min + except ValueError as e: + raise ValueError("Unrecognized version %s (%s)" % (msvc_version,msvc_version_numeric)) def is_host_target_supported(host_target, msvc_version): """Return True if the given (host, target) tuple is supported given the @@ -222,6 +225,35 @@ def is_host_target_supported(host_target, msvc_version): return True + +def find_vc_pdir_vswhere(msvc_version): + """ + Find the MSVC product directory using vswhere.exe . + Run it asking for specified version and get MSVS install location + :param msvc_version: + :return: MSVC install dir + """ + vswhere_path = os.path.join( + 'C:\\', + 'Program Files (x86)', + 'Microsoft Visual Studio', + 'Installer', + 'vswhere.exe' + ) + vswhere_cmd = [vswhere_path, '-version', msvc_version, '-property', 'installationPath'] + + if os.path.exists(vswhere_path): + sp = subprocess.Popen(vswhere_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + vsdir, err = sp.communicate() + vsdir = vsdir.decode("mbcs") + vsdir = vsdir.rstrip() + vc_pdir = os.path.join(vsdir, 'VC') + return vc_pdir + else: + # No vswhere on system, no install info available + return None + + def find_vc_pdir(msvc_version): """Try to find the product directory for the given version. @@ -240,26 +272,31 @@ def find_vc_pdir(msvc_version): for hkroot, key in hkeys: try: comps = None - if common.is_win64(): - try: - # ordinally at win64, try Wow6432Node first. - comps = common.read_reg(root + 'Wow6432Node\\' + key, hkroot) - except SCons.Util.WinError, e: - # at Microsoft Visual Studio for Python 2.7, value is not in Wow6432Node - pass - if not comps: - # not Win64, or Microsoft Visual Studio for Python 2.7 - comps = common.read_reg(root + key, hkroot) - except SCons.Util.WinError, e: - debug('find_vc_dir(): no VC registry key %s' % repr(key)) + if not key: + comps = find_vc_pdir_vswhere(msvc_version) + if not comps: + debug('find_vc_dir(): no VC found via vswhere for version {}'.format(repr(key))) + raise SCons.Util.WinError + else: + if common.is_win64(): + try: + # ordinally at win64, try Wow6432Node first. + comps = common.read_reg(root + 'Wow6432Node\\' + key, hkroot) + except SCons.Util.WinError as e: + # at Microsoft Visual Studio for Python 2.7, value is not in Wow6432Node + pass + if not comps: + # not Win64, or Microsoft Visual Studio for Python 2.7 + comps = common.read_reg(root + key, hkroot) + except SCons.Util.WinError as e: + debug('find_vc_dir(): no VC registry key {}'.format(repr(key))) else: - debug('find_vc_dir(): found VC in registry: %s' % comps) + debug('find_vc_dir(): found VC in registry: {}'.format(comps)) if os.path.exists(comps): return comps else: - debug('find_vc_dir(): reg says dir is %s, but it does not exist. (ignoring)'\ - % comps) - raise MissingConfiguration("registry dir %s not found on the filesystem" % comps) + debug('find_vc_dir(): reg says dir is {}, but it does not exist. (ignoring)'.format(comps)) + raise MissingConfiguration("registry dir {} not found on the filesystem".format(comps)) return None def find_batch_file(env,msvc_version,host_arch,target_arch): @@ -270,8 +307,8 @@ def find_batch_file(env,msvc_version,host_arch,target_arch): pdir = find_vc_pdir(msvc_version) if pdir is None: raise NoVersionFound("No version of Visual Studio found") - - debug('vc.py: find_batch_file() pdir:%s'%pdir) + + debug('vc.py: find_batch_file() pdir:{}'.format(pdir)) # filter out e.g. "Exp" from the version name msvc_ver_numeric = ''.join([x for x in msvc_version if x in string_digits + "."]) @@ -282,13 +319,15 @@ def find_batch_file(env,msvc_version,host_arch,target_arch): elif vernum < 7: pdir = os.path.join(pdir, "Bin") batfilename = os.path.join(pdir, "vcvars32.bat") - else: # >= 8 + elif 8 <= vernum <= 14: batfilename = os.path.join(pdir, "vcvarsall.bat") + else: # vernum >= 14.1 VS2017 and above + batfilename = os.path.join(pdir, "Auxiliary", "Build", "vcvarsall.bat") if not os.path.exists(batfilename): debug("Not found: %s" % batfilename) batfilename = None - + installed_sdks=get_installed_sdks() for _sdk in installed_sdks: sdk_bat_file = _sdk.get_sdk_vc_script(host_arch,target_arch) @@ -296,7 +335,7 @@ def find_batch_file(env,msvc_version,host_arch,target_arch): debug("vc.py:find_batch_file() not found:%s"%_sdk) else: sdk_bat_file_path = os.path.join(pdir,sdk_bat_file) - if os.path.exists(sdk_bat_file_path): + if os.path.exists(sdk_bat_file_path): debug('vc.py:find_batch_file() sdk_bat_file_path:%s'%sdk_bat_file_path) return (batfilename,sdk_bat_file_path) return (batfilename,None) @@ -323,7 +362,7 @@ def get_installed_vcs(): installed_versions.append(ver) else: debug('find_vc_pdir return None for ver %s' % ver) - except VisualCException, e: + except VisualCException as e: debug('did not find VC %s: caught exception %s' % (ver, str(e))) return installed_versions @@ -359,7 +398,7 @@ def get_default_version(env): msvc_version = env.get('MSVC_VERSION') msvs_version = env.get('MSVS_VERSION') - + debug('get_default_version(): msvc_version:%s msvs_version:%s'%(msvc_version,msvs_version)) if msvs_version and not msvc_version: @@ -409,7 +448,7 @@ def msvc_find_valid_batch_script(env,version): try_target_archs = [target_platform] debug("msvs_find_valid_batch_script(): req_target_platform %s target_platform:%s"%(req_target_platform,target_platform)) - # VS2012 has a "cross compile" environment to build 64 bit + # VS2012 has a "cross compile" environment to build 64 bit # with x86_amd64 as the argument to the batch setup script if req_target_platform in ('amd64','x86_64'): try_target_archs.append('x86_amd64') @@ -427,7 +466,7 @@ def msvc_find_valid_batch_script(env,version): for tp in try_target_archs: # Set to current arch. env['TARGET_ARCH']=tp - + debug("vc.py:msvc_find_valid_batch_script() trying target_platform:%s"%tp) host_target = (host_platform, tp) if not is_host_target_supported(host_target, version): @@ -436,11 +475,19 @@ def msvc_find_valid_batch_script(env,version): SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, warn_msg) arg = _HOST_TARGET_ARCH_TO_BAT_ARCH[host_target] + # Get just version numbers + maj, min = msvc_version_to_maj_min(version) + # VS2015+ + if maj >= 14: + if env.get('MSVC_UWP_APP') == '1': + # Initialize environment variables with store/universal paths + arg += ' store' + # Try to locate a batch file for this host/target platform combo try: (vc_script,sdk_script) = find_batch_file(env,version,host_platform,tp) debug('vc.py:msvc_find_valid_batch_script() vc_script:%s sdk_script:%s'%(vc_script,sdk_script)) - except VisualCException, e: + except VisualCException as e: msg = str(e) debug('Caught exception while looking for batch file (%s)' % msg) warn_msg = "VC version %s not installed. " + \ @@ -449,13 +496,13 @@ def msvc_find_valid_batch_script(env,version): warn_msg = warn_msg % (version, cached_get_installed_vcs()) SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, warn_msg) continue - + # Try to use the located batch file for this host/target platform combo debug('vc.py:msvc_find_valid_batch_script() use_script 2 %s, args:%s\n' % (repr(vc_script), arg)) if vc_script: try: d = script_env(vc_script, args=arg) - except BatchFileExecutionError, e: + except BatchFileExecutionError as e: debug('vc.py:msvc_find_valid_batch_script() use_script 3: failed running VC script %s: %s: Error:%s'%(repr(vc_script),arg,e)) vc_script=None continue @@ -463,23 +510,23 @@ def msvc_find_valid_batch_script(env,version): debug('vc.py:msvc_find_valid_batch_script() use_script 4: trying sdk script: %s'%(sdk_script)) try: d = script_env(sdk_script) - except BatchFileExecutionError,e: + except BatchFileExecutionError as e: debug('vc.py:msvc_find_valid_batch_script() use_script 5: failed running SDK script %s: Error:%s'%(repr(sdk_script),e)) continue elif not vc_script and not sdk_script: debug('vc.py:msvc_find_valid_batch_script() use_script 6: Neither VC script nor SDK script found') continue - + debug("vc.py:msvc_find_valid_batch_script() Found a working script/target: %s %s"%(repr(sdk_script),arg)) break # We've found a working target_platform, so stop looking - + # If we cannot find a viable installed compiler, reset the TARGET_ARCH # To it's initial value if not d: env['TARGET_ARCH']=req_target_platform - + return d - + def msvc_setup_env(env): debug('msvc_setup_env()') @@ -498,12 +545,12 @@ def msvc_setup_env(env): env['MSVS_VERSION'] = version env['MSVS'] = {} - + use_script = env.get('MSVC_USE_SCRIPT', True) if SCons.Util.is_String(use_script): debug('vc.py:msvc_setup_env() use_script 1 %s\n' % repr(use_script)) d = script_env(use_script) - elif use_script: + elif use_script: d = msvc_find_valid_batch_script(env,version) debug('vc.py:msvc_setup_env() use_script 2 %s\n' % d) if not d: @@ -524,4 +571,3 @@ def msvc_exists(version=None): if version is None: return len(vcs) > 0 return version in vcs - diff --git a/src/engine/SCons/Tool/MSCommon/vs.py b/src/engine/SCons/Tool/MSCommon/vs.py index 1f04cbe..dafdbaf 100644 --- a/src/engine/SCons/Tool/MSCommon/vs.py +++ b/src/engine/SCons/Tool/MSCommon/vs.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2001 - 2016 The SCons Foundation +# Copyright (c) 2001 - 2017 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -21,7 +21,7 @@ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "src/engine/SCons/Tool/MSCommon/vs.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" +__revision__ = "src/engine/SCons/Tool/MSCommon/vs.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog" __doc__ = """Module to detect Visual Studio and/or Visual C/C++ """ @@ -31,7 +31,7 @@ import os import SCons.Errors import SCons.Util -from common import debug, \ +from .common import debug, \ get_output, \ is_win64, \ normalize_env, \ @@ -83,10 +83,10 @@ class VisualStudio(object): key = root + key try: comps = read_reg(key) - except SCons.Util.WinError, e: - debug('find_vs_dir_by_reg(): no VS registry key %s' % repr(key)) + except SCons.Util.WinError as e: + debug('find_vs_dir_by_reg(): no VS registry key {}'.format(repr(key))) else: - debug('find_vs_dir_by_reg(): found VS in registry: %s' % comps) + debug('find_vs_dir_by_reg(): found VS in registry: {}'.format(comps)) return comps return None @@ -105,12 +105,12 @@ class VisualStudio(object): def find_executable(self): vs_dir = self.get_vs_dir() if not vs_dir: - debug('find_executable(): no vs_dir (%s)'%vs_dir) + debug('find_executable(): no vs_dir ({})'.format(vs_dir)) return None executable = os.path.join(vs_dir, self.executable_path) executable = os.path.normpath(executable) if not os.path.isfile(executable): - debug('find_executable(): %s not on file system' % executable) + debug('find_executable(): {} not on file system'.format(executable)) return None return executable @@ -199,17 +199,28 @@ class VisualStudio(object): # Tool/MSCommon/vc.py, and the MSVC_VERSION documentation in Tool/msvc.xml. SupportedVSList = [ + # Visual Studio 2017 + VisualStudio('14.1', + vc_version='14.1', + sdk_version='10.0A', + hkeys=[], + common_tools_var='VS150COMNTOOLS', + executable_path=r'Common7\IDE\devenv.com', + batch_file_path=r'VC\Auxiliary\Build\vsvars32.bat', + supported_arch=['x86', 'amd64', "arm"], + ), + # Visual Studio 2015 VisualStudio('14.0', vc_version='14.0', - sdk_version='10.0A', + sdk_version='10.0', hkeys=[r'Microsoft\VisualStudio\14.0\Setup\VS\ProductDir'], common_tools_var='VS140COMNTOOLS', executable_path=r'Common7\IDE\devenv.com', batch_file_path=r'Common7\Tools\vsvars32.bat', supported_arch=['x86', 'amd64', "arm"], ), - + # Visual C++ 2015 Express Edition (for Desktop) VisualStudio('14.0Exp', vc_version='14.0', diff --git a/src/engine/SCons/Tool/Perforce.py b/src/engine/SCons/Tool/Perforce.py deleted file mode 100644 index 212150a..0000000 --- a/src/engine/SCons/Tool/Perforce.py +++ /dev/null @@ -1,99 +0,0 @@ -"""SCons.Tool.Perforce.py - -Tool-specific initialization for Perforce Source Code Management system. - -There normally shouldn't be any need to import this module directly. -It will usually be imported through the generic SCons.Tool.Tool() -selection method. - -""" - -# Copyright (c) 2001 - 2016 The SCons Foundation -# -# Permission is hereby granted, free of charge, to any person obtaining -# a copy of this software and associated documentation files (the -# "Software"), to deal in the Software without restriction, including -# without limitation the rights to use, copy, modify, merge, publish, -# distribute, sublicense, and/or sell copies of the Software, and to -# permit persons to whom the Software is furnished to do so, subject to -# the following conditions: -# -# The above copyright notice and this permission notice shall be included -# in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY -# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE -# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -__revision__ = "src/engine/SCons/Tool/Perforce.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" - -import os - -import SCons.Action -import SCons.Builder -import SCons.Node.FS -import SCons.Util - - -# Variables that we want to import from the base OS environment. -_import_env = [ 'P4PORT', 'P4CLIENT', 'P4USER', 'USER', 'USERNAME', 'P4PASSWD', - 'P4CHARSET', 'P4LANGUAGE', 'SystemRoot' ] - -PerforceAction = SCons.Action.Action('$P4COM', '$P4COMSTR') - -def generate(env): - """Add a Builder factory function and construction variables for - Perforce to an Environment.""" - - def PerforceFactory(env=env): - """ """ - import SCons.Warnings as W - W.warn(W.DeprecatedSourceCodeWarning, """The Perforce() factory is deprecated and there is no replacement.""") - return SCons.Builder.Builder(action = PerforceAction, env = env) - - env.Perforce = PerforceFactory - - env['P4'] = 'p4' - env['P4FLAGS'] = SCons.Util.CLVar('') - env['P4COM'] = '$P4 $P4FLAGS sync $TARGET' - try: - environ = env['ENV'] - except KeyError: - environ = {} - env['ENV'] = environ - - # Perforce seems to use the PWD environment variable rather than - # calling getcwd() for itself, which is odd. If no PWD variable - # is present, p4 WILL call getcwd, but this seems to cause problems - # with good ol' Windows's tilde-mangling for long file names. - environ['PWD'] = env.Dir('#').get_abspath() - - for var in _import_env: - v = os.environ.get(var) - if v: - environ[var] = v - - if SCons.Util.can_read_reg: - # If we can read the registry, add the path to Perforce to our environment. - try: - k=SCons.Util.RegOpenKeyEx(SCons.Util.hkey_mod.HKEY_LOCAL_MACHINE, - 'Software\\Perforce\\environment') - val, tok = SCons.Util.RegQueryValueEx(k, 'P4INSTROOT') - SCons.Util.AddPathIfNotExists(environ, 'PATH', val) - except SCons.Util.RegError: - # Can't detect where Perforce is, hope the user has it set in the - # PATH. - pass - -def exists(env): - return env.Detect('p4') - -# Local Variables: -# tab-width:4 -# indent-tabs-mode:nil -# End: -# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/src/engine/SCons/Tool/Perforce.xml b/src/engine/SCons/Tool/Perforce.xml deleted file mode 100644 index 2431c72..0000000 --- a/src/engine/SCons/Tool/Perforce.xml +++ /dev/null @@ -1,129 +0,0 @@ - - - - -%scons; - -%builders-mod; - -%functions-mod; - -%tools-mod; - -%variables-mod; -]> - - - - - - -Sets construction variables for interacting with the -Perforce source code management system. - - - -P4 -P4FLAGS -P4COM - - -P4COMSTR - - - - - - -The Perforce executable. - - - - - - - -The command line used to -fetch source files from Perforce. - - - - - - - -The string displayed when -fetching a source file from Perforce. -If this is not set, then &cv-link-P4COM; (the command line) is displayed. - - - - - - - -General options that are passed to Perforce. - - - - - - -() - - - -A factory function that -returns a Builder object -to be used to fetch source files -from the Perforce source code management system. -The returned Builder -is intended to be passed to the -&f-SourceCode; -function. - - - -This function is deprecated. For details, see the entry for the -&f-SourceCode; -function. - - - -Example: - - - -env.SourceCode('.', env.Perforce()) - - - -Perforce uses a number of external -environment variables for its operation. -Consequently, this function adds the -following variables from the user's external environment -to the construction environment's -ENV dictionary: -P4CHARSET, -P4CLIENT, -P4LANGUAGE, -P4PASSWD, -P4PORT, -P4USER, -SystemRoot, -USER, -and -USERNAME. - - - - - diff --git a/src/engine/SCons/Tool/PharLapCommon.py b/src/engine/SCons/Tool/PharLapCommon.py index ccc2004..c45c6d3 100644 --- a/src/engine/SCons/Tool/PharLapCommon.py +++ b/src/engine/SCons/Tool/PharLapCommon.py @@ -7,7 +7,7 @@ Phar Lap ETS tool chain. Right now, this is linkloc and """ # -# Copyright (c) 2001 - 2016 The SCons Foundation +# Copyright (c) 2001 - 2017 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -29,7 +29,7 @@ Phar Lap ETS tool chain. Right now, this is linkloc and # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "src/engine/SCons/Tool/PharLapCommon.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" +__revision__ = "src/engine/SCons/Tool/PharLapCommon.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog" import os import os.path diff --git a/src/engine/SCons/Tool/RCS.py b/src/engine/SCons/Tool/RCS.py deleted file mode 100644 index 7a8b8b1..0000000 --- a/src/engine/SCons/Tool/RCS.py +++ /dev/null @@ -1,63 +0,0 @@ -"""SCons.Tool.RCS.py - -Tool-specific initialization for RCS. - -There normally shouldn't be any need to import this module directly. -It will usually be imported through the generic SCons.Tool.Tool() -selection method. - -""" - -# Copyright (c) 2001 - 2016 The SCons Foundation -# -# Permission is hereby granted, free of charge, to any person obtaining -# a copy of this software and associated documentation files (the -# "Software"), to deal in the Software without restriction, including -# without limitation the rights to use, copy, modify, merge, publish, -# distribute, sublicense, and/or sell copies of the Software, and to -# permit persons to whom the Software is furnished to do so, subject to -# the following conditions: -# -# The above copyright notice and this permission notice shall be included -# in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY -# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE -# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -__revision__ = "src/engine/SCons/Tool/RCS.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" - -import SCons.Action -import SCons.Builder -import SCons.Util - -def generate(env): - """Add a Builder factory function and construction variables for - RCS to an Environment.""" - - def RCSFactory(env=env): - """ """ - import SCons.Warnings as W - W.warn(W.DeprecatedSourceCodeWarning, """The RCS() factory is deprecated and there is no replacement.""") - act = SCons.Action.Action('$RCS_COCOM', '$RCS_COCOMSTR') - return SCons.Builder.Builder(action = act, env = env) - - env.RCS = RCSFactory - - env['RCS'] = 'rcs' - env['RCS_CO'] = 'co' - env['RCS_COFLAGS'] = SCons.Util.CLVar('') - env['RCS_COCOM'] = '$RCS_CO $RCS_COFLAGS $TARGET' - -def exists(env): - return env.Detect('rcs') - -# Local Variables: -# tab-width:4 -# indent-tabs-mode:nil -# End: -# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/src/engine/SCons/Tool/RCS.xml b/src/engine/SCons/Tool/RCS.xml deleted file mode 100644 index 3c034e4..0000000 --- a/src/engine/SCons/Tool/RCS.xml +++ /dev/null @@ -1,142 +0,0 @@ - - - - -%scons; - -%builders-mod; - -%functions-mod; - -%tools-mod; - -%variables-mod; -]> - - - - - - -Sets construction variables for the interaction -with the Revision Control System. - - - -RCS -RCS_CO -RCS_COFLAGS -RCS_COCOM - - -RCS_COCOMSTR - - - - - - -The RCS executable. -Note that this variable is not actually used -for the command to fetch source files from RCS; -see the -&cv-link-RCS_CO; -construction variable, below. - - - - - - - -The RCS "checkout" executable, -used to fetch source files from RCS. - - - - - - - -The command line used to -fetch (checkout) source files from RCS. - - - - - - - -The string displayed when fetching -a source file from RCS. -If this is not set, then &cv-link-RCS_COCOM; -(the command line) is displayed. - - - - - - - -Options that are passed to the &cv-link-RCS_CO; command. - - - - - - -() - - - -A factory function that -returns a Builder object -to be used to fetch source files -from RCS. -The returned Builder -is intended to be passed to the -&f-SourceCode; -function: - - - -This function is deprecated. For details, see the entry for the -&f-SourceCode; -function. - - - -Examples: - - - -env.SourceCode('.', env.RCS()) - - - -Note that -&scons; -will fetch source files -from RCS subdirectories automatically, -so configuring RCS -as demonstrated in the above example -should only be necessary if -you are fetching from -RCS,v -files in the same -directory as the source files, -or if you need to explicitly specify RCS -for a specific subdirectory. - - - - - diff --git a/src/engine/SCons/Tool/SCCS.py b/src/engine/SCons/Tool/SCCS.py deleted file mode 100644 index c4dbbf8..0000000 --- a/src/engine/SCons/Tool/SCCS.py +++ /dev/null @@ -1,63 +0,0 @@ -"""SCons.Tool.SCCS.py - -Tool-specific initialization for SCCS. - -There normally shouldn't be any need to import this module directly. -It will usually be imported through the generic SCons.Tool.Tool() -selection method. - -""" - -# Copyright (c) 2001 - 2016 The SCons Foundation -# -# Permission is hereby granted, free of charge, to any person obtaining -# a copy of this software and associated documentation files (the -# "Software"), to deal in the Software without restriction, including -# without limitation the rights to use, copy, modify, merge, publish, -# distribute, sublicense, and/or sell copies of the Software, and to -# permit persons to whom the Software is furnished to do so, subject to -# the following conditions: -# -# The above copyright notice and this permission notice shall be included -# in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY -# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE -# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -__revision__ = "src/engine/SCons/Tool/SCCS.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" - -import SCons.Action -import SCons.Builder -import SCons.Util - -def generate(env): - """Add a Builder factory function and construction variables for - SCCS to an Environment.""" - - def SCCSFactory(env=env): - """ """ - import SCons.Warnings as W - W.warn(W.DeprecatedSourceCodeWarning, """The SCCS() factory is deprecated and there is no replacement.""") - act = SCons.Action.Action('$SCCSCOM', '$SCCSCOMSTR') - return SCons.Builder.Builder(action = act, env = env) - - env.SCCS = SCCSFactory - - env['SCCS'] = 'sccs' - env['SCCSFLAGS'] = SCons.Util.CLVar('') - env['SCCSGETFLAGS'] = SCons.Util.CLVar('') - env['SCCSCOM'] = '$SCCS $SCCSFLAGS get $SCCSGETFLAGS $TARGET' - -def exists(env): - return env.Detect('sccs') - -# Local Variables: -# tab-width:4 -# indent-tabs-mode:nil -# End: -# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/src/engine/SCons/Tool/SCCS.xml b/src/engine/SCons/Tool/SCCS.xml deleted file mode 100644 index 97c72a9..0000000 --- a/src/engine/SCons/Tool/SCCS.xml +++ /dev/null @@ -1,133 +0,0 @@ - - - - -%scons; - -%builders-mod; - -%functions-mod; - -%tools-mod; - -%variables-mod; -]> - - - - - - -Sets construction variables for interacting with the -Source Code Control System. - - - -SCCS -SCCSFLAGS -SCCSGETFLAGS -SCCSCOM - - -SCCSCOMSTR - - - - - - -The SCCS executable. - - - - - - - -The command line used to -fetch source files from SCCS. - - - - - - - -The string displayed when fetching -a source file from a CVS repository. -If this is not set, then &cv-link-SCCSCOM; -(the command line) is displayed. - - - - - - - -General options that are passed to SCCS. - - - - - - - -Options that are passed specifically to the SCCS "get" subcommand. -This can be set, for example, to - -to check out editable files from SCCS. - - - - - - -() - - - -A factory function that -returns a Builder object -to be used to fetch source files -from SCCS. -The returned Builder -is intended to be passed to the -&f-link-SourceCode; -function. - - - -Example: - - - -env.SourceCode('.', env.SCCS()) - - - -Note that -&scons; -will fetch source files -from SCCS subdirectories automatically, -so configuring SCCS -as demonstrated in the above example -should only be necessary if -you are fetching from -s.SCCS -files in the same -directory as the source files, -or if you need to explicitly specify SCCS -for a specific subdirectory. - - - - - diff --git a/src/engine/SCons/Tool/Subversion.py b/src/engine/SCons/Tool/Subversion.py deleted file mode 100644 index cb34e07..0000000 --- a/src/engine/SCons/Tool/Subversion.py +++ /dev/null @@ -1,70 +0,0 @@ -"""SCons.Tool.Subversion.py - -Tool-specific initialization for Subversion. - -There normally shouldn't be any need to import this module directly. -It will usually be imported through the generic SCons.Tool.Tool() -selection method. - -""" - -# Copyright (c) 2001 - 2016 The SCons Foundation -# -# Permission is hereby granted, free of charge, to any person obtaining -# a copy of this software and associated documentation files (the -# "Software"), to deal in the Software without restriction, including -# without limitation the rights to use, copy, modify, merge, publish, -# distribute, sublicense, and/or sell copies of the Software, and to -# permit persons to whom the Software is furnished to do so, subject to -# the following conditions: -# -# The above copyright notice and this permission notice shall be included -# in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY -# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE -# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -__revision__ = "src/engine/SCons/Tool/Subversion.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" - -import os.path - -import SCons.Action -import SCons.Builder -import SCons.Util - -def generate(env): - """Add a Builder factory function and construction variables for - Subversion to an Environment.""" - - def SubversionFactory(repos, module='', env=env): - """ """ - # fail if repos is not an absolute path name? - import SCons.Warnings as W - W.warn(W.DeprecatedSourceCodeWarning, """The Subversion() factory is deprecated and there is no replacement.""") - if module != '': - module = os.path.join(module, '') - act = SCons.Action.Action('$SVNCOM', '$SVNCOMSTR') - return SCons.Builder.Builder(action = act, - env = env, - SVNREPOSITORY = repos, - SVNMODULE = module) - - env.Subversion = SubversionFactory - - env['SVN'] = 'svn' - env['SVNFLAGS'] = SCons.Util.CLVar('') - env['SVNCOM'] = '$SVN $SVNFLAGS cat $SVNREPOSITORY/$SVNMODULE$TARGET > $TARGET' - -def exists(env): - return env.Detect('svn') - -# Local Variables: -# tab-width:4 -# indent-tabs-mode:nil -# End: -# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/src/engine/SCons/Tool/Subversion.xml b/src/engine/SCons/Tool/Subversion.xml deleted file mode 100644 index 2d8fd26..0000000 --- a/src/engine/SCons/Tool/Subversion.xml +++ /dev/null @@ -1,135 +0,0 @@ - - - - -%scons; - -%builders-mod; - -%functions-mod; - -%tools-mod; - -%variables-mod; -]> - - - - - - - - - - - - - - diff --git a/src/engine/SCons/Tool/ToolTests.py b/src/engine/SCons/Tool/ToolTests.py index 0739063..f5678c1 100644 --- a/src/engine/SCons/Tool/ToolTests.py +++ b/src/engine/SCons/Tool/ToolTests.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2001 - 2016 The SCons Foundation +# Copyright (c) 2001 - 2017 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -21,7 +21,7 @@ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "src/engine/SCons/Tool/ToolTests.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" +__revision__ = "src/engine/SCons/Tool/ToolTests.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog" import sys import unittest diff --git a/src/engine/SCons/Tool/__init__.py b/src/engine/SCons/Tool/__init__.py index 274b563..9265b81 100644 --- a/src/engine/SCons/Tool/__init__.py +++ b/src/engine/SCons/Tool/__init__.py @@ -14,7 +14,7 @@ tool definition. """ # -# Copyright (c) 2001 - 2016 The SCons Foundation +# Copyright (c) 2001 - 2017 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -35,14 +35,16 @@ tool definition. # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -__revision__ = "src/engine/SCons/Tool/__init__.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" +__revision__ = "src/engine/SCons/Tool/__init__.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog" import imp +import importlib import sys import re import os import shutil + import SCons.Builder import SCons.Errors import SCons.Node.FS @@ -52,6 +54,7 @@ import SCons.Scanner.D import SCons.Scanner.LaTeX import SCons.Scanner.Prog import SCons.Scanner.SWIG +import collections DefaultToolpath=[] @@ -94,9 +97,20 @@ for suffix in LaTeXSuffixes: SourceFileScanner.add_scanner(suffix, LaTeXScanner) SourceFileScanner.add_scanner(suffix, PDFLaTeXScanner) + +# Tool aliases are needed for those tools whos module names also +# occur in the python standard library. This causes module shadowing and +# can break using python library functions under python3 +TOOL_ALIASES = { + 'gettext':'gettext_tool', + 'clang++': 'clangxx', +} + class Tool(object): def __init__(self, name, toolpath=[], **kw): - self.name = name + + # Rename if there's a TOOL_ALIAS for this tool + self.name = TOOL_ALIASES.get(name,name) self.toolpath = toolpath + DefaultToolpath # remember these so we can merge them into the call self.init_kw = kw @@ -107,35 +121,124 @@ class Tool(object): if hasattr(module, 'options'): self.options = module.options + def _load_dotted_module_py2(self, short_name, full_name, searchpaths=None): + splitname = short_name.split('.') + index = 0 + srchpths = searchpaths + for item in splitname: + file, path, desc = imp.find_module(item, srchpths) + mod = imp.load_module(full_name, file, path, desc) + srchpths = [path] + return mod, file + def _tool_module(self): - # TODO: Interchange zipimport with normal initialization for better error reporting oldpythonpath = sys.path sys.path = self.toolpath + sys.path + # sys.stderr.write("Tool:%s\nPATH:%s\n"%(self.name,sys.path)) - try: + if sys.version_info[0] < 3 or (sys.version_info[0] == 3 and sys.version_info[1] in (0,1,2,3,4)): + # Py 2 code try: - file, path, desc = imp.find_module(self.name, self.toolpath) try: - return imp.load_module(self.name, file, path, desc) - finally: - if file: - file.close() - except ImportError, e: - if str(e)!="No module named %s"%self.name: - raise SCons.Errors.EnvironmentError(e) - try: - import zipimport - except ImportError: - pass + file = None + try: + mod, file = self._load_dotted_module_py2(self.name, self.name, self.toolpath) + return mod + finally: + if file: + file.close() + except ImportError as e: + splitname = self.name.split('.') + if str(e)!="No module named %s"%splitname[0]: + raise SCons.Errors.EnvironmentError(e) + try: + import zipimport + except ImportError: + pass + else: + for aPath in self.toolpath: + try: + importer = zipimport.zipimporter(aPath) + return importer.load_module(self.name) + except ImportError as e: + pass + finally: + sys.path = oldpythonpath + elif sys.version_info[1] > 4: + # From: http://stackoverflow.com/questions/67631/how-to-import-a-module-given-the-full-path/67692#67692 + # import importlib.util + # spec = importlib.util.spec_from_file_location("module.name", "/path/to/file.py") + # foo = importlib.util.module_from_spec(spec) + # spec.loader.exec_module(foo) + # foo.MyClass() + # Py 3 code + + # import pdb; pdb.set_trace() + import importlib.util + + # sys.stderr.write("toolpath:%s\n" % self.toolpath) + # sys.stderr.write("SCONS.TOOL path:%s\n" % sys.modules['SCons.Tool'].__path__) + debug = False + spec = None + found_name = self.name + add_to_scons_tools_namespace = False + for path in self.toolpath: + sepname = self.name.replace('.', os.path.sep) + file_path = os.path.join(path, "%s.py"%sepname) + file_package = os.path.join(path, sepname) + + if debug: sys.stderr.write("Trying:%s %s\n"%(file_path, file_package)) + + if os.path.isfile(file_path): + spec = importlib.util.spec_from_file_location(self.name, file_path) + if debug: print("file_Path:%s FOUND"%file_path) + break + elif os.path.isdir(file_package): + file_package = os.path.join(file_package, '__init__.py') + spec = importlib.util.spec_from_file_location(self.name, file_package) + if debug: print("PACKAGE:%s Found"%file_package) + break + else: - for aPath in self.toolpath: - try: - importer = zipimport.zipimporter(aPath) - return importer.load_module(self.name) - except ImportError, e: - pass - finally: - sys.path = oldpythonpath + continue + + if spec is None: + if debug: sys.stderr.write("NO SPEC :%s\n"%self.name) + spec = importlib.util.find_spec("."+self.name, package='SCons.Tool') + if spec: + found_name = 'SCons.Tool.'+self.name + add_to_scons_tools_namespace = True + if debug: sys.stderr.write("Spec Found? .%s :%s\n"%(self.name, spec)) + + if spec is None: + error_string = "No module named %s"%self.name + raise SCons.Errors.EnvironmentError(error_string) + + module = importlib.util.module_from_spec(spec) + if module is None: + if debug: print("MODULE IS NONE:%s"%self.name) + error_string = "No module named %s"%self.name + raise SCons.Errors.EnvironmentError(error_string) + + # Don't reload a tool we already loaded. + sys_modules_value = sys.modules.get(found_name,False) + if sys_modules_value and sys_modules_value.__file__ == spec.origin: + return sys.modules[found_name] + else: + # Not sure what to do in the case that there already + # exists sys.modules[self.name] but the source file is + # different.. ? + module = spec.loader.load_module(spec.name) + + sys.modules[found_name] = module + if add_to_scons_tools_namespace: + # If we found it in SCons.Tool, then add it to the module + setattr(SCons.Tool, self.name, module) + + return module + + + sys.path = oldpythonpath full_name = 'SCons.Tool.' + self.name try: @@ -144,13 +247,12 @@ class Tool(object): try: smpath = sys.modules['SCons.Tool'].__path__ try: - file, path, desc = imp.find_module(self.name, smpath) - module = imp.load_module(full_name, file, path, desc) + module, file = self._load_dotted_module_py2(self.name, full_name, smpath) setattr(SCons.Tool, self.name, module) if file: file.close() return module - except ImportError, e: + except ImportError as e: if str(e)!="No module named %s"%self.name: raise SCons.Errors.EnvironmentError(e) try: @@ -159,10 +261,10 @@ class Tool(object): module = importer.load_module(full_name) setattr(SCons.Tool, self.name, module) return module - except ImportError, e: + except ImportError as e: m = "No tool named '%s': %s" % (self.name, e) raise SCons.Errors.EnvironmentError(m) - except ImportError, e: + except ImportError as e: m = "No tool named '%s': %s" % (self.name, e) raise SCons.Errors.EnvironmentError(m) @@ -217,6 +319,7 @@ def createProgBuilder(env): return program + def createStaticLibBuilder(env): """This is a utility function that creates the StaticLibrary Builder in an Environment if it is not there already. @@ -228,7 +331,7 @@ def createStaticLibBuilder(env): static_lib = env['BUILDERS']['StaticLibrary'] except KeyError: action_list = [ SCons.Action.Action("$ARCOM", "$ARCOMSTR") ] - if env.Detect('ranlib'): + if env.get('RANLIB',False) or env.Detect('ranlib'): ranlib_action = SCons.Action.Action("$RANLIBCOM", "$RANLIBCOMSTR") action_list.append(ranlib_action) @@ -254,22 +357,22 @@ def _call_linker_cb(env, callback, args, result = None): Verbose = False if Verbose: - print '_call_linker_cb: args=%r' % args - print '_call_linker_cb: callback=%r' % callback - + print('_call_linker_cb: args=%r' % args) + print('_call_linker_cb: callback=%r' % callback) + try: cbfun = env['LINKCALLBACKS'][callback] except (KeyError, TypeError): if Verbose: - print '_call_linker_cb: env["LINKCALLBACKS"][%r] not found or can not be used' % callback + print('_call_linker_cb: env["LINKCALLBACKS"][%r] not found or can not be used' % callback) pass else: if Verbose: - print '_call_linker_cb: env["LINKCALLBACKS"][%r] found' % callback - print '_call_linker_cb: env["LINKCALLBACKS"][%r]=%r' % (callback, cbfun) - if(callable(cbfun)): + print('_call_linker_cb: env["LINKCALLBACKS"][%r] found' % callback) + print('_call_linker_cb: env["LINKCALLBACKS"][%r]=%r' % (callback, cbfun)) + if(isinstance(cbfun, collections.Callable)): if Verbose: - print '_call_linker_cb: env["LINKCALLBACKS"][%r] is callable' % callback + print('_call_linker_cb: env["LINKCALLBACKS"][%r] is callable' % callback) result = cbfun(env, *args) return result @@ -388,7 +491,7 @@ class _LibInfoGeneratorBase(object): def generate_versioned_lib_info(self, env, args, result = None, **kw): callback = self.get_versioned_lib_info_generator(**kw) - return _call_linker_cb(env, callback, args, result) + return _call_linker_cb(env, callback, args, result) class _LibPrefixGenerator(_LibInfoGeneratorBase): """Library prefix generator, used as target_prefix in SharedLibrary and @@ -407,17 +510,17 @@ class _LibPrefixGenerator(_LibInfoGeneratorBase): prefix = self.get_lib_prefix(env,**kw2) if Verbose: - print "_LibPrefixGenerator: input prefix=%r" % prefix + print("_LibPrefixGenerator: input prefix=%r" % prefix) version = self.get_lib_version(env, **kw2) if Verbose: - print "_LibPrefixGenerator: version=%r" % version + print("_LibPrefixGenerator: version=%r" % version) if version: prefix = self.generate_versioned_lib_info(env, [prefix, version], prefix, **kw2) if Verbose: - print "_LibPrefixGenerator: return prefix=%r" % prefix + print("_LibPrefixGenerator: return prefix=%r" % prefix) return prefix ShLibPrefixGenerator = _LibPrefixGenerator('ShLib') @@ -441,17 +544,17 @@ class _LibSuffixGenerator(_LibInfoGeneratorBase): suffix = self.get_lib_suffix(env, **kw2) if Verbose: - print "_LibSuffixGenerator: input suffix=%r" % suffix + print("_LibSuffixGenerator: input suffix=%r" % suffix) version = self.get_lib_version(env, **kw2) if Verbose: - print "_LibSuffixGenerator: version=%r" % version + print("_LibSuffixGenerator: version=%r" % version) if version: suffix = self.generate_versioned_lib_info(env, [suffix, version], suffix, **kw2) if Verbose: - print "_LibSuffixGenerator: return suffix=%r" % suffix + print("_LibSuffixGenerator: return suffix=%r" % suffix) return suffix ShLibSuffixGenerator = _LibSuffixGenerator('ShLib') @@ -474,15 +577,15 @@ class _LibSymlinkGenerator(_LibInfoGeneratorBase): kw2 = kw if Verbose: - print "_LibSymLinkGenerator: libnode=%r" % libnode.get_path() + print("_LibSymLinkGenerator: libnode=%r" % libnode.get_path()) symlinks = None version = self.get_lib_version(env, **kw2) disable = self.get_lib_noversionsymlinks(env, **kw2) if Verbose: - print '_LibSymlinkGenerator: version=%r' % version - print '_LibSymlinkGenerator: disable=%r' % disable + print('_LibSymlinkGenerator: version=%r' % version) + print('_LibSymlinkGenerator: disable=%r' % disable) if version and not disable: prefix = self.get_lib_prefix(env,**kw2) @@ -490,7 +593,7 @@ class _LibSymlinkGenerator(_LibInfoGeneratorBase): symlinks = self.generate_versioned_lib_info(env, [libnode, version, prefix, suffix], **kw2) if Verbose: - print '_LibSymlinkGenerator: return symlinks=%r' % StringizeLibSymlinks(symlinks) + print('_LibSymlinkGenerator: return symlinks=%r' % StringizeLibSymlinks(symlinks)) return symlinks ShLibSymlinkGenerator = _LibSymlinkGenerator('ShLib') @@ -499,7 +602,7 @@ ImpLibSymlinkGenerator = _LibSymlinkGenerator('ImpLib') class _LibNameGenerator(_LibInfoGeneratorBase): """Generates "unmangled" library name from a library file node. - + Generally, it's thought to revert modifications done by prefix/suffix generators (_LibPrefixGenerator/_LibSuffixGenerator) used by a library builder. For example, on gnulink the suffix generator used by SharedLibrary @@ -509,7 +612,7 @@ class _LibNameGenerator(_LibInfoGeneratorBase): "$SHLIBSUFFIX" in the node's basename. So that, if $SHLIBSUFFIX is ".so", $SHLIBVERSION is "0.1.2" and the node path is "/foo/bar/libfoo.so.0.1.2", the _LibNameGenerator shall return "libfoo.so". Other link tools may - implement it's own way of library name unmangling. + implement it's own way of library name unmangling. """ def __init__(self, libtype): super(_LibNameGenerator, self).__init__(libtype, 'Name') @@ -525,11 +628,11 @@ class _LibNameGenerator(_LibInfoGeneratorBase): kw2 = kw if Verbose: - print "_LibNameGenerator: libnode=%r" % libnode.get_path() + print("_LibNameGenerator: libnode=%r" % libnode.get_path()) version = self.get_lib_version(env, **kw2) if Verbose: - print '_LibNameGenerator: version=%r' % version + print('_LibNameGenerator: version=%r' % version) name = None if version: @@ -541,7 +644,7 @@ class _LibNameGenerator(_LibInfoGeneratorBase): name = os.path.basename(libnode.get_path()) if Verbose: - print '_LibNameGenerator: return name=%r' % name + print('_LibNameGenerator: return name=%r' % name) return name @@ -550,7 +653,7 @@ LdModNameGenerator = _LibNameGenerator('LdMod') ImpLibNameGenerator = _LibNameGenerator('ImpLib') class _LibSonameGenerator(_LibInfoGeneratorBase): - """Library soname generator. Returns library soname (e.g. libfoo.so.0) for + """Library soname generator. Returns library soname (e.g. libfoo.so.0) for a given node (e.g. /foo/bar/libfoo.so.0.1.2)""" def __init__(self, libtype): super(_LibSonameGenerator, self).__init__(libtype, 'Soname') @@ -566,13 +669,13 @@ class _LibSonameGenerator(_LibInfoGeneratorBase): kw2 = kw if Verbose: - print "_LibSonameGenerator: libnode=%r" % libnode.get_path() + print("_LibSonameGenerator: libnode=%r" % libnode.get_path()) soname = _call_env_subst(env, '$SONAME', **kw2) if not soname: version = self.get_lib_version(env,**kw2) if Verbose: - print "_LibSonameGenerator: version=%r" % version + print("_LibSonameGenerator: version=%r" % version) if version: prefix = self.get_lib_prefix(env,**kw2) suffix = self.get_lib_suffix(env,**kw2) @@ -582,10 +685,10 @@ class _LibSonameGenerator(_LibInfoGeneratorBase): # fallback to library name (as returned by appropriate _LibNameGenerator) soname = _LibNameGenerator(self.get_libtype())(env, libnode) if Verbose: - print "_LibSonameGenerator: FALLBACK: soname=%r" % soname + print("_LibSonameGenerator: FALLBACK: soname=%r" % soname) if Verbose: - print "_LibSonameGenerator: return soname=%r" % soname + print("_LibSonameGenerator: return soname=%r" % soname) return soname @@ -613,39 +716,39 @@ def EmitLibSymlinks(env, symlinks, libnode, **kw): clean_targets = kw.get('clean_targets', []) if not SCons.Util.is_List(clean_targets): clean_targets = [ clean_targets ] - + for link, linktgt in symlinks: env.SideEffect(link, linktgt) if(Verbose): - print "EmitLibSymlinks: SideEffect(%r,%r)" % (link.get_path(), linktgt.get_path()) - clean_list = filter(lambda x : x != linktgt, nodes) + print("EmitLibSymlinks: SideEffect(%r,%r)" % (link.get_path(), linktgt.get_path())) + clean_list = [x for x in nodes if x != linktgt] env.Clean(list(set([linktgt] + clean_targets)), clean_list) if(Verbose): - print "EmitLibSymlinks: Clean(%r,%r)" % (linktgt.get_path(), map(lambda x : x.get_path(), clean_list)) + print("EmitLibSymlinks: Clean(%r,%r)" % (linktgt.get_path(), [x.get_path() for x in clean_list])) def CreateLibSymlinks(env, symlinks): """Physically creates symlinks. The symlinks argument must be a list in form [ (link, linktarget), ... ], where link and linktarget are SCons nodes. """ - + Verbose = False for link, linktgt in symlinks: linktgt = link.get_dir().rel_path(linktgt) link = link.get_path() if(Verbose): - print "CreateLibSymlinks: preparing to add symlink %r -> %r" % (link, linktgt) + print("CreateLibSymlinks: preparing to add symlink %r -> %r" % (link, linktgt)) # Delete the (previously created) symlink if exists. Let only symlinks # to be deleted to prevent accidental deletion of source files... if env.fs.islink(link): env.fs.unlink(link) if(Verbose): - print "CreateLibSymlinks: removed old symlink %r" % link + print("CreateLibSymlinks: removed old symlink %r" % link) # If a file or directory exists with the same name as link, an OSError # will be thrown, which should be enough, I think. env.fs.symlink(linktgt, link) if(Verbose): - print "CreateLibSymlinks: add symlink %r -> %r" % (link, linktgt) + print("CreateLibSymlinks: add symlink %r -> %r" % (link, linktgt)) return 0 def LibSymlinksActionFunction(target, source, env): @@ -670,10 +773,11 @@ def LibSymlinksStrFun(target, source, env, *args): else: cmd += ": %s" % linkstr return cmd - + LibSymlinksAction = SCons.Action.Action(LibSymlinksActionFunction, LibSymlinksStrFun) + def createSharedLibBuilder(env): """This is a utility function that creates the SharedLibrary Builder in an Environment if it is not there already. @@ -810,7 +914,7 @@ def CreateJarBuilder(env): jar_com = SCons.Action.Action('$JARCOM', '$JARCOMSTR') java_jar = SCons.Builder.Builder(action = jar_com, suffix = '$JARSUFFIX', - src_suffix = '$JAVACLASSSUFIX', + src_suffix = '$JAVACLASSSUFFIX', src_builder = 'JavaClassFile', source_factory = fs.Entry) env['BUILDERS']['Jar'] = java_jar @@ -890,9 +994,9 @@ class ToolInitializerMethod(object): def get_builder(self, env): """ - Returns the appropriate real Builder for this method name - after having the associated ToolInitializer object apply - the appropriate Tool module. + Returns the appropriate real Builder for this method name + after having the associated ToolInitializer object apply + the appropriate Tool module. """ builder = getattr(env, self.__name__) @@ -949,13 +1053,13 @@ class ToolInitializer(object): so we no longer copy and re-bind them when the construction environment gets cloned. """ - for method in self.methods.values(): + for method in list(self.methods.values()): env.RemoveMethod(method) def apply_tools(self, env): """ - Searches the list of associated Tool modules for one that - exists, and applies that to the construction environment. + Searches the list of associated Tool modules for one that + exists, and applies that to the construction environment. """ for t in self.tools: tool = SCons.Tool.Tool(t) @@ -1005,7 +1109,7 @@ def tool_list(platform, env): "prefer Microsoft tools on Windows" linkers = ['mslink', 'gnulink', 'ilink', 'linkloc', 'ilink32' ] c_compilers = ['msvc', 'mingw', 'gcc', 'intelc', 'icl', 'icc', 'cc', 'bcc32' ] - cxx_compilers = ['msvc', 'intelc', 'icc', 'g++', 'c++', 'bcc32' ] + cxx_compilers = ['msvc', 'intelc', 'icc', 'g++', 'cxx', 'bcc32' ] assemblers = ['masm', 'nasm', 'gas', '386asm' ] fortran_compilers = ['gfortran', 'g77', 'ifl', 'cvf', 'f95', 'f90', 'fortran'] ars = ['mslib', 'ar', 'tlib'] @@ -1014,7 +1118,7 @@ def tool_list(platform, env): "prefer IBM tools on OS/2" linkers = ['ilink', 'gnulink', ]#'mslink'] c_compilers = ['icc', 'gcc',]# 'msvc', 'cc'] - cxx_compilers = ['icc', 'g++',]# 'msvc', 'c++'] + cxx_compilers = ['icc', 'g++',]# 'msvc', 'cxx'] assemblers = ['nasm',]# 'masm', 'gas'] fortran_compilers = ['ifl', 'g77'] ars = ['ar',]# 'mslib'] @@ -1022,7 +1126,7 @@ def tool_list(platform, env): "prefer MIPSPro on IRIX" linkers = ['sgilink', 'gnulink'] c_compilers = ['sgicc', 'gcc', 'cc'] - cxx_compilers = ['sgic++', 'g++', 'c++'] + cxx_compilers = ['sgicxx', 'g++', 'cxx'] assemblers = ['as', 'gas'] fortran_compilers = ['f95', 'f90', 'f77', 'g77', 'fortran'] ars = ['sgiar'] @@ -1030,7 +1134,7 @@ def tool_list(platform, env): "prefer Forte tools on SunOS" linkers = ['sunlink', 'gnulink'] c_compilers = ['suncc', 'gcc', 'cc'] - cxx_compilers = ['sunc++', 'g++', 'c++'] + cxx_compilers = ['suncxx', 'g++', 'cxx'] assemblers = ['as', 'gas'] fortran_compilers = ['sunf95', 'sunf90', 'sunf77', 'f95', 'f90', 'f77', 'gfortran', 'g77', 'fortran'] @@ -1039,7 +1143,7 @@ def tool_list(platform, env): "prefer aCC tools on HP-UX" linkers = ['hplink', 'gnulink'] c_compilers = ['hpcc', 'gcc', 'cc'] - cxx_compilers = ['hpc++', 'g++', 'c++'] + cxx_compilers = ['hpcxx', 'g++', 'cxx'] assemblers = ['as', 'gas'] fortran_compilers = ['f95', 'f90', 'f77', 'g77', 'fortran'] ars = ['ar'] @@ -1047,7 +1151,7 @@ def tool_list(platform, env): "prefer AIX Visual Age tools on AIX" linkers = ['aixlink', 'gnulink'] c_compilers = ['aixcc', 'gcc', 'cc'] - cxx_compilers = ['aixc++', 'g++', 'c++'] + cxx_compilers = ['aixcxx', 'g++', 'cxx'] assemblers = ['as', 'gas'] fortran_compilers = ['f95', 'f90', 'aixf77', 'g77', 'fortran'] ars = ['ar'] @@ -1055,7 +1159,7 @@ def tool_list(platform, env): "prefer GNU tools on Mac OS X, except for some linkers and IBM tools" linkers = ['applelink', 'gnulink'] c_compilers = ['gcc', 'cc'] - cxx_compilers = ['g++', 'c++'] + cxx_compilers = ['g++', 'cxx'] assemblers = ['as'] fortran_compilers = ['gfortran', 'f95', 'f90', 'g77'] ars = ['ar'] @@ -1063,18 +1167,18 @@ def tool_list(platform, env): "prefer GNU tools on Cygwin, except for a platform-specific linker" linkers = ['cyglink', 'mslink', 'ilink'] c_compilers = ['gcc', 'msvc', 'intelc', 'icc', 'cc'] - cxx_compilers = ['g++', 'msvc', 'intelc', 'icc', 'c++'] + cxx_compilers = ['g++', 'msvc', 'intelc', 'icc', 'cxx'] assemblers = ['gas', 'nasm', 'masm'] fortran_compilers = ['gfortran', 'g77', 'ifort', 'ifl', 'f95', 'f90', 'f77'] ars = ['ar', 'mslib'] else: "prefer GNU tools on all other platforms" - linkers = ['gnulink', 'mslink', 'ilink'] - c_compilers = ['gcc', 'msvc', 'intelc', 'icc', 'cc'] - cxx_compilers = ['g++', 'msvc', 'intelc', 'icc', 'c++'] + linkers = ['gnulink', 'ilink'] + c_compilers = ['gcc', 'intelc', 'icc', 'cc'] + cxx_compilers = ['g++', 'intelc', 'icc', 'cxx'] assemblers = ['gas', 'nasm', 'masm'] fortran_compilers = ['gfortran', 'g77', 'ifort', 'ifl', 'f95', 'f90', 'f77'] - ars = ['ar', 'mslib'] + ars = ['ar',] if not str(platform) == 'win32': other_plat_tools += ['m4', 'rpm'] @@ -1102,7 +1206,7 @@ def tool_list(platform, env): fortran_compiler = FindTool(fortran_compilers, env) or fortran_compilers[0] ar = FindTool(ars, env) or ars[0] - d_compilers = ['dmd', 'gdc', 'ldc'] + d_compilers = ['dmd', 'ldc', 'gdc'] d_compiler = FindTool(d_compilers, env) or d_compilers[0] other_tools = FindAllTools(other_plat_tools + [ @@ -1121,9 +1225,6 @@ def tool_list(platform, env): 'tex', 'latex', 'pdflatex', 'pdftex', # Archivers 'tar', 'zip', - # SourceCode factories - 'BitKeeper', 'CVS', 'Perforce', - 'RCS', 'SCCS', # 'Subversion', ], env) tools = ([linker, c_compiler, cxx_compiler, @@ -1137,4 +1238,3 @@ def tool_list(platform, env): # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: - diff --git a/src/engine/SCons/Tool/__init__.xml b/src/engine/SCons/Tool/__init__.xml index d66b04a..32b8ce6 100644 --- a/src/engine/SCons/Tool/__init__.xml +++ b/src/engine/SCons/Tool/__init__.xml @@ -1,6 +1,6 @@ + + +%scons; + +%builders-mod; + +%functions-mod; + +%tools-mod; + +%variables-mod; +]> + + + + + + +Set construction variables for the Clang C compiler. + + + +CC +SHCCFLAGS +CCVERSION + + + + diff --git a/src/engine/SCons/Tool/clangxx.py b/src/engine/SCons/Tool/clangxx.py new file mode 100644 index 0000000..f56c9e5 --- /dev/null +++ b/src/engine/SCons/Tool/clangxx.py @@ -0,0 +1,91 @@ +# -*- coding: utf-8; -*- + +"""SCons.Tool.clang++ + +Tool-specific initialization for clang++. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. + +""" + +# +# Copyright (c) 2001 - 2017 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +# __revision__ = "src/engine/SCons/Tool/clangxx.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog" + +# Based on SCons/Tool/g++.py by Paweł Tomulik 2014 as a separate tool. +# Brought into the SCons mainline by Russel Winder 2017. + +import os.path +import re +import subprocess +import sys + +import SCons.Tool +import SCons.Util +import SCons.Tool.cxx + +compilers = ['clang++'] + +def generate(env): + """Add Builders and construction variables for clang++ to an Environment.""" + static_obj, shared_obj = SCons.Tool.createObjBuilders(env) + + SCons.Tool.cxx.generate(env) + + env['CXX'] = env.Detect(compilers) or 'clang++' + + # platform specific settings + if env['PLATFORM'] == 'aix': + env['SHCXXFLAGS'] = SCons.Util.CLVar('$CXXFLAGS -mminimal-toc') + env['STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME'] = 1 + env['SHOBJSUFFIX'] = '$OBJSUFFIX' + elif env['PLATFORM'] == 'hpux': + env['SHOBJSUFFIX'] = '.pic.o' + elif env['PLATFORM'] == 'sunos': + env['SHOBJSUFFIX'] = '.pic.o' + # determine compiler version + if env['CXX']: + pipe = SCons.Action._subproc(env, [env['CXX'], '--version'], + stdin='devnull', + stderr='devnull', + stdout=subprocess.PIPE) + if pipe.wait() != 0: return + # clang -dumpversion is of no use + line = pipe.stdout.readline() + if sys.version_info[0] > 2: + line = line.decode() + match = re.search(r'clang +version +([0-9]+(?:\.[0-9]+)+)', line) + if match: + env['CXXVERSION'] = match.group(1) + +def exists(env): + return env.Detect(compilers) + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/src/engine/SCons/Tool/clangxx.xml b/src/engine/SCons/Tool/clangxx.xml new file mode 100644 index 0000000..309bb63 --- /dev/null +++ b/src/engine/SCons/Tool/clangxx.xml @@ -0,0 +1,41 @@ + + + + +%scons; + +%builders-mod; + +%functions-mod; + +%tools-mod; + +%variables-mod; +]> + + + + + + +Set construction variables for the Clang C++ compiler. + + + +CXX +SHCXXFLAGS +STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME +SHOBJSUFFIX +CXXVERSION + + + + diff --git a/src/engine/SCons/Tool/cvf.py b/src/engine/SCons/Tool/cvf.py index 37b4a00..a785471 100644 --- a/src/engine/SCons/Tool/cvf.py +++ b/src/engine/SCons/Tool/cvf.py @@ -5,7 +5,7 @@ Tool-specific initialization for the Compaq Visual Fortran compiler. """ # -# Copyright (c) 2001 - 2016 The SCons Foundation +# Copyright (c) 2001 - 2017 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -27,9 +27,9 @@ Tool-specific initialization for the Compaq Visual Fortran compiler. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "src/engine/SCons/Tool/cvf.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" +__revision__ = "src/engine/SCons/Tool/cvf.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog" -import fortran +from . import fortran compilers = ['f90'] diff --git a/src/engine/SCons/Tool/cvf.xml b/src/engine/SCons/Tool/cvf.xml index 1227658..1b2c447 100644 --- a/src/engine/SCons/Tool/cvf.xml +++ b/src/engine/SCons/Tool/cvf.xml @@ -1,6 +1,6 @@ \n') def printSources(self, hierarchy, commonprefix): @@ -950,7 +954,7 @@ class _GenerateV7DSP(_DSPGenerator, _GenerateV7User): self.file.write('\t\n') - cats = sorted([k for k in categories.keys() if self.sources[k]], + cats = sorted([k for k in list(categories.keys()) if self.sources[k]], key=lambda a: a.lower()) for kind in cats: if len(cats) > 1: @@ -1037,13 +1041,13 @@ class _GenerateV7DSP(_DSPGenerator, _GenerateV7User): def Build(self): try: self.file = open(self.dspabs,'w') - except IOError, detail: + except IOError as detail: raise SCons.Errors.InternalError('Unable to open "' + self.dspabs + '" for writing:' + str(detail)) else: self.PrintHeader() self.PrintProject() self.file.close() - + _GenerateV7User.Build(self) V10DSPHeader = """\ @@ -1100,7 +1104,7 @@ class _GenerateV10DSP(_DSPGenerator, _GenerateV10User): self.dspheader = V10DSPHeader self.dspconfiguration = V10DSPProjectConfiguration self.dspglobals = V10DSPGlobals - + _GenerateV10User.__init__(self, dspfile, source, env) def PrintHeader(self): @@ -1131,27 +1135,27 @@ class _GenerateV10DSP(_DSPGenerator, _GenerateV10User): '\t\t%s\n' % (scc_project_name, scc_local_path_legacy)) else: self.dspglobals = self.dspglobals.replace('%(scc_attrs)s', '') - + self.file.write(self.dspheader % locals()) - + self.file.write('\t\n') - + confkeys = sorted(self.configs.keys()) for kind in confkeys: variant = self.configs[kind].variant platform = self.configs[kind].platform self.file.write(self.dspconfiguration % locals()) - + self.file.write('\t\n') - + self.file.write(self.dspglobals % locals()) - + def PrintProject(self): name = self.name confkeys = sorted(self.configs.keys()) - + self.file.write('\t\n') - + toolset = '' if 'MSVC_VERSION' in self.env: version_num, suite = msvs_parse_version(self.env['MSVC_VERSION']) @@ -1164,16 +1168,16 @@ class _GenerateV10DSP(_DSPGenerator, _GenerateV10User): self.file.write('\t\n') self.file.write('\t\n') self.file.write('\t\n') - + for kind in confkeys: variant = self.configs[kind].variant platform = self.configs[kind].platform self.file.write(V10DSPImportGroupCondition % locals()) - + self.file.write('\t\n') self.file.write('\t\n') self.file.write('\t<_ProjectFileVersion>10.0.30319.1\n') - + for kind in confkeys: variant = self.configs[kind].variant platform = self.configs[kind].platform @@ -1181,7 +1185,7 @@ class _GenerateV10DSP(_DSPGenerator, _GenerateV10User): buildtarget = self.configs[kind].buildtarget runfile = self.configs[kind].runfile cmdargs = self.configs[kind].cmdargs - + env_has_buildtarget = 'MSVSBUILDTARGET' in self.env if not env_has_buildtarget: self.env['MSVSBUILDTARGET'] = buildtarget @@ -1206,41 +1210,41 @@ class _GenerateV10DSP(_DSPGenerator, _GenerateV10User): del self.env['MSVSBUILDTARGET'] self.file.write(V10DSPCommandLine % locals()) - + self.file.write('\t\n') - + #filter settings in MSVS 2010 are stored in separate file self.filtersabs = self.dspabs + '.filters' try: self.filters_file = open(self.filtersabs, 'w') - except IOError, detail: + except IOError as detail: raise SCons.Errors.InternalError('Unable to open "' + self.filtersabs + '" for writing:' + str(detail)) - + self.filters_file.write('\n' '\n') - + self.PrintSourceFiles() - + self.filters_file.write('') self.filters_file.close() - + self.file.write('\t\n' '\t\n' '\t\n' '\n') - + if self.nokeep == 0: # now we pickle some data and add it to the file -- MSDEV will ignore it. - pdata = pickle.dumps(self.configs,1) - pdata = base64.encodestring(pdata) + pdata = pickle.dumps(self.configs,PICKLE_PROTOCOL) + pdata = base64.encodestring(pdata).decode() self.file.write('\n') def printFilters(self, hierarchy, name): sorteditems = sorted(hierarchy.items(), key = lambda a: a[0].lower()) - + for key, value in sorteditems: if SCons.Util.is_Dict(value): filter_name = name + '\\' + key @@ -1248,14 +1252,14 @@ class _GenerateV10DSP(_DSPGenerator, _GenerateV10User): '\t\t\t%s\n' '\t\t\n' % (filter_name, _generateGUID(self.dspabs, filter_name))) self.printFilters(value, filter_name) - + def printSources(self, hierarchy, kind, commonprefix, filter_name): keywords = {'Source Files': 'ClCompile', 'Header Files': 'ClInclude', 'Local Headers': 'ClInclude', 'Resource Files': 'None', 'Other Files': 'None'} - + sorteditems = sorted(hierarchy.items(), key = lambda a: a[0].lower()) # First folders, then files @@ -1269,7 +1273,7 @@ class _GenerateV10DSP(_DSPGenerator, _GenerateV10User): if commonprefix: file = os.path.join(commonprefix, value) file = os.path.normpath(file) - + self.file.write('\t\t<%s Include="%s" />\n' % (keywords[kind], file)) self.filters_file.write('\t\t<%s Include="%s">\n' '\t\t\t%s\n' @@ -1281,10 +1285,10 @@ class _GenerateV10DSP(_DSPGenerator, _GenerateV10User): 'Local Headers': 'h;hpp;hxx;hm;inl', 'Resource Files': 'r;rc;ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe', 'Other Files': ''} - - cats = sorted([k for k in categories.keys() if self.sources[k]], + + cats = sorted([k for k in list(categories.keys()) if self.sources[k]], key = lambda a: a.lower()) - + # print vcxproj.filters file first self.filters_file.write('\t\n') for kind in cats: @@ -1292,7 +1296,7 @@ class _GenerateV10DSP(_DSPGenerator, _GenerateV10User): '\t\t\t{7b42d31d-d53c-4868-8b92-ca2bc9fc052f}\n' '\t\t\t%s\n' '\t\t\n' % (kind, categories[kind])) - + # First remove any common prefix sources = self.sources[kind] commonprefix = None @@ -1305,17 +1309,17 @@ class _GenerateV10DSP(_DSPGenerator, _GenerateV10User): # +1 because the filename starts after the separator sources = [s[len(cp)+1:] for s in sources] commonprefix = cp - + hierarchy = makeHierarchy(sources) self.printFilters(hierarchy, kind) - + self.filters_file.write('\t\n') - + # then print files and filters for kind in cats: self.file.write('\t\n') self.filters_file.write('\t\n') - + # First remove any common prefix sources = self.sources[kind] commonprefix = None @@ -1328,13 +1332,13 @@ class _GenerateV10DSP(_DSPGenerator, _GenerateV10User): # +1 because the filename starts after the separator sources = [s[len(cp)+1:] for s in sources] commonprefix = cp - + hierarchy = makeHierarchy(sources) self.printSources(hierarchy, kind, commonprefix, kind) - + self.file.write('\t\n') self.filters_file.write('\t\n') - + # add the SConscript file outside of the groups self.file.write('\t\n' '\t\t\n' @@ -1342,18 +1346,18 @@ class _GenerateV10DSP(_DSPGenerator, _GenerateV10User): '\t\n' % str(self.sconscript)) def Parse(self): - print "_GenerateV10DSP.Parse()" + print("_GenerateV10DSP.Parse()") def Build(self): try: self.file = open(self.dspabs, 'w') - except IOError, detail: + except IOError as detail: raise SCons.Errors.InternalError('Unable to open "' + self.dspabs + '" for writing:' + str(detail)) else: self.PrintHeader() self.PrintProject() self.file.close() - + _GenerateV10User.Build(self) class _DSWGenerator(object): @@ -1428,7 +1432,7 @@ class _GenerateV7DSW(_DSWGenerator): config.platform = 'Win32' self.configs[variant] = config - print "Adding '" + self.name + ' - ' + config.variant + '|' + config.platform + "' to '" + str(dswfile) + "'" + print("Adding '" + self.name + ' - ' + config.variant + '|' + config.platform + "' to '" + str(dswfile) + "'") if 'variant' not in env: raise SCons.Errors.InternalError("You must specify a 'variant' argument (i.e. 'Debug' or " +\ @@ -1440,7 +1444,7 @@ class _GenerateV7DSW(_DSWGenerator): AddConfig(self, variant) self.platforms = [] - for key in self.configs.keys(): + for key in list(self.configs.keys()): platform = self.configs[key].platform if not platform in self.platforms: self.platforms.append(platform) @@ -1461,7 +1465,7 @@ class _GenerateV7DSW(_DSWGenerator): 'SLN_RELATIVE_FOLDER_PATH': dsp_relative_folder_path, 'SLN_RELATIVE_FILE_PATH': dsp_relative_file_path} self.dspfiles_info.append(dspfile_info) - + self.dspfiles_info = [] GenerateProjectFilesInfo(self) @@ -1507,7 +1511,7 @@ class _GenerateV7DSW(_DSWGenerator): self.file.write('# Visual Studio 2008\n') elif self.version_num >= 8.0: self.file.write('# Visual Studio 2005\n') - + for dspinfo in self.dspfiles_info: name = dspinfo['NAME'] base, suffix = SCons.Util.splitext(name) @@ -1605,14 +1609,15 @@ class _GenerateV7DSW(_DSWGenerator): '\tEndGlobalSection\n') self.file.write('EndGlobal\n') if self.nokeep == 0: - pdata = pickle.dumps(self.configs,1) - pdata = base64.encodestring(pdata) - self.file.write(pdata + '\n') + pdata = pickle.dumps(self.configs,PICKLE_PROTOCOL) + pdata = base64.encodestring(pdata).decode() + self.file.write(pdata) + self.file.write('\n') def Build(self): try: self.file = open(self.dswfile,'w') - except IOError, detail: + except IOError as detail: raise SCons.Errors.InternalError('Unable to open "' + self.dswfile + '" for writing:' + str(detail)) else: self.PrintSolution() @@ -1661,7 +1666,7 @@ class _GenerateV6DSW(_DSWGenerator): def Build(self): try: self.file = open(self.dswfile,'w') - except IOError, detail: + except IOError as detail: raise SCons.Errors.InternalError('Unable to open "' + self.dswfile + '" for writing:' + str(detail)) else: self.PrintWorkspace() @@ -1718,8 +1723,8 @@ def GenerateProject(target, source, env): if not dspfile is builddspfile: try: bdsp = open(str(builddspfile), "w+") - except IOError, detail: - print 'Unable to open "' + str(dspfile) + '" for writing:',detail,'\n' + except IOError as detail: + print('Unable to open "' + str(dspfile) + '" for writing:',detail,'\n') raise bdsp.write("This is just a placeholder file.\nThe real project file is here:\n%s\n" % dspfile.get_abspath()) @@ -1734,8 +1739,8 @@ def GenerateProject(target, source, env): try: bdsw = open(str(builddswfile), "w+") - except IOError, detail: - print 'Unable to open "' + str(dspfile) + '" for writing:',detail,'\n' + except IOError as detail: + print('Unable to open "' + str(dspfile) + '" for writing:',detail,'\n') raise bdsw.write("This is just a placeholder file.\nThe real workspace file is here:\n%s\n" % dswfile.get_abspath()) @@ -1843,7 +1848,10 @@ def projectEmitter(target, source, env): targetlist = targetlist + t # Beginning with Visual Studio 2010 for each project file (.vcxproj) we have additional file (.vcxproj.filters) - if float(env['MSVS_VERSION']) >= 10.0: + version_num = 6.0 + if 'MSVS_VERSION' in env: + version_num, suite = msvs_parse_version(env['MSVS_VERSION']) + if version_num >= 10.0: targetlist.append(targetlist[0] + '.filters') return (targetlist, sourcelist) @@ -1969,7 +1977,7 @@ def generate(env): else: env['MSVS']['PROJECTSUFFIX'] = '.vcxproj' env['MSVS']['SOLUTIONSUFFIX'] = '.sln' - + if (version_num >= 10.0): env['MSVSENCODING'] = 'utf-8' else: diff --git a/src/engine/SCons/Tool/msvs.xml b/src/engine/SCons/Tool/msvs.xml index 4ca5fb1..0408509 100644 --- a/src/engine/SCons/Tool/msvs.xml +++ b/src/engine/SCons/Tool/msvs.xml @@ -1,6 +1,6 @@