__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+import os
import os.path
+import re
import string
import SCons.Builder
-
-# Okay, I don't really know what configurability would be good for
-# parsing Java files for package and/or class names, but it was easy, so
-# here it is.
-#
-# Set java_parsing to the following values to enable three different
-# flavors of parsing:
-#
-# 0 The file isn't actually parsed, so this will be quickest. The
-# package + class name is assumed to be the file path name, and we
-# just split the path name. This breaks if a package name will
-# ever be different from the path to the .java file.
-#
-# 1 The file is read to find the package name, after which we stop.
-# This should be pretty darn quick, and allows flexibility in
-# package names, but assumes that the public class name in the
-# file matches the file name. This seems to be a good assumption
-# because, for example, if you try to declare a public class
-# with a different name from the file, javac tells you:
-#
-# class Foo is public, should be declared in a file named Foo.java
-#
-# 2 Full flexibility of class names. We parse for the package name
-# (like level #1) but the output .class file name is assumed to
-# match the declared public class name--and, as a bonus, this will
-# actually support multiple public classes in a single file. My
-# guess is that's illegal Java, though... Or is it an option
-# supported by some compilers?
-#
-java_parsing = 1
-
-if java_parsing == 0:
- def parse_java(file, suffix):
- """ "Parse" a .java file.
-
- This actually just splits the file name, so the assumption here
- is that the file name matches the public class name, and that
- the path to the file is the same as the package name.
- """
- return os.path.split(file)
-elif java_parsing == 1:
- def parse_java(file, suffix):
- """Parse a .java file for a package name.
-
- This, of course, is not full parsing of Java files, but
- simple-minded searching for the usual begins-in-column-1
- "package" string most Java programs use to define their package.
- """
- pkg_dir = None
- classes = []
- f = open(file, "rb")
- while 1:
- line = f.readline()
- if not line:
- break
- if line[:7] == 'package':
- pkg = string.split(line)[1]
- if pkg[-1] == ';':
- pkg = pkg[:-1]
- pkg_dir = apply(os.path.join, string.split(pkg, '.'))
- classes = [ os.path.split(file[:-len(suffix)])[1] ]
- break
- f.close()
- return pkg_dir, classes
-
-elif java_parsing == 2:
- import re
- pub_re = re.compile('^\s*public(\s+abstract)?\s+class\s+(\S+)')
- def parse_java(file, suffix):
- """Parse a .java file for package name and classes.
-
- This, of course, is not full parsing of Java files, but
- simple-minded searching for the usual strings most Java programs
- seem to use for packages and public class names.
- """
- pkg_dir = None
- classes = []
- f = open(file, "rb")
- while 1:
- line = f.readline()
- if not line:
- break
- if line[:7] == 'package':
- pkg = string.split(line)[1]
- if pkg[-1] == ';':
- pkg = pkg[:-1]
- pkg_dir = apply(os.path.join, string.split(pkg, '.'))
- elif line[:6] == 'public':
- c = pub_re.findall(line)
- try:
- classes.append(c[0][1])
- except IndexError:
- pass
- f.close()
- return pkg_dir, classes
+from SCons.Node.FS import _my_normcase
+from SCons.Tool.JavaCommon import parse_java_file
+
+def classname(path):
+ """Turn a string (path name) into a Java class name."""
+ return string.replace(os.path.normpath(path), os.sep, '.')
+
+def emit_java_classes(target, source, env):
+ """Create and return lists of source java files
+ and their corresponding target class files.
+ """
+ java_suffix = env.get('JAVASUFFIX', '.java')
+ class_suffix = env.get('JAVACLASSSUFFIX', '.class')
+
+ slist = []
+ js = _my_normcase(java_suffix)
+ def visit(arg, dirname, names, js=js, dirnode=source[0].rdir()):
+ java_files = filter(lambda n, js=js:
+ _my_normcase(n[-len(js):]) == js,
+ names)
+ mydir = dirnode.Dir(dirname)
+ java_paths = map(lambda f, d=mydir: d.File(f), java_files)
+ arg.extend(java_paths)
+ os.path.walk(source[0].rdir().get_abspath(), visit, slist)
+
+ tlist = []
+ for file in slist:
+ pkg_dir, classes = parse_java_file(file.get_abspath())
+ if pkg_dir:
+ for c in classes:
+ t = target[0].Dir(pkg_dir).File(c+class_suffix)
+ t.attributes.java_classdir = target[0]
+ t.attributes.java_classname = classname(pkg_dir + os.sep + c)
+ tlist.append(t)
+ elif classes:
+ for c in classes:
+ t = target[0].File(c+class_suffix)
+ t.attributes.java_classdir = target[0]
+ t.attributes.java_classname = classname(c)
+ tlist.append(t)
+ else:
+ # This is an odd end case: no package and no classes.
+ # Just do our best based on the source file name.
+ base = str(file)[:-len(java_suffix)]
+ t = target[0].File(base + class_suffix)
+ t.attributes.java_classdir = target[0]
+ t.attributes.java_classname = classname(base)
+ tlist.append(t)
+
+ return tlist, slist
+
+JavaBuilder = SCons.Builder.Builder(action = '$JAVACCOM',
+ emitter = emit_java_classes,
+ target_factory = SCons.Node.FS.default_fs.Dir,
+ source_factory = SCons.Node.FS.default_fs.Dir)
def generate(env):
"""Add Builders and construction variables for javac to an Environment."""
- def emit_java_files(target, source, env):
- """Create and return lists of source java files
- and their corresponding target class files.
- """
- env['_JAVACLASSDIR'] = target[0]
- env['_JAVASRCDIR'] = source[0]
- java_suffix = env.get('JAVASUFFIX', '.java')
- class_suffix = env.get('JAVACLASSSUFFIX', '.class')
- slist = []
- def visit(arg, dirname, names, js=java_suffix):
- java_files = filter(lambda n, js=js: n[-len(js):] == js, names)
- java_paths = map(lambda f, d=dirname:
- os.path.join(d, f),
- java_files)
- arg.extend(java_paths)
- os.path.walk(source[0], visit, slist)
- tlist = []
- for file in slist:
- pkg_dir, classes = parse_java(file, java_suffix)
- if pkg_dir:
- for c in classes:
- tlist.append(os.path.join(target[0],
- pkg_dir,
- c + class_suffix))
- else:
- tlist.append(os.path.join(target[0],
- file[:-5] + class_suffix))
- return tlist, slist
-
- JavaBuilder = SCons.Builder.Builder(action = '$JAVACCOM',
- emitter = emit_java_files,
- target_factory = SCons.Node.FS.default_fs.File,
- source_factory = SCons.Node.FS.default_fs.File)
-
env['BUILDERS']['Java'] = JavaBuilder
env['JAVAC'] = 'javac'
env['JAVACFLAGS'] = ''
- env['JAVACCOM'] = '$JAVAC $JAVACFLAGS -d $_JAVACLASSDIR -sourcepath $_JAVASRCDIR $SOURCES'
+ env['JAVACCOM'] = '$JAVAC $JAVACFLAGS -d ${TARGET.attributes.java_classdir} -sourcepath ${SOURCE.dir.rdir()} $SOURCES'
env['JAVACLASSSUFFIX'] = '.class'
env['JAVASUFFIX'] = '.java'