This commit does the following things:
* Removes the boolean from the instance context passes to the linter.
* Prohibits the use of value inside anonymous functions.
* Improves the previous check of `value` inside if.
The improvements have occurred thanks to the fix of an oversight in the
traverser. As a result, several implementation of tasks have been
rewritten because of new compilation failures by both checks.
Note that the new check that prohibits the use of value inside anonymous
functions ignores all the functions whose parameters have been
synthesized by scalac (that can happen in a number of different
scenarios, like for comprehensions). Other scripted tests have also been
fixed.
Running `.value` inside an anonymous function yields the following
error:
```
[error] /data/rw/code/scala/sbt/main-settings/src/test/scala/sbt/std/TaskPosSpec.scala:50:24: The evaluation of `foo` inside an anonymous function is prohibited.
[error]
[error] Problem: Task invocations inside anonymous functions are evaluated independently of whether the anonymous function is invoked or not.
[error]
[error] Solution:
[error] 1. Make `foo` evaluation explicit outside of the function body if you don't care about its evaluation.
[error] 2. Use a dynamic task to evaluate `foo` and pass that value as a parameter to an anonymous function.
[error]
[error] val anon = () => foo.value + " "
[error] ^
```
`.value` inside the if of a regular task is unsafe. The wrapping task
will always execute the value, no matter what the if predicate yields.
This commit adds the infrastructure to lint code for every sbt DSL
macro. It also adds example of neg tests that check that the DSL checks
are in place.
The sbt checks yield error for this specific case because we may want to
explore changing this behaviour in the future. The solutions to this are
straightforward and explained in the error message, that looks like
this:
```
EXPECTED: The evaluation of `fooNeg` happens always inside a regular task.
PROBLEM: `fooNeg` is inside the if expression of a regular task.
Regular tasks always evaluate task inside the bodies of if expressions.
SOLUTION:
1. If you only want to evaluate it when the if predicate is true, use a dynamic task.
2. Otherwise, make the static evaluation explicit by evaluating `fooNeg` outside the if expression.
```
Aside from those solutions, this commit also adds a way to disable any
DSL check by using the new `sbt.unchecked` annotation. This annotation,
similar to `scala.annotation.unchecked` disables compiler output. In our
case, it will disable any task dsl check, making it silent.
Examples of positive checks have also been added.
There have been only two places in `Defaults.scala` where this check has
made compilation fail.
The first one is inside `allDependencies`. To ensure that we still have
static dependencies for `allDependencies`, I have hoisted up the value
invocation outside the if expression. We may want to explore adding a
dynamic task in the future, though. We are doing unnecessary work there.
The second one is inside `update` and is not important because it's not
exposed to the user. We use a `taskDyn`.
This commit adds the first version of the checker that will tell users
if they are doing something wrong.
The first version warns any user that write `.value` inside an if
expression.
As the test integration is not yet working correctly and messages are
swallowed, we have to println to get info from the test.
The previous scalafmt plugin had two problems:
* Caching with Coursier did not work correctly
* It failed after the upgrade to 1.0 in my computer (from a clean fork):
```
[error] (testingProj/compile:scalafmtInc) java.lang.NoClassDefFoundError: Could not initialize class scala.meta.package$
[error] (runProj/compile:scalafmtInc) java.lang.NoClassDefFoundError: Could not initialize class scala.meta.package$
[error] (taskProj/compile:scalafmtInc) java.lang.NoClassDefFoundError: Could not initialize class scala.meta.package$
[error] (stdTaskProj/compile:scalafmtInc) java.lang.NoClassDefFoundError: Could not initialize class scala.meta.package$
[error] (actionsProj/compile:scalafmtInc) java.lang.NoClassDefFoundError: Could not initialize class scala.meta.package$
[error] (protocolProj/compile:scalafmtInc) java.lang.NoClassDefFoundError: Could not initialize class scala.meta.package$
[error] (commandProj/compile:scalafmtInc) java.lang.NoClassDefFoundError: Could not initialize class scala.meta.package$
[error] (mainSettingsProj/compile:scalafmtInc) java.lang.NoClassDefFoundError: Could not initialize class scala.meta.package$
[error] (mainProj/compile:scalafmtInc) java.lang.NoClassDefFoundError: Could not initialize class scala.meta.package$
[error] (sbtProj/compile:scalafmtInc) java.lang.NoClassDefFoundError: Could not initialize class scala.meta.package$
[error] (scriptedPluginProj/compile:scalafmtInc) java.lang.NoClassDefFoundError: Could not initialize class scala.meta.package$
[error] (scriptedSbtProj/compile:scalafmtInc) java.lang.NoClassDefFoundError: Could not initialize class scala.meta.package$
[error] Total time: 19 s, completed May 24, 2017 10:44:56 AM
```
This commit replaces the previous scalafmt integration by the one
created by Lucidsoftware, big shoutout! (/cc @pauldraper)
https://github.com/lucidsoftware/neo-sbt-scalafmt
This commit moves everything behind the old util-appmacro over to
sbt/sbt.
appmacro has been renamed as core-macros. It is indeed the project
that defines the main logic to manipulate macros, and defines interfaces
that are then implemented by main-settings. Because of this strong
relationship between these two modules, I find that they have to stay
together and be able to be modified in one commit. I've realised this
while hacking on the macro changes for the usability of sbt.
The reason for this change is because the logic of this module is really
tight to the implementation of sbt and, I would even say, essentially
define the sbt DSL.
Some plugins remain commented out, for now.
sbt-doge is no longer needed because a variant of it has been folded
into sbt 1.
For some reason scripted requires src/doc jars of sbt, so switch back to
using `publishAll` rather than `publishLocalBinAll`. :(
Also, the sys.prop change in scripted is to force log4j2 to not use a
thread context classloader, and avoid the following:
ERROR StatusLogger Unable to create custom ContextSelector. Falling back to default.
java.lang.ClassCastException: Cannot cast org.apache.logging.log4j.core.async.AsyncLoggerContextSelector to org.apache.logging.log4j.core.selector.ContextSelector
at java.lang.Class.cast(Class.java:3369)
at org.apache.logging.log4j.util.LoaderUtil.newCheckedInstanceOf(LoaderUtil.java:201)
at org.apache.logging.log4j.util.LoaderUtil.newCheckedInstanceOfProperty(LoaderUtil.java:226)
at org.apache.logging.log4j.core.impl.Log4jContextFactory.createContextSelector(Log4jContextFactory.java:97)
at org.apache.logging.log4j.core.impl.Log4jContextFactory.<init>(Log4jContextFactory.java:58)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at java.lang.Class.newInstance(Class.java:442)
at org.apache.logging.log4j.LogManager.<clinit>(LogManager.java:94)
at org.apache.logging.log4j.spi.ThreadContextMapFactory.createThreadContextMap(ThreadContextMapFactory.java:73)
at org.apache.logging.log4j.ThreadContext.init(ThreadContext.java:223)
at org.apache.logging.log4j.ThreadContext.<clinit>(ThreadContext.java:202)
at org.apache.logging.log4j.core.impl.ContextDataInjectorFactory.createDefaultInjector(ContextDataInjectorFactory.java:83)
at org.apache.logging.log4j.core.impl.ContextDataInjectorFactory.createInjector(ContextDataInjectorFactory.java:67)
at org.apache.logging.log4j.core.lookup.ContextMapLookup.<init>(ContextMapLookup.java:34)
at org.apache.logging.log4j.core.lookup.Interpolator.<init>(Interpolator.java:117)
at org.apache.logging.log4j.core.config.AbstractConfiguration.<init>(AbstractConfiguration.java:125)
at org.apache.logging.log4j.core.config.DefaultConfiguration.<init>(DefaultConfiguration.java:46)
at org.apache.logging.log4j.core.layout.PatternLayout$Builder.build(PatternLayout.java:650)
at org.apache.logging.log4j.core.layout.PatternLayout.createDefaultLayout(PatternLayout.java:487)
at sbt.internal.util.ConsoleAppender.<init>(ConsoleAppender.scala:245)
at sbt.internal.util.ConsoleAppender$.apply(ConsoleAppender.scala:196)
at sbt.internal.util.ConsoleLogger.<init>(ConsoleAppender.scala:42)
at sbt.internal.util.ConsoleLogger$.apply(ConsoleAppender.scala:34)
at sbt.test.ScriptedRunner.run(ScriptedTests.scala:221)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at Scripted$.doScripted(Scripted.scala:125)
at $0483e89d182e9d240274$.$anonfun$scriptedTask$5(build.sbt:301)
I've tried to put together some scripted tests to remove the overhead of
compiling the whole sbt, which is around 3 minutes every time.
This new structure *should* make the scripted tests run faster.
Aside from this, we do some more tweaks:
* Increase memory.
* Fork processes to compile and run (to see if it makes a difference).
* Pass in the server flag to sbt.
This commit makes sure that between every run in batch mode the local
root project name is updated if no name is set.
This fixes project/generated-root-no-project that was assuming that the
root directory name was `generated-root-no-project`. This invariant does
not hold anymore with the batch-mode. Now one sbt dir is shared for lots
of scripted tests.
* Remove MaxPermSize from another scripted opts
* Reduce memory of sbt host to 1g instead of 2g
* Add Xms java options to scripted
* Enable parallelism with 512M for sbt tests
* Parallelism + batch mode
Clean up first analysis to make sure that test utilities using
information from analysis have correct information that does not collide
with the compilation analysis of the previous runs (batch tests).
Those tests using `checkIterations` were not working because an
invariant was working: the first iterations number is 0. As we reuse
sbt for running several tests, this is no longer true, so this commit
makes sure that they are updated with the pertinent infrastructure to
compute the performed iterations from the latest known number of
iterations.
For that, we:
* Change the existing infrastructure to recycle as much code as
possible.
* Use `BatchScriptRunner` since `ScriptRunner` is too restrictive to
programmatically control the underlying sbt servers.
* Unify `TestRunner` to the more general way for both batch and
non-batch modes.
This covers the case described in #1361 plus an esoteric case too.
Parsers are initialized when sbt starts and text completions use the
knowledge at that time. If we happen to move a new file that should
influence the behaviour of the tab completion, that file will not be
picked up. Before, since we were throwing an error, the previous case
that would no produce any tab completion would also fail, though the
files are legitimately in the correct place.