Commit Graph

1234 Commits

Author SHA1 Message Date
Ethan Atkins f515aab8d7 Add scripted test for `~compile` in play 2019-08-29 09:38:11 -07:00
eugene yokota c38ce111fe
Merge pull request #4999 from eatkins/clean-directories
Restore old cleanFiles behavior
2019-08-28 20:42:23 -04:00
Ethan Atkins b3320ce1ba Restore old cleanFiles behavior
I inadvertently changed the semantics of clean so that cleanFiles would
only delete the file if it was a regular file. In older versions of sbt,
if a file in cleanFiles was a directory, it would be recursively
deleted.
2019-08-28 16:41:25 -07:00
Eugene Yokota 4086fc1213 Take dependencyOverrides into account
This tracks https://github.com/coursier/sbt-coursier/pull/106
Fixes https://github.com/sbt/sbt/issues/4895
2019-08-28 17:43:42 -04:00
Ethan Atkins 6ec9edb733 Abort early in watch multi commands
During refactoring of Continuous, I inadvertently changed the semantics
of `~` so that all multi commands were run regardless of whether or not
an earlier command had failed. I fixed the issue and added a regression
test.
2019-08-27 10:38:55 -07:00
eugene yokota 110f54a044
Merge pull request #4987 from eatkins/fix-cross-overcompilation
Store compile file stamps for each scala version
2019-08-27 08:39:37 -04:00
Ethan Atkins 6ba3afbef7 Fix settings in ScriptMain
It was reported in https://github.com/sbt/sbt/issues/4973 that the
scalaVersion setting was not being correctly set in a script running
with ScriptMain using 1.3.0-RC4. Using git bisect, I found that the
issue was introduced in
73cfd7c8bd.
That commit manipulates the classloaders passed in by the launcher, but
only for the xMain entry point. I found that the script ran correctly if
I updated the classloader for ScriptedMain as well.

After these changes, the example script in #4973 correctly prints 2.13.0
for the scala version with a locally published sbt.

