Permalink
Switch branches/tags
Nothing to show
Find file
Fetching contributors…
Cannot retrieve contributors at this time
executable file 215 lines (172 sloc) 6.14 KB
#!/usr/bin/env ruby
require 'optparse'
require 'pathname'
FILE = Pathname.new(__FILE__).realpath
def split_opts(split_at, argv, right=true)
if i=argv.index(split_at)
[argv[0...i], argv[i+1..-1]]
elsif right
[[],argv]
else
[argv,[]]
end
end
def parse_opts(argv)
cp_elements = []
options = {
:clj_home => nil,
:clj_root => File.join( File.dirname(FILE), ".." ),
:default_libs => ["clojure-contrib", "clojure"],
:main => "clojure.main",
:repl => true,
:rlwrap => nil,
:java => "java",
:debug => false,
:cp_elements => cp_elements,
:java_options=>[],
:script_options=>[]
}
# if there's a --- switch, everything before is for java
# if there's a -- switch, everything after --- before -- is for this wrapper script
# otherwise everything goes to the wrapper script
java_opts,wrapper_script_opts = split_opts("---", argv, true)
wrapper_opts, script_opts = split_opts("--", wrapper_script_opts, false)
options[:java_options] = java_opts
options[:script_options] = script_opts
parser = OptionParser.new do |opts|
opts.banner = "usage: clojure [options] -- [java_options] -- [clojure_options]"
opts.on( "--home=CLOJURE_HOME", "clojure home dir" ) do |clj_home|
options[:clj_home] = clj_home
end
opts.on( "--root=CLOJURE_ROOT", "root dir for clojure libs" ) do |clj_root|
options[:clj_root] = clj_root
end
opts.on( "--java=JAVA", "java runtime" ) do |java|
options[:java] = java
end
opts.on( "-m", "--main=MAIN_CLASS", "main java class to run. defaults to clojure.lang.Repl") do |main|
options[:main] = main
end
opts.on( "--script" , "run a script rather than start a repl" ) do
options[:repl] = false
end
opts.on( "--nodefaultlibs", "disable inclusion of default clojure libs on classpath" ) do
options[:default_libs] = []
end
opts.on( "--rlwrap", "enable rlwrap" ) do
options[:rlwrap] = true
end
opts.on( "--norlwrap", "disable rlwrap") do
options[:rlwrap] = false
end
opts.on( "-d", "--debug" ) do
options[:debug] = true
end
opts.on( "-p", "--path=CLASSPATH_ELEMENT", "jar or dir path to go directly in classpath") do |cp_dir|
cp_elements << [:path, cp_dir]
end
opts.on( "-l", "--lib=LIB_DIR", "clojure library dir containing lib/*.jar and one of LIB_DIR.jar or src/clj or src sub-dir" ) do |clj_lib|
cp_elements << [:clj_lib, clj_lib]
end
opts.on( "-s", "--src_lib=LIB_DIR", "clojure source library dir containing lib/*.jar and one of src/clj or src sub-dir") do |clj_src|
cp_elements << [:clj_src, clj_src]
end
opts.on( "-j", "--jardir=JAR_DIR", "dir containing *.jar files" ) do |jar_dir|
cp_elements << [:jar_dir, jar_dir]
end
end
# parse destructively, keeping any remaining args in options
wrapper_argv = parser.parse!(wrapper_opts)
raise "wrapper script takes no arguments : only options" if !wrapper_argv.empty?
options
end
def check_files_with(files, pred, ex)
files = [*files].compact
f = files.find{ |file| file if File.send(pred, file) }
raise "no match: File.#{pred.to_s} from #{files.inspect}" if ex && !f
f
end
def clj_home(options)
h=check_files_with(options[:clj_home], :directory?, false)
raise "clj_home: #{options[:clj_home]} is not a directory" if options[:clj_home] && !h
h
end
def clj_root(options)
r = check_files_with(options[:clj_root], :directory?, false)
raise "clj_root: #{options[:clj_root]} is not a directory" if options[:clj_root] && !r
r
end
def choose_path(options, path, pred)
# choose an expansion relative to current dir, or relative to libdir
if check_files_with(path, pred, false)
path
elsif clj_root(options) && check_files_with(lp=File.join(clj_root(options), path), pred, false)
lp
else
raise "no path matching: #{path}"
end
end
def expand_path(options, path)
path.split(':').select{ |p| !p.empty? }.map{ |p| choose_path(options, p, :exist?) }
end
def expand_jar_dir(options, dir)
dir = choose_path(options, dir, :directory?)
Dir[ File.join( dir, "**/*.jar") ]
end
def lib_dir(options, lib)
[choose_path(options, lib, :directory?), File.basename(lib)]
end
def expand_clj_src(options, lib)
libdir,libname = lib_dir(options, lib)
paths = [check_files_with([File.join( libdir, "src", "clj" ),
File.join( libdir, "src")],
:directory?, true )]
if File.directory?(lib_jar_dir = File.join(libdir, "lib"))
paths += expand_jar_dir(options, lib_jar_dir)
end
if File.directory?(lib_deps_dir = File.join(libdir, "deps"))
paths += expand_jar_dir(options, lib_deps_dir)
end
paths
end
def expand_clj_lib(options, lib)
libdir,libname = lib_dir(options, lib)
if File.exist?( jar=File.join(libdir, "#{libname}.jar" ) )
paths = [jar]
if File.directory?(lib_jar_dir = File.join(libdir, "lib"))
paths += expand_jar_dir(options, lib_jar_dir)
end
if File.directory?(lib_deps_dir = File.join(libdir, "deps"))
paths += expand_jar_dir(options, lib_deps_dir)
end
paths
else
expand_clj_src(options, lib)
end
end
def expand_classpath(options)
paths = []
paths += options[:default_libs].map{ |lib| expand_clj_lib(options, lib) }.flatten
paths += options[:cp_elements].map do |(type,cp)|
p = self.send("expand_#{type.to_s}", options, cp)
end.flatten
paths += expand_clj_lib(options, clj_home(options)) if clj_home(options)
paths
end
def classpath(options)
expand_classpath(options).map{ |p| File.expand_path(p) }.uniq.join(':')
end
def squish_argv(argv)
argv.map{ |a| "\"#{a}\"" }.join(" ")
end
def rlwrap(options)
%x{which rlwrap}.strip if options[:rlwrap] || (options[:rlwrap].nil? && options[:repl] )
end
def launch_clojure()
options = parse_opts(ARGV)
$stderr << "options: " << options.inspect << "\n" if options[:debug]
cmd_line = "#{rlwrap(options)} #{options[:java]} -Dpid=#{Process.pid} #{squish_argv(options[:java_options])} -cp #{classpath(options)} #{options[:main]} #{"--repl" if options[:repl]} #{squish_argv(options[:script_options])}".strip
$stderr << cmd_line << "\n" if options[:debug]
exec( cmd_line )
end
launch_clojure()