Skip to content

Commit 6d09a1b

Browse files
committed
Merge pull request scala#4957 from retronym/topic/merge-2.11.x-to-2.12.x-20160210
Merge 2.11.x to 2.12.x [ci:last-only]
2 parents b19e253 + 6455062 commit 6d09a1b

File tree

15 files changed

+502
-19
lines changed

15 files changed

+502
-19
lines changed

build.sbt

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,18 @@ lazy val commonSettings = clearSourceAndResourceDirectories ++ publishSettings +
196196
},
197197
// Remove auto-generated manifest attributes
198198
packageOptions in Compile in packageBin := Seq.empty,
199-
packageOptions in Compile in packageSrc := Seq.empty
199+
packageOptions in Compile in packageSrc := Seq.empty,
200+
201+
// Lets us CTRL-C partest without exiting SBT entirely
202+
cancelable in Global := true,
203+
// When we fork subprocesses, use the base directory as the working directory.
204+
// This enables `sbt> partest test/files/run/t1.scala` or `sbt> scalac sandbox/test.scala`
205+
baseDirectory in Compile := (baseDirectory in ThisBuild).value,
206+
baseDirectory in Test := (baseDirectory in ThisBuild).value,
207+
208+
// Don't log process output (e.g. of forked `compiler/runMain ...Main`), just pass it
209+
// directly to stdout
210+
outputStrategy in run := Some(StdoutOutput)
200211
)
201212