Bonus: rename xMainImpl object xMain. It was private[sbt] anyway.
2019-08-26 21:15:43 -07:00
Ethan Atkins bd4d04d131 Store compile file stamps for each scala version
https://github.com/sbt/sbt/issues/4986 reported that +compile would
always recompile everything in the project even when the sources hadn't
changed. This was because the dependency classpath was changing between
calls to compile, which caused the external hooks cache introduced in
32a6d0d5d7 to invalidate the scala
library. To fix this, I cache the file stamps on a per scala version
basis. I added a scripted test that checks that there is no
recompilation in two consecutive calls to `+compile` in a multi scala
version build. It failed prior to these changes.
2019-08-26 14:47:57 -07:00
Ethan Atkins 5eab9df0df Fix clean performance
The clean task got a lot slower in 1.3.0
(https://github.com/sbt/sbt/issues/4972). The reason for this was that
sbt 1.3.0 generated many custom clean tasks for any tasks that returned
`File` or `Seq[File]`. Each of these tasks was tagged with
Tags.Clean which meant that only one of them could run at a time. As a
result, it took a long time to evaluate all of the custom tasks, even if
they were no-ops. In the akka project, a no-op clean was taking 35
seconds which is simply unacceptable. After this change, a no-op clean
takes less than a second in akka (a full clean only takes about 6
seconds after running test:compile)

To fix this, I stopped aggregating the clean task across configs and
projects. Because I removed the aggregation, I needed to manually
implement clean in the `Compile` and `Test` configurations to make
`Compile / clean` and `Test / compile` clean work correctly.
2019-08-22 13:01:56 -07:00
Eugene Yokota fcf7c5955e remove neo-sbt-scalafmt test
The test fails because the plugin is using reflection to access a private class, and we changed it - https://github.com/lucidsoftware/neo-sbt-scalafmt/issues/80
2019-08-19 03:37:33 -04:00
Eugene Yokota a22e4889f4 reproduce "Conflicting dependencies"
Ref #4720
2019-08-15 15:40:43 -04:00
Ethan Atkins 7c483909af Invalidate unmanagedFileStampCache in allOutputFiles
In the code formatting use case, the formatting task may modify the
source files in place. If the formatting task uses the nio
inputFileStamps, then it would fill the in-memory cache of source paths
to file stamps. This would cause compile to see the pre-formatted
stamps. To fix this, we can invalidate the file cache entries for the
outputs of a task. This will cause the side-effect of some extra io
because the hashes may be computed three times: once for the format
inputs, once for the format outputs and once for the compile inputs. I
think most users would understand that adding auto-formatting would
potentially slowdown compilation.

To really prove this out, I implemented a poor man's scalafmt plugin in
a scripted test. It is fully incremental. Even in the case when some
files cannot be formatted it will update all of the files that can be
formatted and not re-format them until they change.
2019-08-09 13:18:29 -07:00
Ethan Atkins 6700d5f77a Add nio path filter settings
It makes sense for the new glob/nio based apis that we provide first
class support for filtering the results. Because it isn't possible to
scope a task within a task within a task, i.e.
`compile / fileInputs / includePathFilter`, I had to add four new
filter settings of type `PathFilter`:

fileInputIncludeFilter :== AllPassFilter.toNio,
fileInputExcludeFilter :== DirectoryFilter.toNio || HiddenFileFilter,
fileOutputIncludeFilter :== AllPassFilter.toNio,
fileOutputExcludeFilter :== NothingFilter.toNio,

Before I was effectively hard-coding the filter: RegularFileFilter &&
!HiddenFileFilter in the inputFileStamps and allInputFiles tasks. These
remain the defaults, as seen in the fileInputExcludeFilter definition
above, but can be overridden by the user.

It makes sense to exclude directories and hidden files for the input
files, but it doesn't necessarily make sense to apply any output filters
by default. For symmetry, it makes sense to have them, but they are
unlikely to be used often.

Apart from adding and defining the default values for these keys, the
only other changes I had to make was to remove the hard-coded filters
from the allInputFiles and inputFileStamps tasks and also add the
filtering to the allOutputFiles task. Because we don't automatically
calculate the FileAttributes for the output files, I added logic for
bypassing the path filter application if the PathFilter is effectively
AllPass, which is the case for the default values because:
AllPassFilter.toNio == AllPass
NothingFilter.toNio == NoPass
AllPass && !NoPass == AllPass && AllPass == AllPass
2019-08-09 12:18:22 -07:00
Ethan Atkins 8ce2578060 Introduce FileChanges
Prior to this commit, change tracking in sbt 1.3.0 was done via the
changed(Input|Output)Files tasks which were tasks returning
Option[ChangedFiles]. The ChangedFiles case class was defined in io as

case class ChangedFiles(created: Seq[Path], deleted: Seq[Path], updated: Seq[Path])

When no changes were found, or if there were no previous stamps, the
changed(Input|Output)Files tasks returned None. This made it impossible
to tell whether nothing had changed or if it was the first time.
Moreover, the api was awkward as it required pattern matching or folding
the result into a default value.

To address these limitations, I introduce the FileChanges class. It can
be generated regardless of whether or not previous file stamps were
available. The changes contains all of the created, deleted, modified
and unmodified files so that the user can directly call these methods
without having to pattern match.
2019-08-09 12:18:22 -07:00
Ethan Atkins 8e9efbeaac Add extension methods for input and output files
It is tedious to write (foo / allInputFiles).value so I added simple
extension method macros that expand `foo.inputFiles` to
(foo / allInputFiles).value and `foo.outputFiles` to
`(foo / allOutputFiles).value`.
2019-08-09 12:18:22 -07:00
Ethan Atkins f126206231 Fix incremental task evaluation semantics
While writing documentation for the new file management/incremental
task evaluation features, I realized that incremental task evaluation
did not have the correct semantics. The problem was that calls to
`.previous` are not scoped within the current task. By this, I mean that
say there are tasks foo and bar and that the defintion of bar looks like

bar := {
    val current = foo.value
    foo.previous match {
        case Some(v) if v == current => // value hasn't changed
        case _ => process(current)
    }
}

The problem is that foo.previous is stored in
effectively (foo / streams).value.cacheDirectory / "previous". This
means that it is completely decoupled from foo. Now, suppose that the
user runs something like:
> set foo := 1
> bar // processes the value 1
> set foo := 2
> foo
> bar // does not process the new value 2 because foo was called, which updates the previous value

This is not an unrealistic scenario and is, in fact, common if the
incremental task evaluation is changed across multiple processing steps.
For example, in the make-clone scripted test, the linkLib task processes
the outputs of the compileLib task. If compileLib is invoked separately
from linkLib, then when we next call linkLib, it might not do anything
even if there was recompilation of objects because the objects hadn't
changed since the last time we called compileLib.

To fix this, I generalizedthe previous cache so that it can be keyed on
two tasks, one is the task whose value is being stored (foo in the
example above) and the other is the task in which the stored task value
is retrieved (bar in the example above). When the two tasks are the
same, the behavior is the same as before.

Currently the previous value for foo might be stored somewhere like:

base_directory/target/streams/_global/_global/foo/previous

Now, if foo is stored with respect to bar, it might be stored in

base_directory/target/streams/_global/_global/bar/previous-dependencies/_global/_gloal/foo/previous

By storing the files this way, it is easy to remove all of the previous
values for the dependencies of a task.

In addition to changing how the files are stored on disk, we have to store
the references in memory differently. A given task can now have multiple
previous references (if, say, two tasks bar and baz both depend on the
previous value). When we complete the results, we first have to collect
all of the successful tasks. Then for each successful task, we find all
of its references. For each of the references, we only complete the
value if the scope in which the task value is used is successful.

In the actual implemenation in Previous.scala, there are a number places
where we have to cast to ScopedKey[Task[Any]]. This is due to
limitations of ScopedKey and Task being type invariant. These casts are
all safe because we never try to get the value of anything, we only use
the portion of the apis of these types that are independent of the value
type. Structural typing where ScopedKey[Task[_]] gets inferred to
ScopedKey[Task[x]] forSome x is a big part of why we have problems with
type inference.
2019-08-09 12:18:22 -07:00
Ethan Atkins fb15065438 Move implicit FileStamp JsonFormats into object
I realized it was probably not ideal to have these implicit JsonFormats
defined directly in the FileStamp object because they might
inadvertently be brought into scope with a wildcard import.
2019-08-09 12:18:22 -07:00
Ethan Atkins 2990e08c5d Set make-clone c compile options for all platforms
I realized that it didn't make sense to specify these just for linux
even though they work fine with the version of gcc that runs on my mac.
I also ran scalafmt on this file.
2019-08-09 12:18:22 -07:00
eugene yokota 6865f32eae
Merge pull request #4934 from eed3si9n/wip/publishTo
Revert "don't require publishTo specified if publishArtifact is `false`"
2019-08-09 09:24:31 -04:00
Ethan Atkins d86afb5745 Revert "Merge pull request #4930 from eatkins/2.12.9"
This reverts commit 053b72005d, reversing
changes made to d6b8e0388c.
2019-08-08 11:09:29 -07:00
Ethan Atkins f1538f76ce Revert "Merge pull request #4933 from eatkins/paradise"
This reverts commit 294a1c181e, reversing
changes made to 8365e4b189.
2019-08-08 11:08:06 -07:00
Eugene Yokota ec6cf15f12 Revert "don't require publishTo specified if publishArtifact is `false`"
This reverts commit 4668faff7c.
Ref https://github.com/sbt/sbt/pull/3760
Ref https://github.com/sbt/sbt/pull/4931
2019-08-08 00:36:36 -04:00
Ethan Atkins 0fc43cc95b Bump source-dependencies/macro-annotation to 2.12.9 2019-08-06 12:47:08 -07:00
Ethan Atkins 86cb74bb96 Downgrade to 2.12.8 for project/semanticdb scripted test
Semanticdb hasn't been published for 2.12.9 yet.
2019-08-05 14:25:59 -07:00
Ethan Atkins 416cc653b6 Downgrade to 2.12.8 for source-dependencies/macro-annotation
The macro paradise library isn't published for 2.12.9 (yet).
2019-08-05 14:25:59 -07:00
Ethan Atkins 2a99f86b87 Fix dependency-management/sources for 2.12.9
An additional jar is required.
2019-08-05 14:25:54 -07:00
Ethan Atkins 9e165b01d9 Use https in scala url 2019-08-05 14:00:26 -07:00
Ethan Atkins c34de173ea Upgrade classloader-cache/resources libarary to 2.12.9 2019-08-05 13:59:17 -07:00
Ethan Atkins b26ce819ca Bump default scala version to 2.12.9
I automatically generated with:

git grep "2.12.8" | \
  cut -d ':' -f1 | uniq | xargs perl -p -i -e "s/2.12.8/2.12.9/"
2019-08-05 13:12:28 -07:00
Eugene Yokota 54b6e1fc08 Remove ivy-settings-b scripted test 2019-08-05 00:24:44 -04:00
eugene yokota 96d6e0d52a
Merge pull request #4899 from eatkins/watch-symlink-scripted
Add scripted test for symlink source monitoring
2019-07-30 17:39:27 -04:00
Ethan Atkins 4061dabf4d Override zinc compile analysis for source changes
Zinc records all of the compile source file hashes when compilation
completes. This is problematic because its possible that a source file
was changed during compilation. From the user perspective, this may mean
that their source change will not be recompiled even if a build is
triggered by the change.

To overcome this, I add logic in the sbt provided external hooks to
override the zinc analysis stamps. This is done by writing the source
file stamps to the previous cache after compilation completes. This
allows us to see the source differences from sbt's perspective, rather
than zinc's perspective. We then merge the combined differences in the
actual implementation of ExternalHooks. In some cases this may result in
over-compilation but generally over-compilation is preferred to under
compilation. Most of the time, the results should be the same.

The scripted test that I added modifies a file during compilation by
invoking a macro. It then effectively asserts that the file is
recompiled during the next test run by validating the compilation result
in the test. The test fails on the latest develop hash.
2019-07-29 20:13:41 -07:00
Ethan Atkins bbd88e04dc Add scripted test for symlink source monitoring
The swoval library automatically watches the _target_ of symlinks. I had
been meaning to add a scripted test to ensure that in sbt continuous
builds detect changes to the target of symlinks. The naive approach of
just watching all of the files in the source directory doesn't work
because the native watch process will just watch the symlink node itself
and not detect updates to its target. This test would have thus failed
with 1.2.8.

Watching symlinked files doesn't work at the moment on windows, but does
work on mac and linux. Eventually I'd like there to be feature parity,
but, for now, we'll just skip the file target test on windows. At least
this test makes it explicit what does and doesn't work on each platform.
2019-07-29 14:26:28 -07:00
Ethan Atkins f7f6c3edfe Use '_' instead of '$' in path names
The use of '$' in the path names for streams is a pain because, since
'$' is a special character in the shell, it makes it impossible to
directly copy and paste the paths. If we make this change, some builds
will be left with vestigial directories with $global and $build in them
until they run clean. It also would break any scripts that manually
delete these paths. That doesn't seem like a common use case, but it's
worth mentioning.
2019-07-25 14:07:44 -07:00
Eugene Yokota 9512a60fa6 Fix java.util.zip.ZipException: duplicate entry
Fixes #4889

#4329 switched from using Map to Seq during packaging. That allowed multiple files to be included with different paths, but it also started admitting duplicate files causing ZipException.
2019-07-23 01:28:32 -04:00
Eugene Yokota ef05e07cc5 Fixes credential strictness
Fixes #4882

In #4855 I inadvertently introduced `credential` strictness. This makes relaxes it again by ignoring if the credential file doesn't exist.
2019-07-18 18:30:30 -04:00
Ethan Atkins 36f37d2fe3 Set linux compile options for make-clone
This scripted tests failed on the linux travis ci build with an
error around relocation. It said to use -fPIC in the compilation so
that's what I'm doing. It also said I needed to set the -std=c99 flag.
2019-07-16 22:18:45 -07:00
Ethan Atkins 69ed60653c Add scripted test for excludeFilter
It was reported in #4868 that exclueFilters didn't work correctly if
there was an || in the filter. This was an upstream issue in io, but
this commit adds a scripted test in sbt.
2019-07-16 20:35:44 -07:00
Ethan Atkins 6c4e23f77c Only persist file stamps in turbo mode
The use of the persistent file stamp cache between watch runs didn't
seem to cause any issues, but there was some chance for inconsistency
between the file stamp cache and the file system so it makes sense to
put it behind the turbo flag.

After changing the default, the watch/on-change scripted test started
failing. It turns out that the reason is that the file stamp cache
managed by the watch process was not pre-filled by task evaluation. For
this reason, the first time a source file was modified, it was treated
as a creation regardless of whether or not it actually was.

To fix this, I add logic to pre-fill the watch file stamp cache if we
are _not_ persisting the file stamps between runs.

I ran a before and after with the scala build performance benchmark tool
and setting the watchPersistFileStamps key to true reduced the median
run time by about 200ms in the non-turbo case.
2019-07-15 17:59:14 -07:00
Ethan Atkins a071ce8224 Handle multi-command with reload correctly
@olegych reported that sbt would silently swallow the 'compile' command
in the multi-command, 'run;compile;reload'. I tracked this down to the
build source check. When the build has
Global / onChangedBuildSource := ReloadOnSourceChanges, the check build
sources command return a new state with "reload" prefixed. To actually
perform the reload, I returned this modified state with the prefixed
reload command.

There were two problems with this:
1) In the auto-reload case, the current command was not run after the
   reload
