Permalink
Browse files

Export approximate command lines executed for 'doc', 'compile', and '…

…console'
  • Loading branch information...
1 parent daf300f commit f2d29d86783e175359b6488f3abc45b0eba286f4 @harrah harrah committed Feb 28, 2013
@@ -82,6 +82,9 @@ private final class CachedCompiler0(args: Array[String], output: Output, initial
def noErrors(dreporter: DelegatingReporter) = !dreporter.hasErrors && command.ok
+ def commandArguments(sources: Array[File]): Array[String] =
+ (command.settings.recreateArgs ++ sources.map(_.getAbsolutePath)).toArray[String]
+
def run(sources: Array[File], changes: DependencyChanges, callback: AnalysisCallback, log: Logger, delegate: Reporter, progress: CompileProgress): Unit = synchronized
{
debug(log, "Running cached compiler " + hashCode.toHexString + ", interfacing (CompilerInterface) with Scala compiler " + scala.tools.nsc.Properties.versionString)
@@ -11,18 +11,18 @@ import scala.tools.nsc.util.ClassPath
class ConsoleInterface
{
+ def commandArguments(args: Array[String], bootClasspathString: String, classpathString: String, log: Logger): Array[String] =
+ MakeSettings.sync(args, bootClasspathString, classpathString, log).recreateArgs.toArray[String]
+
def run(args: Array[String], bootClasspathString: String, classpathString: String, initialCommands: String, cleanupCommands: String, loader: ClassLoader, bindNames: Array[String], bindValues: Array[Any], log: Logger)
{
- val options = args.toList
- lazy val interpreterSettings = MakeSettings.sync(options, log)
- val compilerSettings = MakeSettings.sync(options, log)
+ lazy val interpreterSettings = MakeSettings.sync(args.toList, log)
+ val compilerSettings = MakeSettings.sync(args, bootClasspathString, classpathString, log)
if(!bootClasspathString.isEmpty)
compilerSettings.bootclasspath.value = bootClasspathString
compilerSettings.classpath.value = classpathString
log.info(Message("Starting scala interpreter..."))
- log.debug(Message(" Boot classpath: " + compilerSettings.bootclasspath.value))
- log.debug(Message(" Classpath: " + compilerSettings.classpath.value))
log.info(Message(""))
val loop = new InterpreterLoop {
@@ -68,6 +68,15 @@ object MakeSettings
throw new InterfaceCompileFailed(Array(), Array(), command.usageMsg)
}
+ def sync(args: Array[String], bootClasspathString: String, classpathString: String, log: Logger): Settings =
+ {
+ val compilerSettings = sync(args.toList, log)
+ if(!bootClasspathString.isEmpty)
+ compilerSettings.bootclasspath.value = bootClasspathString
+ compilerSettings.classpath.value = classpathString
+ compilerSettings
+ }
+
def sync(options: List[String], log: Logger) =
{
val settings = apply(options, log)
@@ -13,8 +13,10 @@ package compiler
* provided by scalaInstance. This class requires a ComponentManager in order to obtain the interface code to scalac and
* the analysis plugin. Because these call Scala code for a different Scala version than the one used for this class, they must
* be compiled for the version of Scala being used.*/
-final class AnalyzingCompiler(val scalaInstance: xsbti.compile.ScalaInstance, val provider: CompilerInterfaceProvider, val cp: xsbti.compile.ClasspathOptions) extends CachedCompilerProvider
+final class AnalyzingCompiler private(val scalaInstance: xsbti.compile.ScalaInstance, val provider: CompilerInterfaceProvider, val cp: xsbti.compile.ClasspathOptions, onArgsF: Seq[String] => Unit) extends CachedCompilerProvider
{
+ def this(scalaInstance: xsbti.compile.ScalaInstance, provider: CompilerInterfaceProvider, cp: xsbti.compile.ClasspathOptions) =
+ this(scalaInstance, provider, cp, _ => ())
def this(scalaInstance: ScalaInstance, provider: CompilerInterfaceProvider) = this(scalaInstance, provider, ClasspathOptions.auto)
@deprecated("A Logger is no longer needed.", "0.13.0")
@@ -23,6 +25,8 @@ final class AnalyzingCompiler(val scalaInstance: xsbti.compile.ScalaInstance, va
@deprecated("A Logger is no longer needed.", "0.13.0")
def this(scalaInstance: xsbti.compile.ScalaInstance, provider: CompilerInterfaceProvider, cp: xsbti.compile.ClasspathOptions, log: Logger) = this(scalaInstance, provider, cp)
+ def onArgs(f: Seq[String] => Unit): AnalyzingCompiler = new AnalyzingCompiler(scalaInstance, provider, cp, f)
+
def apply(sources: Seq[File], changes: DependencyChanges, classpath: Seq[File], singleOutput: File, options: Seq[String], callback: AnalysisCallback, maximumErrors: Int, cache: GlobalsCache, log: Logger)
{
val arguments = (new CompilerArguments(scalaInstance, cp))(Nil, classpath, None, options)
@@ -39,6 +43,7 @@ final class AnalyzingCompiler(val scalaInstance: xsbti.compile.ScalaInstance, va
def compile(sources: Seq[File], changes: DependencyChanges, callback: AnalysisCallback, log: Logger, reporter: Reporter, progress: CompileProgress, compiler: CachedCompiler)
{
+ onArgsF(compiler.commandArguments(sources.toArray))
call("xsbt.CompilerInterface", "run", log)(
classOf[Array[File]], classOf[DependencyChanges], classOf[AnalysisCallback], classOf[xLogger], classOf[Reporter], classOf[CompileProgress], classOf[CachedCompiler]) (
sources.toArray, changes, callback, log, reporter, progress, compiler )
@@ -59,19 +64,35 @@ final class AnalyzingCompiler(val scalaInstance: xsbti.compile.ScalaInstance, va
def doc(sources: Seq[File], classpath: Seq[File], outputDirectory: File, options: Seq[String], log: Logger, reporter: Reporter): Unit =
{
val arguments = (new CompilerArguments(scalaInstance, cp))(sources, classpath, Some(outputDirectory), options)
+ onArgsF(arguments)
call("xsbt.ScaladocInterface", "run", log) (classOf[Array[String]], classOf[xLogger], classOf[Reporter]) (
arguments.toArray[String] : Array[String], log, reporter)
}
def console(classpath: Seq[File], options: Seq[String], initialCommands: String, cleanupCommands: String, log: Logger)(loader: Option[ClassLoader] = None, bindings: Seq[(String, Any)] = Nil): Unit =
{
- val arguments = new CompilerArguments(scalaInstance, cp)
- val classpathString = CompilerArguments.absString(arguments.finishClasspath(classpath))
- val bootClasspath = if(cp.autoBoot) arguments.createBootClasspathFor(classpath) else ""
+ onArgsF(consoleCommandArguments(classpath, options, log))
+ val (classpathString, bootClasspath) = consoleClasspaths(classpath)
val (names, values) = bindings.unzip
call("xsbt.ConsoleInterface", "run", log)(
classOf[Array[String]], classOf[String], classOf[String], classOf[String], classOf[String], classOf[ClassLoader], classOf[Array[String]], classOf[Array[Any]], classOf[xLogger])(
options.toArray[String]: Array[String], bootClasspath, classpathString, initialCommands, cleanupCommands, loader.orNull, names.toArray[String], values.toArray[Any], log)
}
+
+ private[this] def consoleClasspaths(classpath: Seq[File]): (String, String) =
+ {
+ val arguments = new CompilerArguments(scalaInstance, cp)
+ val classpathString = CompilerArguments.absString(arguments.finishClasspath(classpath))
+ val bootClasspath = if(cp.autoBoot) arguments.createBootClasspathFor(classpath) else ""
+ (classpathString, bootClasspath)
+ }
+ def consoleCommandArguments(classpath: Seq[File], options: Seq[String], log: Logger): Seq[String] =
+ {
+ val (classpathString, bootClasspath) = consoleClasspaths(classpath)
+ val argsObj = call("xsbt.ConsoleInterface", "commandArguments", log)(
+ classOf[Array[String]], classOf[String], classOf[String], classOf[xLogger])(
+ options.toArray[String]: Array[String], bootClasspath, classpathString, log)
+ argsObj.asInstanceOf[Array[String]].toSeq
+ }
def force(log: Logger): Unit = provider(scalaInstance, log)
private def call(interfaceClassName: String, methodName: String, log: Logger)(argTypes: Class[_]*)(args: AnyRef*): AnyRef =
{
@@ -20,10 +20,14 @@ trait JavaCompiler extends xsbti.compile.JavaCompiler
}
apply(sources, classpath, outputDirectory, options)(log)
}
+
+ def onArgs(f: Seq[String] => Unit): JavaCompiler
}
trait Javadoc
{
def doc(sources: Seq[File], classpath: Seq[File], outputDirectory: File, options: Seq[String], maximumErrors: Int, log: Logger)
+
+ def onArgs(f: Seq[String] => Unit): Javadoc
}
trait JavaTool extends Javadoc with JavaCompiler
{
@@ -34,6 +38,8 @@ trait JavaTool extends Javadoc with JavaCompiler
compile(JavaCompiler.javadoc, sources, classpath, outputDirectory, options)(log)
def compile(contract: JavacContract, sources: Seq[File], classpath: Seq[File], outputDirectory: File, options: Seq[String])(implicit log: Logger): Unit
+
+ def onArgs(f: Seq[String] => Unit): JavaTool
}
object JavaCompiler
{
@@ -52,18 +58,25 @@ object JavaCompiler
}
}
- def construct(f: Fork, cp: ClasspathOptions, scalaInstance: ScalaInstance): JavaTool =
- new JavaTool {
- def compile(contract: JavacContract, sources: Seq[File], classpath: Seq[File], outputDirectory: File, options: Seq[String])(implicit log: Logger) {
- val augmentedClasspath = if(cp.autoBoot) classpath ++ Seq(scalaInstance.libraryJar) else classpath
- val javaCp = ClasspathOptions.javac(cp.compiler)
- val arguments = (new CompilerArguments(scalaInstance, javaCp))(sources, augmentedClasspath, Some(outputDirectory), options)
- log.debug("Calling " + contract.name.capitalize + " with arguments:\n\t" + arguments.mkString("\n\t"))
- val code: Int = f(contract, arguments, log)
- log.debug(contract.name + " returned exit code: " + code)
- if( code != 0 ) throw new CompileFailed(arguments.toArray, contract.name + " returned nonzero exit code", Array())
- }
+ def construct(f: Fork, cp: ClasspathOptions, scalaInstance: ScalaInstance): JavaTool = new JavaTool0(f, cp, scalaInstance, _ => ())
+
+ private[this] class JavaTool0(f: Fork, cp: ClasspathOptions, scalaInstance: ScalaInstance, onArgsF: Seq[String] => Unit) extends JavaTool
+ {
+ def onArgs(g: Seq[String] => Unit): JavaTool = new JavaTool0(f, cp, scalaInstance, g)
+ def commandArguments(sources: Seq[File], classpath: Seq[File], outputDirectory: File, options: Seq[String], log: Logger): Seq[String] =
+ {
+ val augmentedClasspath = if(cp.autoBoot) classpath ++ Seq(scalaInstance.libraryJar) else classpath
+ val javaCp = ClasspathOptions.javac(cp.compiler)
+ (new CompilerArguments(scalaInstance, javaCp))(sources, augmentedClasspath, Some(outputDirectory), options)
+ }
+ def compile(contract: JavacContract, sources: Seq[File], classpath: Seq[File], outputDirectory: File, options: Seq[String])(implicit log: Logger) {
+ val arguments = commandArguments(sources, classpath, outputDirectory, options, log)
+ onArgsF(arguments)
+ val code: Int = f(contract, arguments, log)
+ log.debug(contract.name + " returned exit code: " + code)
+ if( code != 0 ) throw new CompileFailed(arguments.toArray, contract.name + " returned nonzero exit code", Array())
}
+ }
def directOrFork(cp: ClasspathOptions, scalaInstance: ScalaInstance)(implicit doFork: Fork): JavaTool =
construct(directOrForkJavac, cp, scalaInstance)
@@ -7,5 +7,7 @@
public interface CachedCompiler
{
+ /** Returns an array of arguments representing the nearest command line equivalent of a call to run but without the command name itself.*/
+ public String[] commandArguments(File[] sources);
public void run(File[] sources, DependencyChanges cpChanges, AnalysisCallback callback, Logger log, Reporter delegate, CompileProgress progress);
}
@@ -3,7 +3,7 @@
*/
package sbt
- import java.io.File
+ import java.io.{File, PrintWriter}
import compiler.{AnalyzingCompiler, JavaCompiler}
import Predef.{conforms => _, _}
@@ -20,8 +20,9 @@ object Doc
import RawCompileLike._
def scaladoc(label: String, cache: File, compiler: AnalyzingCompiler): Gen =
cached(cache, prepare(label + " Scala API documentation", compiler.doc))
+
def javadoc(label: String, cache: File, doc: sbt.compiler.Javadoc): Gen =
- cached(cache, prepare(label + " Scala API documentation", filterSources(javaSourcesOnly, doc.doc)))
+ cached(cache, prepare(label + " Java API documentation", filterSources(javaSourcesOnly, doc.doc)))
val javaSourcesOnly: File => Boolean = _.getName.endsWith(".java")
@@ -34,6 +34,7 @@ ShowCommand + """ <setting>
val LastCommand = "last"
val LastGrepCommand = "last-grep"
+ val ExportCommand = "export"
val lastGrepBrief = (LastGrepCommand, "Shows lines from the last output for 'key' that match 'pattern'.")
val lastGrepDetailed =
@@ -56,6 +57,17 @@ LastCommand + """
See also '""" + LastGrepCommand + "'."
+ val exportBrief = (ExportCommand, "Displays the equivalent command line(s) for previously executed tasks.")
+ val exportDetailed =
+s"""$ExportCommand <task-key>+
+ Prints the approximate command line(s) for the previously executed tasks.
+
+ NOTE: These command lines are necessarily approximate. Usually tasks do not actually
+ execute the command line and the actual command line program may not be installed or
+ on the PATH. Incremental tasks will typically show the command line for the previous
+ incremental run and not for a full run.
+"""
+
val InspectCommand = "inspect"
val inspectBrief = (InspectCommand, "Prints the value for 'key', the defining scope, delegates, related definitions, and dependencies.")
val inspectDetailed =
@@ -4,7 +4,6 @@
package sbt
import java.io.File
- import compiler.AnalyzingCompiler
object ConsoleProject
{
@@ -21,7 +21,7 @@ package sbt
import scala.xml.NodeSeq
import org.apache.ivy.core.module.{descriptor, id}
import descriptor.ModuleDescriptor, id.ModuleRevisionId
- import java.io.File
+ import java.io.{File, PrintWriter}
import java.net.{URI,URL,MalformedURLException}
import java.util.concurrent.Callable
import sbinary.DefaultProtocol.StringFormat
@@ -619,9 +619,11 @@ object Defaults extends BuildCommon
val label = nameForSrc(config.name)
val (options, runDoc) =
if(hasScala)
- (in.config.options ++ Opts.doc.externalAPI(xapis), Doc.scaladoc(label, s.cacheDirectory / "scala", in.compilers.scalac))
+ (in.config.options ++ Opts.doc.externalAPI(xapis),
+ Doc.scaladoc(label, s.cacheDirectory / "scala", in.compilers.scalac.onArgs(exported(s, "scaladoc"))))
else if(hasJava)
- (in.config.javacOptions, Doc.javadoc(label, s.cacheDirectory / "java", in.compilers.javac))
+ (in.config.javacOptions,
+ Doc.javadoc(label, s.cacheDirectory / "java", in.compilers.javac.onArgs(exported(s, "javadoc"))))
else
(Nil, RawCompileLike.nop)
runDoc(srcs, cp, out, options, in.config.maxErrors, s.log)
@@ -641,15 +643,29 @@ object Defaults extends BuildCommon
def consoleTask(classpath: TaskKey[Classpath], task: TaskKey[_]): Initialize[Task[Unit]] =
(compilers in task, classpath in task, scalacOptions in task, initialCommands in task, cleanupCommands in task, taskTemporaryDirectory in task, scalaInstance in task, streams) map {
(cs, cp, options, initCommands, cleanup, temp, si, s) =>
- val fullcp = (data(cp) ++ si.jars).distinct
+ val cpFiles = data(cp)
+ val fullcp = (cpFiles ++ si.jars).distinct
val loader = sbt.classpath.ClasspathUtilities.makeLoader(fullcp, si, IO.createUniqueDirectory(temp))
- (new Console(cs.scalac))(data(cp), options, loader, initCommands, cleanup)()(s.log).foreach(msg => error(msg))
+ val compiler = cs.scalac.onArgs(exported(s, "scala"))
+ (new Console(compiler))(cpFiles, options, loader, initCommands, cleanup)()(s.log).foreach(msg => error(msg))
println()
}
+ private[this] def exported(w: PrintWriter, command: String): Seq[String] => Unit = args =>
+ w.println( (command +: args).mkString(" ") )
+ private[this] def exported(s: TaskStreams, command: String): Seq[String] => Unit = args =>
+ exported(s.text("export"), command)
+
def compileTaskSettings: Seq[Setting[_]] = inTask(compile)(compileInputsSettings)
- def compileTask = (compileInputs in compile, streams) map { (i,s) => Compiler(i,s.log) }
+ def compileTask: Initialize[Task[inc.Analysis]] = Def.task { compileTaskImpl(streams.value, (compileInputs in compile).value) }
+ private[this] def compileTaskImpl(s: TaskStreams, ci: Compiler.Inputs): inc.Analysis =
+ {
+ lazy val x = s.text("export")
+ def onArgs(cs: Compiler.Compilers) = cs.copy(scalac = cs.scalac.onArgs(exported(x, "scalac")), javac = cs.javac.onArgs(exported(x, "javac")))
+ val i = ci.copy(compilers = onArgs(ci.compilers))
+ Compiler(i,s.log)
+ }
def compileIncSetupTask =
(dependencyClasspath, skip in compile, definesClass, compilerCache, streams, incOptions) map { (cp, skip, definesC, cache, s, incOptions) =>
Compiler.IncSetup(analysisMap(cp), definesC, skip, s.cacheDirectory / "inc_compile", cache, incOptions)
@@ -77,7 +77,7 @@ object BuiltinCommands
def ScriptCommands: Seq[Command] = Seq(ignore, exit, Script.command, act, nop)
def DefaultCommands: Seq[Command] = Seq(ignore, help, about, tasks, settingsCommand, loadProject,
projects, project, reboot, read, history, set, sessionCommand, inspect, loadProjectImpl, loadFailed, Cross.crossBuild, Cross.switchVersion,
- setOnFailure, clearOnFailure, ifLast, multi, shell, continuous, eval, alias, append, last, lastGrep, boot, nop, call, exit, act)
+ setOnFailure, clearOnFailure, ifLast, multi, shell, continuous, eval, alias, append, last, lastGrep, export, boot, nop, call, exit, act)
def DefaultBootCommands: Seq[String] = LoadProject :: (IfLast + " " + Shell) :: Nil
def boot = Command.make(BootCommand)(bootParser)
@@ -295,20 +295,26 @@ object BuiltinCommands
val spacedKeyParser = (s: State) => Act.requireSession(s, token(Space) ~> Act.scopedKeyParser(s))
val spacedAggregatedParser = (s: State) => Act.requireSession(s, token(Space) ~> Act.aggregatedKeyParser(s))
- val aggregatedKeyValueParser: State => Parser[Option[AnyKeys]] =
- (s: State) => spacedAggregatedParser(s).map(x => Act.keyValues(s)(x) ).?
+ val exportParser: State => Parser[AnyKeys] = (s: State) => spacedAggregatedParser(s).map(x => Act.keyValues(s)(x) )
+ val aggregatedKeyValueParser: State => Parser[Option[AnyKeys]] = s => exportParser(s).?
def lastGrepParser(s: State) = Act.requireSession(s, (token(Space) ~> token(NotSpace, "<pattern>")) ~ aggregatedKeyValueParser(s))
def last = Command(LastCommand, lastBrief, lastDetailed)(aggregatedKeyValueParser) {
- case (s,Some(sks)) =>
- val (str, ref, display) = extractLast(s)
- Output.last(sks, str.streams(s), printLast(s))(display)
- keepLastLog(s)
+ case (s,Some(sks)) => lastImpl(s, sks, None)
case (s, None) =>
for(logFile <- lastLogFile(s)) yield
Output.last( logFile, printLast(s) )
keepLastLog(s)
}
+ def export = Command(ExportCommand, exportBrief, exportDetailed)(exportParser) { (s, sks) =>
+ lastImpl(s, sks, Some("export"))
+ }
+ private[this] def lastImpl(s: State, sks: AnyKeys, sid: Option[String]): State =
+ {
+ val (str, ref, display) = extractLast(s)
+ Output.last(sks, str.streams(s), printLast(s), sid)(display)
+ keepLastLog(s)
+ }
/** Determines the log file that last* commands should operate on. See also isLastOnly. */
def lastLogFile(s: State) =
Oops, something went wrong.

0 comments on commit f2d29d8

Please sign in to comment.