202213
/** Extra post-processing for the published POM files. These are needed to create POMs that
@@ -409,7 +420,6 @@ lazy val repl = configureAsSubproject(project)
409420
.settings(
410421
connectInput in run := true,
411422
publishArtifact := false,
412-
outputStrategy in run := Some(StdoutOutput),
413423
run <<= (run in Compile).partialInput(" -usejavacp") // Automatically add this so that `repl/run` works without additional arguments.
414424
)
415425
.dependsOn(compiler, interactive)
@@ -456,7 +466,8 @@ lazy val replJlineEmbedded = Project("repl-jline-embedded", file(".") / "target"
456466
val outdir = (classDirectory in Compile).value
457467
JarJar(inputs, outdir, config)
458468
}),
459-
publishArtifact := false
469+
publishArtifact := false,
470+
connectInput in run := true
460471
)
461472
.dependsOn(replJline)
462473

@@ -767,3 +778,25 @@ def generateServiceProviderResources(services: (String, String)*): Setting[_] =
767778
}.taskValue
768779

769780
buildDirectory in ThisBuild := (baseDirectory in ThisBuild).value / "build-sbt"
781+
782+
// Add tab completion to partest
783+
commands += Command("partest")(_ => PartestUtil.partestParser((baseDirectory in ThisBuild).value, (baseDirectory in ThisBuild).value / "test")) { (state, parsed) =>
784+
("test/it:testOnly -- " + parsed) :: state
785+
}
786+
787+
// Add tab completion to scalac et al.
788+
commands ++= {
789+
val commands =
790+
List(("scalac", "compiler", "scala.tools.nsc.Main"),
791+
("scala", "repl-jline-embedded", "scala.tools.nsc.MainGenericRunner"),
792+
("scaladoc", "scaladoc", "scala.tools.nsc.ScalaDoc"))
793+
794+
commands.map {
795+
case (entryPoint, projectRef, mainClassName) =>
796+
Command(entryPoint)(_ => ScalaOptionParser.scalaParser(entryPoint, (baseDirectory in ThisBuild).value)) { (state, parsedOptions) =>
797+
(projectRef + "/runMain " + mainClassName + " -usejavacp " + parsedOptions) :: state
798+
}
799+
}
800+
}
801+
802+
addCommandAlias("scalap", "scalap/compile:runMain scala.tools.scalap.Main -usejavacp")

build.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ TODO:
183183

184184
<property name="dists.dir" value="${basedir}/dists"/>
185185

186-
<property name="copyright.string" value="Copyright 2002-2015, LAMP/EPFL"/>
186+
<property name="copyright.string" value="Copyright 2002-2016, LAMP/EPFL"/>
187187

188188
<!-- These are NOT the flags used to run SuperSabbus, but the ones written
189189
into the script runners created with scala.tools.ant.ScalaTool -->

doc/LICENSE.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ Scala is licensed under the [BSD 3-Clause License](http://opensource.org/license
22

33
## Scala License
44

5-
Copyright (c) 2002-2015 EPFL
5+
Copyright (c) 2002-2016 EPFL
66

7-
Copyright (c) 2011-2015 Typesafe, Inc.
7+
Copyright (c) 2011-2016 Typesafe, Inc.
88

99
All rights reserved.
1010

doc/License.rtf

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@
1010
\fs48 Scala License
1111
\fs40 \
1212

13-
\fs26 Copyright (c) 2002-2015 EPFL\
14-
Copyright (c) 2011-2015 Typesafe, Inc.\
13+
\fs26 Copyright (c) 2002-2016 EPFL\
14+
Copyright (c) 2011-2016 Typesafe, Inc.\
1515
All rights reserved.\
1616
\
1717
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\

project/ParserUtil.scala

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import sbt._
2+
import sbt.complete.Parser._
3+
import sbt.complete.Parsers._
4+
import sbt.complete._
5+
6+
object ParserUtil {
7+
def notStartingWith(parser: Parser[String], c: Char): Parser[String] = parser & not(c ~> any.*, "value cannot start with " + c + ".")
8+
def concat(p: Parser[(String, String)]): Parser[String] = {
9+
p.map(x => x._1 + x._2)
10+
}
11+
12+
def Opt(a: Parser[String]) = a.?.map(_.getOrElse(""))
13+
14+
val StringBasicNotStartingWithDash = notStartingWith(StringBasic, '-')
15+
val IsDirectoryFilter = new SimpleFileFilter(_.isDirectory)
16+
val JarOrDirectoryParser = FileParser(GlobFilter("*.jar") || IsDirectoryFilter)
17+
def FileParser(fileFilter: FileFilter, dirFilter: FileFilter = AllPassFilter, base: File = file(".")) = {
18+
def matching(prefix: String): List[String] = {
19+
val preFile = file(prefix)
20+
val cwd = base
21+
val parent = Option(preFile.getParentFile).getOrElse(cwd)
22+
if (preFile.exists) {
23+
if (preFile.isDirectory) {
24+
preFile.*(IsDirectoryFilter.&&(dirFilter) || fileFilter).get.map(_.getPath).toList
25+
} else {
26+
List(preFile).filter(fileFilter.accept).map(_.getPath)
27+
}
28+
}
29+
else if (parent != null) {
30+
def ensureSuffix(s: String, suffix: String) = if (s.endsWith(suffix)) s else s + suffix
31+
def pathOf(f: File): String = {
32+
val f1 = if (preFile.getParentFile == null) f.relativeTo(cwd).getOrElse(f) else f
33+
if (f1.isDirectory && !fileFilter.accept(f1)) ensureSuffix(f1.getPath, "/") else f1.getPath
34+
}
35+
val childFilter = GlobFilter(preFile.name + "*") && ((IsDirectoryFilter && dirFilter) || fileFilter)
36+
val children = parent.*(childFilter).get
37+
children.map(pathOf).toList
38+
} else Nil
39+
}
40+
def displayPath = Completions.single(Completion.displayOnly("<path>"))
41+
token(StringBasic, TokenCompletions.fixed((seen, level) => if (seen.isEmpty) displayPath else matching(seen) match {
42+
case Nil => displayPath
43+
case x :: Nil =>
44+
if (fileFilter.accept(file(x)))
45+
Completions.strict(Set(Completion.tokenDisplay(x.stripPrefix(seen), x)))
46+
else
47+
Completions.strict(Set(Completion.suggestion(x.stripPrefix(seen))))
48+
case xs =>
49+
Completions.strict(xs.map(x => Completion.tokenDisplay(x.stripPrefix(seen), x)).toSet)
50+
})).filter(!_.startsWith("-"), x => x)
51+
}
52+
}

project/PartestUtil.scala

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
import sbt._
2+
import sbt.complete._, Parser._, Parsers._
3+
4+
object PartestUtil {
5+
private case class TestFiles(srcPath: String, globalBase: File, testBase: File) {
6+
private val testCaseDir = new SimpleFileFilter(f => f.isDirectory && f.listFiles.nonEmpty && !(f.getParentFile / (f.name + ".res")).exists)
7+
private val testCaseFilter = GlobFilter("*.scala") | GlobFilter("*.java") | GlobFilter("*.res") || testCaseDir
8+
private def testCaseFinder = (testBase / srcPath).*(AllPassFilter).*(testCaseFilter)
9+
private val basePaths = allTestCases.map(_._2.split('/').take(3).mkString("/") + "/").distinct
10+
11+
def allTestCases = testCaseFinder.pair(relativeTo(globalBase))
12+
def basePathExamples = new FixedSetExamples(basePaths)
13+
private def equiv(f1: File, f2: File) = f1.getCanonicalFile == f2.getCanonicalFile
14+
def parentChain(f: File): Iterator[File] =
15+
if (f == null || !f.exists) Iterator()
16+
else Iterator(f) ++ (if (f.getParentFile == null) Nil else parentChain(f.getParentFile))
17+
def isParentOf(parent: File, f2: File, maxDepth: Int) =
18+
parentChain(f2).take(maxDepth).exists(p1 => equiv(p1, parent))
19+
def isTestCase(f: File) = {
20+
val grandParent = if (f != null && f.getParentFile != null) f.getParentFile.getParentFile else null
21+
grandParent != null && equiv(grandParent, testBase / srcPath) && testCaseFilter.accept(f)
22+
}
23+
def mayContainTestCase(f: File) = {
24+
isParentOf(testBase / srcPath, f, 2) || isParentOf(f, testBase / srcPath, Int.MaxValue)
25+
}
26+
}
27+
/** A parser for the custom `partest` command */
28+
def partestParser(globalBase: File, testBase: File): Parser[String] = {
29+
val knownUnaryOptions = List(
30+
"--pos", "--neg", "--run", "--jvm", "--res", "--ant", "--scalap", "--specialized",
31+
"--scalacheck", "--instrumented", "--presentation", "--failed", "--update-check",
32+
"--show-diff", "--verbose", "--terse", "--debug", "--version", "--self-test", "--help")
33+
val srcPathOption = "--srcpath"
34+
val grepOption = "--grep"
35+
36+
// HACK: if we parse `--srpath scaladoc`, we overwrite this var. The parser for test file paths
37+
// then lazily creates the examples based on the current value.
38+
// TODO is there a cleaner way to do this with SBT's parser infrastructure?
39+
var srcPath = "files"
40+
var _testFiles: TestFiles = null
41+
def testFiles = {
42+
if (_testFiles == null || _testFiles.srcPath != srcPath) _testFiles = new TestFiles(srcPath, globalBase, testBase)
43+
_testFiles
44+
}
45+
val TestPathParser = ParserUtil.FileParser(
46+
new SimpleFileFilter(f => testFiles.isTestCase(f)),
47+
new SimpleFileFilter(f => testFiles.mayContainTestCase(f)), globalBase)
48+
49+
// allow `--grep "is unchecked" | --grep *t123*, in the spirit of ./bin/partest-ack
50+
// superset of the --grep built into partest itself.
51+
val Grep = {
52+
def expandGrep(x: String): Seq[String] = {
53+
val matchingFileContent = try {
54+
val Pattern = ("(?i)" + x).r
55+
testFiles.allTestCases.filter {
56+
case (testFile, testPath) =>
57+
val assocFiles = List(".check", ".flags").map(testFile.getParentFile / _)
58+
val sourceFiles = if (testFile.isFile) List(testFile) else testFile.**(AllPassFilter).get.toList
59+
val allFiles = testFile :: assocFiles ::: sourceFiles
60+
allFiles.exists { f => f.exists && f.isFile && Pattern.findFirstIn(IO.read(f)).isDefined }
61+
}
62+
} catch {
63+
case _: Throwable => Nil
64+
}
65+
val matchingFileName = try {
66+
val filter = GlobFilter("*" + x + "*")
67+
testFiles.allTestCases.filter(x => filter.accept(x._1.name))
68+
} catch {
69+
case t: Throwable => Nil
70+
}
71+
(matchingFileContent ++ matchingFileName).map(_._2).distinct.sorted
72+
}
73+
74+
val completion = Completions.strict(Set("<filename glob>", "<regex> (for source, flags or checkfile contents)").map(s => Completion.displayOnly(s)))
75+
val tokenCompletion = TokenCompletions.fixed((seen, level) => completion)
76+
77+
val globOrPattern = StringBasic.map(expandGrep).flatMap {
78+
case Seq() => failure("no tests match pattern / glob")
79+
case x => success(x.mkString(" "))
80+
}
81+
token(grepOption <~ Space) ~> token(globOrPattern, tokenCompletion)
82+
}
83+
84+
val SrcPath = ((token(srcPathOption) <~ Space) ~ token(StringBasic.examples(Set("files", "pending", "scaladoc")))) map {
85+
case opt ~ path =>
86+
srcPath = path
87+
opt + " " + path
88+
}
89+
val P = oneOf(knownUnaryOptions.map(x => token(x))) | SrcPath | TestPathParser | Grep
90+
(Space ~> repsep(P, oneOrMore(Space))).map(_.mkString(" ")).?.map(_.getOrElse("")) <~ OptSpace
91+
}
92+
}

0 commit comments

Comments
 (0)