From bc71b14aa8ebf22f4a49b406508485f7a963eb2f Mon Sep 17 00:00:00 2001 From: djh <1810493+djh82@users.noreply.github.com> Date: Mon, 5 Jul 2021 18:25:42 +0100 Subject: feat: adds minor java improvements --- CHANGES.txt | 2 + SCons/Scanner/Java.py | 101 ++++++++++++++++++++++++++++ SCons/Scanner/JavaTests.py | 160 +++++++++++++++++++++++++++++++++++++++++++++ SCons/Tool/__init__.py | 8 ++- SCons/Tool/javac.py | 1 + SCons/Tool/javac.xml | 9 --- SCons/Tool/javacTests.py | 5 ++ 7 files changed, 275 insertions(+), 11 deletions(-) create mode 100644 SCons/Scanner/Java.py create mode 100644 SCons/Scanner/JavaTests.py diff --git a/CHANGES.txt b/CHANGES.txt index c73f345..343d547 100755 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -37,6 +37,8 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER - Fix Issue #3906 - `IMPLICIT_COMMAND_DEPENDENCIES` was not properly disabled when set to any string value (For example ['none','false','no','off']) Also previously 'All' wouldn't have the desired affect. + - Add JavaScanner to include JAVACLASSPATH as a dependency when using the Java tool. + - Fix incorrect Java classpath generation when a NodeList is used as part of any JAVA*PATH variables. From Ivan Kravets: - Provide a custom argument escape function for `TempFileMunge` using a new diff --git a/SCons/Scanner/Java.py b/SCons/Scanner/Java.py new file mode 100644 index 0000000..4c08b10 --- /dev/null +++ b/SCons/Scanner/Java.py @@ -0,0 +1,101 @@ +# +# __COPYRIGHT__ +# +# 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" + +import os + +import SCons.Node +import SCons.Node.FS +import SCons.Scanner +import SCons.Util + + +def _subst_libs(env, libs): + """ + Substitute environment variables and split into list. + """ + if SCons.Util.is_String(libs): + libs = env.subst(libs) + if SCons.Util.is_String(libs): + libs = libs.split() + elif SCons.Util.is_Sequence(libs): + _libs = [] + for lib in libs: + _libs += _subst_libs(env, lib) + libs = _libs + else: + # libs is an object (Node, for example) + libs = [libs] + return libs + + +def _collect_classes(list, dirname, files): + for fname in files: + if os.path.splitext(fname)[1] == ".class": + list.append(os.path.join(str(dirname), fname)) + + +def scan(node, env, libpath=()): + """Scan for files on the JAVACLASSPATH. + + The classpath can contain: + - Explicit paths to JAR/Zip files + - Wildcards (*) + - Directories which contain classes in an unnamed package + - Parent directories of the root package for classes in a named package + + Class path entries that are neither directories nor archives (.zip or JAR files) nor the asterisk (*) wildcard character are ignored. + """ + classpath = env.get('JAVACLASSPATH', []) + classpath = _subst_libs(env, classpath) + + result = [] + for path in classpath: + if SCons.Util.is_String(path) and "*" in path: + libs = env.Glob(path) + else: + libs = [path] + + for lib in libs: + if os.path.isdir(str(lib)): + # grab the in-memory nodes + env.Dir(lib).walk(_collect_classes, result) + # now the on-disk ones + for root, dirs, files in os.walk(str(lib)): + _collect_classes(result, root, files) + else: + result.append(lib) + + return list(filter(lambda x: os.path.splitext(str(x))[1] in [".class", ".zip", ".jar"], result)) + + +def JavaScanner(): + return SCons.Scanner.Base(scan, 'JavaScanner', + skeys=['.java']) + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/SCons/Scanner/JavaTests.py b/SCons/Scanner/JavaTests.py new file mode 100644 index 0000000..9fb39ce --- /dev/null +++ b/SCons/Scanner/JavaTests.py @@ -0,0 +1,160 @@ +# MIT License +# +# Copyright 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. + +import unittest +import collections +import os + +import TestCmd + +import SCons.Scanner.Java +import SCons.Node.FS +import SCons.Warnings + + +test = TestCmd.TestCmd(workdir = '') +test.subdir('com') + +files = [ + 'bootclasspath.jar', + 'classpath.jar', + 'Test.class', + 'com/Test.class' +] + +for fname in files: + test.write(fname, "\n") + + +class DummyEnvironment(collections.UserDict): + def __init__(self,**kw): + collections.UserDict.__init__(self) + self.data.update(kw) + self.fs = SCons.Node.FS.FS(test.workpath('')) + self['ENV'] = {} + + def Dictionary(self, *args): + return self.data + + def subst(self, strSubst, target=None, source=None, conv=None): + if strSubst[0] == '$': + return self.data[strSubst[1:]] + return strSubst + + def subst_path(self, path, target=None, source=None, conv=None): + if not isinstance(path, list): + path = [path] + return list(map(self.subst, path)) + + def has_key(self, key): + return key in self.Dictionary() + + def get_calculator(self): + return None + + def get_factory(self, factory): + return factory or self.fs.File + + def Dir(self, filename): + return self.fs.Dir(filename) + + def File(self, filename): + return self.fs.File(filename) + + def Glob(self, path): + return self.fs.Glob(path) + + +class DummyNode: + def __init__(self, name): + self.name = name + + def rexists(self): + return 1 + + def __str__(self): + return self.name + + +global my_normpath +my_normpath = os.path.normpath + +if os.path.normcase('foo') == os.path.normcase('FOO'): + my_normpath = os.path.normcase + +def deps_match(self, deps, headers): + scanned = sorted(map(my_normpath, list(map(str, deps)))) + expect = sorted(map(my_normpath, headers)) + self.assertTrue(scanned == expect, "expect %s != scanned %s" % (expect, scanned)) + + +class JavaScannerEmptyClasspath(unittest.TestCase): + def runTest(self): + path = [] + env = DummyEnvironment(JAVASUFFIXES=['.java'], + JAVACLASSPATH=path) + s = SCons.Scanner.Java.JavaScanner() + deps = s(DummyNode('dummy'), env) + expected = [] + deps_match(self, deps, expected) + + +class JavaScannerClasspath(unittest.TestCase): + def runTest(self): + env = DummyEnvironment(JAVASUFFIXES=['.java'], + JAVACLASSPATH=[test.workpath('classpath.jar')]) + s = SCons.Scanner.Java.JavaScanner() + deps = s(DummyNode('dummy'), env) + expected = ['classpath.jar'] + deps_match(self, deps, expected) + + +class JavaScannerWildcardClasspath(unittest.TestCase): + def runTest(self): + env = DummyEnvironment(JAVASUFFIXES=['.java'], + JAVACLASSPATH=[test.workpath('*')]) + s = SCons.Scanner.Java.JavaScanner() + deps = s(DummyNode('dummy'), env) + expected = ['bootclasspath.jar', 'classpath.jar', 'Test.class'] + deps_match(self, deps, expected) + + +class JavaScannerDirClasspath(unittest.TestCase): + def runTest(self): + env = DummyEnvironment(JAVASUFFIXES=['.java'], + JAVACLASSPATH=[test.workpath()]) + s = SCons.Scanner.Java.JavaScanner() + deps = s(DummyNode('dummy'), env) + expected = ['Test.class', 'com/Test.class'] + deps_match(self, deps, expected) + + + +if __name__ == "__main__": + unittest.main() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/SCons/Tool/__init__.py b/SCons/Tool/__init__.py index e78e953..df2e935 100644 --- a/SCons/Tool/__init__.py +++ b/SCons/Tool/__init__.py @@ -48,6 +48,7 @@ import SCons.Node.FS import SCons.Scanner import SCons.Scanner.C import SCons.Scanner.D +import SCons.Scanner.Java import SCons.Scanner.LaTeX import SCons.Scanner.Prog import SCons.Scanner.SWIG @@ -57,6 +58,7 @@ DefaultToolpath = [] CScanner = SCons.Scanner.C.CScanner() DScanner = SCons.Scanner.D.DScanner() +JavaScanner = SCons.Scanner.Java.JavaScanner() LaTeXScanner = SCons.Scanner.LaTeX.LaTeXScanner() PDFLaTeXScanner = SCons.Scanner.LaTeX.PDFLaTeXScanner() ProgramScanner = SCons.Scanner.Prog.ProgramScanner() @@ -521,7 +523,8 @@ def CreateJavaClassFileBuilder(env): src_suffix='$JAVASUFFIX', src_builder=['JavaFile'], target_factory=fs.Entry, - source_factory=fs.File) + source_factory=fs.File, + target_scanner=JavaScanner) env['BUILDERS']['JavaClassFile'] = java_class_file return java_class_file @@ -535,7 +538,8 @@ def CreateJavaClassDirBuilder(env): java_class_dir = SCons.Builder.Builder(action=javac_com, emitter={}, target_factory=fs.Dir, - source_factory=fs.Dir) + source_factory=fs.Dir, + target_scanner=JavaScanner) env['BUILDERS']['JavaClassDir'] = java_class_dir return java_class_dir diff --git a/SCons/Tool/javac.py b/SCons/Tool/javac.py index fd007eb..98009f9 100644 --- a/SCons/Tool/javac.py +++ b/SCons/Tool/javac.py @@ -157,6 +157,7 @@ class pathopt: default = [default] path = path + default if path: + path = SCons.Util.flatten(path) return [self.opt, os.pathsep.join(map(str, path))] else: return [] diff --git a/SCons/Tool/javac.xml b/SCons/Tool/javac.xml index 3ec7fea..eeafb15 100644 --- a/SCons/Tool/javac.xml +++ b/SCons/Tool/javac.xml @@ -215,15 +215,6 @@ env = Environment(JAVACCOMSTR="Compiling class files $TARGETS from $SOURCES") ; on Windows). - - - Note that this currently just adds the specified - directory via the option. - &SCons; does not currently search the - &cv-JAVACLASSPATH; directories for dependency - .class - files. - diff --git a/SCons/Tool/javacTests.py b/SCons/Tool/javacTests.py index ff0b8d4..08633d5 100644 --- a/SCons/Tool/javacTests.py +++ b/SCons/Tool/javacTests.py @@ -97,6 +97,11 @@ class pathoptTestCase(unittest.TestCase): ['-foopath', '/foo'], '/foo', '') + + def test_list_within_list(self): + self.assert_pathopt(['-foopath', os.pathsep.join(['/foo','/bar'])], + ['/foo', ['/bar']]) + if __name__ == "__main__": unittest.main() -- cgit v0.12 From 570a59f9028e6bcf95ceac4dee92c03073191550 Mon Sep 17 00:00:00 2001 From: William Deegan Date: Sat, 14 May 2022 18:15:05 -0700 Subject: Fix file header --- SCons/Scanner/Java.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/SCons/Scanner/Java.py b/SCons/Scanner/Java.py index 4c08b10..ab1f4e6 100644 --- a/SCons/Scanner/Java.py +++ b/SCons/Scanner/Java.py @@ -1,5 +1,6 @@ +# MIT License # -# __COPYRIGHT__ +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -19,9 +20,6 @@ # 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import os -- cgit v0.12 From e5043ad11bdcaa87ab8e3ed391d00ef002192641 Mon Sep 17 00:00:00 2001 From: William Deegan Date: Sun, 22 May 2022 14:35:06 -0700 Subject: [ci skip] Updated CHANGES/RELEASE.txt to move the blurbs for these changes to the current version --- CHANGES.txt | 8 ++++---- RELEASE.txt | 2 ++ 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index fa441f4..28ec5f3 100755 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -53,7 +53,9 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER arguments would yield an exception. This issue was found via qt4 and qt5 tools in scons-contrib https://github.com/SCons/scons-contrib/issues/45 - + From David H: + - Add JavaScanner to include JAVACLASSPATH as a dependency when using the Java tool. + - Fix incorrect Java classpath generation when a NodeList is used as part of any JAVA*PATH variables. From Daniel Moody: - Add cache-debug messages for push failures. @@ -270,9 +272,7 @@ RELEASE 4.2.0 - Sat, 31 Jul 2021 18:12:46 -0700 - Fix Issue #3906 - `IMPLICIT_COMMAND_DEPENDENCIES` was not properly disabled when set to any string value (For example ['none','false','no','off']) Also previously 'All' wouldn't have the desired affect. - - Add JavaScanner to include JAVACLASSPATH as a dependency when using the Java tool. - - Fix incorrect Java classpath generation when a NodeList is used as part of any JAVA*PATH variables. - + From Ivan Kravets: - Provide a custom argument escape function for `TempFileMunge` using a new `TEMPFILEARGESCFUNC` variable. Useful if you need to apply extra operations on diff --git a/RELEASE.txt b/RELEASE.txt index a6ffbee..3cab3eb 100755 --- a/RELEASE.txt +++ b/RELEASE.txt @@ -52,6 +52,7 @@ CHANGED/ENHANCED EXISTING FUNCTIONALITY output format written to stdout to include more information about the source for each message of MSVC initialization debugging output. A single space was added before the message for all debugging output records written to stdout and to files. +- Add JavaScanner to include JAVACLASSPATH as a dependency when using the Java tool. FIXES ----- @@ -94,6 +95,7 @@ FIXES that link has been modified (issue #3880) - Fix typo in ninja scons daemon startup which causes ConnectionRefusedError to not retry to connect to the server during start up. +- Fix incorrect Java classpath generation when a NodeList is used as part of any JAVA*PATH variables. IMPROVEMENTS ------------ -- cgit v0.12