2) If the multi-command contained reload, the auto-reload check would
   have a false positive which triggered the bug in (1)

To fix this, I clear out the remaining commands before I run the check
command. That way, we know that if the remaining commands has a reload,
then it is an auto-reload. We then prefix the state with both the reload
and the current command.

I updated the scripted test for auto-reload to handle multi commands
containing reload.
2019-07-13 11:18:56 -07:00
Eugene Yokota 00f7d1fab5 scope the reference of useSuperShell to ThisBuild
Fixes #4800
2019-07-12 11:34:39 -04:00
eugene yokota 8413e259e1
Merge pull request #4838 from eatkins/multi-cleanup
Multi cleanup
2019-07-08 07:06:31 -04:00
Eugene Yokota 83d35c8ed0 lm-coursier-shaded 2.0.0-RC2-1
Fixes #4823
2019-07-04 23:13:46 +09:00
Ethan Atkins 60b1ac7ac4 Improve multi parser performance
The multi parser had very poor performance if there were many commands.
Evaluating the expansion of something like "compile;" * 30 could cause
sbt to hang indefinitely. I believe this was due to excessive
backtracking due to the optional `(parser <~ semi.?).?` part of the
parser in the non-leading semicolon case.

I also reworked the implementation so that the multi command now has a
name. This allows us to partition the commands into multi and non-multi
commands more easily in State while still having multi in the command
list. With this change, builds and plugins can exclude the multi parser
if they wish.

