Skip to content

Commit

Permalink
added a method to the jar tool to handle directories and file sources…
Browse files Browse the repository at this point in the history
…. This was taken from the similar Java method in the javac tool. Updated the Jar builder to have an unambiguos name.
  • Loading branch information
dmoody256 committed Oct 26, 2017
1 parent a583f04 commit b54f416
Show file tree
Hide file tree
Showing 2 changed files with 119 additions and 2 deletions.
14 changes: 12 additions & 2 deletions src/engine/SCons/Tool/__init__.py
Expand Up @@ -913,15 +913,25 @@ def createCFileBuilders(env):
# Create common Java builders

def CreateJarBuilder(env):
"""The Jar builder expects a list of class files
which it can package into a jar file.
The jar tool provides an interface for passing other types
of java files such as .java, directories or swig interfaces
and will build them to class files in which it can package
into the jar.
"""
try:
java_jar = env['BUILDERS']['Jar']
java_jar = env['BUILDERS']['JarFile']
except KeyError:
fs = SCons.Node.FS.get_default_fs()
jar_com = SCons.Action.Action('$JARCOM', '$JARCOMSTR')
java_jar = SCons.Builder.Builder(action = jar_com,
suffix = '$JARSUFFIX',
src_suffix = '$JAVACLASSSUFFIX',
src_builder = 'JavaClassFile',
source_factory = fs.Entry)
env['BUILDERS']['Jar'] = java_jar
env['BUILDERS']['JarFile'] = java_jar
return java_jar

def CreateJavaHBuilder(env):
Expand Down
107 changes: 107 additions & 0 deletions src/engine/SCons/Tool/jar.py
Expand Up @@ -35,6 +35,8 @@

import SCons.Subst
import SCons.Util
from SCons.Node.FS import _my_normcase
import os

def jarSources(target, source, env, for_signature):
"""Only include sources that are not a manifest file."""
Expand Down Expand Up @@ -87,10 +89,115 @@ def jarFlags(target, source, env, for_signature):
break
return jarflags

def Jar(env, target = None, source = [], *args, **kw):
"""
A pseudo-Builder wrapper around the separate Jar sources{File,Dir}
Builders.
"""

# jar target should not be a list so assume they passed
# no target and want implicit target to be made and the arg
# was actaully the list of sources
if SCons.Util.is_List(target):
source = target
target = None

# they passed no target so make a target implicitly
if target == None:
try:
# make target from the first source file
target = os.path.splitext(str(source[0]))[0] + env.subst('$JARSUFFIX')
except:
# something strange is happening but attempt anyways
SCons.Warning.Warning("Could not make implicit target from sources, using directory")
target = os.path.basename(str(env.Dir('.'))) + env.subst('$JARSUFFIX')

# make lists out of our target and sources
if not SCons.Util.is_List(target):
target = [target]
if not SCons.Util.is_List(source):
source = [source]

# Pad the target list with repetitions of the last element in the
# list so we have a target for every source element.
target = target + ([target[-1]] * (len(source) - len(target)))

# setup for checking through all the sources and handle accordingly
java_class_suffix = env.subst('$JAVACLASSSUFFIX')
java_suffix = env.subst('$JAVASUFFIX')
target_classes = []

# function for determining what to do with a file and not a directory
# if its already a class file then it can be used as a
# source for jar, otherwise turn it into a class file then
# return the source
def file_to_class(s):
if(str(_my_normcase(s)).endswith(java_suffix)):
return env.JavaClassFile(source = s, *args, **kw)
else:
return [env.fs.File(s)]

# In the case that we are passed just string to a node which is directory
# but does not exist, we need to check all the current targets to see if
# that directory is going to exist so we can add it as a source to Jar builder
def get_all_targets(env, node='.'):
def get_all_targets_iter(env, node):
if node.has_builder():
yield node
for kid in node.all_children():
for kid in get_all_targets(env, kid):
yield kid
node = env.arg2nodes(node, env.fs.Entry)[0]
return list(get_all_targets_iter(env, node))

# loop through the sources and handle each accordingly
# the goal here is to get all the source files into a class
# file or a directory that contains class files
for s in source:
s = env.subst(s)
if isinstance(s, SCons.Node.FS.Base):
if isinstance(s, SCons.Node.FS.File):
# found a file so make sure its a class file
target_classes.extend(file_to_class(s))
else:
# found a dir so make sure its a dir of class files
target_classes.extend(env.JavaClassDir(source = env.fs.Dir(s), *args, **kw))
else:
if os.path.isfile(s):
# found a file that exists on the FS, make sure its a class file
target_classes.extend(file_to_class(s))
elif os.path.isdir(s):
# found a dir on the FS, add it as a dir of class files
target_classes.append(env.fs.Dir(s))
elif s[-len(java_suffix):] == java_suffix or s[-len(java_class_suffix):] == java_class_suffix:
# found a file that may not exists and is only a string
# so add it after converting it to a class file
target_classes.extend(file_to_class(s))
else:
# found a swig file so add it after converting it to class files
if(os.path.splitext(str(s))[1] == ".i"):
target_classes.extend(env.JavaClassFile(source = s, *args, **kw))
else:
# found a directory that does not yet exist, but can exist as a node
# check the target nodes to make sure it will be built, then add
# it as a source
for node in get_all_targets(env):
if(s in str(node) and os.path.splitext(str(node))[1] == ""):
target_classes.append(node)
# at this point all our sources have been converted to classes or directories of class
# so pass it to the Jar builder
return env.JarFile(target = target, source = target_classes, *args, **kw)

def generate(env):
"""Add Builders and construction variables for jar to an Environment."""
SCons.Tool.CreateJarBuilder(env)

SCons.Tool.CreateJavaFileBuilder(env)
SCons.Tool.CreateJavaClassFileBuilder(env)
SCons.Tool.CreateJavaClassDirBuilder(env)

env.AddMethod(Jar)

env['JAR'] = 'jar'
env['JARFLAGS'] = SCons.Util.CLVar('cf')
env['_JARFLAGS'] = jarFlags
Expand Down

0 comments on commit b54f416

Please sign in to comment.