Using the partitioned parsers, I removed the high/priority low priority
distinction. Instead, I made it so that the multi command will actually
check if the first command is a named command, like '~'. If it is, it
will pass the raw command argument with the named command stripped out
into the parser for the named command. If that is parseable, then we
directly apply the effect. Otherwise we prefix each multi command to the
state.
2019-06-25 13:45:09 -07:00
Eugene Yokota 29d3894b27 add back typesafe-ivy-releases resolver
Fixes #4698
Fixes #4827
2019-06-22 09:45:15 -04:00
Ethan Atkins 4c814752fb Support braces in multi command parser
We run into issues if we naively split the command input on ';' and
treat each part as a separate command unless the ';' is inside of a
string because it is also valid to have ';'s inside of braced
expressions, e.g. `set foo := { val x = 1; x + 1 }`. There was no parser
for expressions enclosed in braces. I add one that should parse any
expression wrapped in braces so long as each opening brace is matched by a
closing brace. The parser returns the original expression. This allows
the multi parser to ignore ';' inside of '{...}'.

I had to rework the scripted tests to individually run 'reload' and
'setUpScripted' because the new parser rejects setUpScripted because it
isn't a valid command until reload has run.
2019-06-19 16:12:45 -07:00
Ethan Atkins ccfc3d7bc7 Validate commands in multiparser
It was reported in https://github.com/sbt/sbt/issues/4808 that compared
to 1.2.8, sbt 1.3.0-RC2 will truncate the command args of an input task
that contains semicolons. This is actually intentional, but not
completely robust. For sbt >= 1.3.0, we are making ';' syntactically
meaningful. This means that it always represents a command separator
_unless_ it is inside of a quoted string. To enforce this, the multi parser
will effectively split the input on ';', it will then validate that each
command that it extracted is valid. If not, it throws an exception. If
the input is not a multi command, then parsing fails with a normal
failure.

I removed the multi command from the state's defined commands and reworked
State.combinedParser to explicitly first try multi parsing and fall back
to the regular combined parser if it is a regular command. If the multi
parser throws an uncaught exception, parsing fails even if the regular
parser could have successfully parsed the command. The reason is so that
we do not ever allow the user to evaluate, say 'run a;b'. Otherwise the
behavior would be inconsitent when the user runs 'compile; run a;b'
2019-06-19 16:12:45 -07:00
Ethan Atkins 2fe26403e7 Add test for using switch version in multi command
I noticed that in 1.3.0-RC2, the following commands worked:
  ++2.11.12 ;test
  ;++2.11.12;test
but
  ++2.11.12; test
did not. This issue is fixed in the next commit.
2019-06-19 16:12:45 -07:00
Eugene Yokota 7b10b372f8 Fix updateClassifiers
Fixes #4816

Copied sbt-lm-coursier hacks from 9173406bb3/modules/sbt-lm-coursier/src/main/scala/sbt/hack/Foo.scala.
2019-06-19 12:20:26 -04:00
Eugene Yokota 6878fb6cdb turbo mode
This creates a performance mode that enables experimental or advanced features that might require some debugging by the build user when it doesn't work.

Initially we are putting the layered ClassLoader (`ClassLoaderLayeringStrategy.AllLibraryJars`) behind this flag.
2019-06-08 21:37:50 +02:00