Conversation
* parametrized clieanFilesTask by the files it should delete * added a cleanFiles override for cleaning only classDirectory
jvican
left a comment
There was a problem hiding this comment.
LGTM! Great work @laughedelic.
| lazy val outputConfigPaths = Seq( | ||
| classDirectory := crossTarget.value / (prefix(configuration.value.name) + "classes"), | ||
| target in doc := crossTarget.value / (prefix(configuration.value.name) + "api") | ||
| ) ++ inTask(compile)( |
There was a problem hiding this comment.
To reviewers: this is scoped in the default configs Compile, Test and Runtime.
There was a problem hiding this comment.
I should also add cleanKeepFiles here and fix dependency on it in cleanFilesTask, because otherwise user cannot override it in this particular scope.
| # it should clean only class files | ||
| $ absent target/scala-2.12/classes/A.class | ||
|
|
||
| > test:compile::clean |
|
|
||
| lazy val projectTasks: Seq[Setting[_]] = Seq( | ||
| cleanFiles := cleanFilesTask.value, | ||
| cleanFiles := Def.taskDyn { cleanFilesTask(managedDirectory.value, target.value) }.value, |
There was a problem hiding this comment.
This is the same as it was before. But I'm not sure if I should add managedDirectory to cleanFiles in the compile task above.
| lazy val outputConfigPaths = Seq( | ||
| classDirectory := crossTarget.value / (prefix(configuration.value.name) + "classes"), | ||
| target in doc := crossTarget.value / (prefix(configuration.value.name) + "api") | ||
| ) ++ inTask(compile)( |
There was a problem hiding this comment.
No if you look at #3542 it talks about creating a compile:clean, not compile::clean, i.e a clean scoped to the Compile configuration, not to the compile task.
There was a problem hiding this comment.
I changed that in the ticket and advised Alexey to do it this way. I think that scoping in the task makes more sense because you may be interested in deleting test class files as well.
There was a problem hiding this comment.
I think that scoping in the task makes more sense because you may be interested in deleting test class files as well.
I agree, and test:clean should do that.
There was a problem hiding this comment.
I'm fine with either way. I think scoping by task makes sense if there will be more variants of clean. But if it addresses only compilation task, I agree with @dwijnand that it's better to scope it by configuration. Because compile::clean gives a false impression that it should magically work with other tasks (cleaning their specific artifacts).
There was a problem hiding this comment.
Because
compile::cleangives a false impression that it should magically work with other tasks (cleaning their specific artifacts).
Exactly.
There was a problem hiding this comment.
Hmm, test:clean is not the same to test:compile::clean. The latter is explicit and portrays better the original intent: only deleting class files. test:clean already has a meaning now and is not clear about what it should clean, so I strongly favor test:compile::clean.
Because compile::clean gives a false impression that it should magically work with other tasks (cleaning their specific artifacts).
Well, this already happens with test:clean. You would expect sbt to only delete things generated by the Test configuration, but it will delete things generated by Compile and Test.
There was a problem hiding this comment.
test:cleanalready works now and is not clear about what it should clean
Well, this already happens with
test:clean. You would expect sbt to only delete things generated by theTestconfiguration, but it will delete things generated byCompileandTest.
I'm not sure what you mean by "works" then. Currently test:clean just delegates to clean. Thus #3542.
There is actually a sys property to disable that delegation and I was playing with it the other day:
It's interesting because it mean that test:clean wouldn't run because it wouldn't delegate to clean, but test would continue to delegate to test:test and therefore run. I want to revisit it for sbt 2.
There was a problem hiding this comment.
I'm not sure what you mean by "works" then. Currently test:clean just delegates to clean. Thus #3542.
Yup, I agree. This is why I said:
this already happens with test:clean. You would expect sbt to only delete things generated by the Test configuration, but it will delete things generated by Compile and Test.
That sys property is interesting, didn't know it.
I'm trying to think how we solve this puzzle to get the intended behaviour in test:compile::clean.
There was a problem hiding this comment.
It turns out we've been missing that the actual implementation does only delete test class files, so we're good. Turning the test into the following makes the test pass:
> test:compile
$ exists target/scala-2.12/resolution-cache/
$ exists target/streams/
$ exists target/scala-2.12/classes/A.class
$ exists target/scala-2.12/test-classes/B.class
> test:compile::clean
$ exists target/scala-2.12/resolution-cache/
$ exists target/streams/
# it should clean only test class files
$ exists target/scala-2.12/classes/A.class
$ absent target/scala-2.12/test-classes/B.class
> compile:compile::clean
$ exists target/scala-2.12/resolution-cache/
$ exists target/streams/
# it should clean only compile class files
$ absent target/scala-2.12/classes/A.class
$ absent target/scala-2.12/test-classes/B.class
There was a problem hiding this comment.
There is actually a sys property to disable that delegation and I was playing with it the other day
Wow! I just told @jvican yesterday that delegation is confusing and I'd like sbt to fail when I mix up scopes and get a delegated value without realising it.
It turns out we've been missing that the actual implementation does only delete test class files, so we're good.
👍 done in f2aab78
| $ exists target/scala-2.12/resolution-cache/ | ||
| $ exists target/streams/ | ||
| # it should clean both compile and test classes | ||
| $ absent target/scala-2.12/classes/A.class |
There was a problem hiding this comment.
I have 2 concerns with this test: (1) I think it's over-specifying - it shouldn't make assertions about whether or not there is a streams directory, etc, and (2) I also think it's wrong - cleaning test classes shouldn't clean compile classes too.
There was a problem hiding this comment.
I agree. Ideally, only tests' class files should be removed.
Can you elaborate how you would implement this so that cleaning test classes shouldn't clean compile classes? I don't think there's a way to avoid that given how sbt deals with configuration dependencies.
There was a problem hiding this comment.
I don't know, I would have to experiment.
There was a problem hiding this comment.
it shouldn't make assertions about whether or not there is a streams directory, etc
@dwijnand OK. What about resolution_cache? I just want to check that whatever else is generated by sbt is kept.
There was a problem hiding this comment.
Same with resolution_cache. I agree with the intent. My idea was something along the lines of:
test:compile
# sanity check
exists classes
exists test-classes
compile:clean
absent classes
exists test-classes
test:compile
test:clean
exists classes
absent test-classes
There was a problem hiding this comment.
OK. How about creating a file in target/ and checking that it's not deleted? (because normal clean would delete it).
Also I have to check for existence of specific class files, because the root class folders are preserved.
There was a problem hiding this comment.
OK. How about creating a file in
target/and checking that it's not deleted? (because normalcleanwould delete it).
Sounds good.
Also I have to check for existence of specific class files, because the root class folders are preserved.
Yep - I was just using short-hand.
To check that test:compile::clean deletes only test-generated classes
| } | ||
|
|
||
| /** Implements `cleanFiles` task. */ | ||
| def cleanFilesTask: Initialize[Task[Vector[File]]] = |
There was a problem hiding this comment.
Can't get rid of this, for binary compatibility (MiMa-enforced) reasons.
|
I'd hold fire on any additional feature for the moment (obviously hold onto those SHAs!): this is still not implemented as |
|
I'm against that. I've already explained why in this PR several times. Can you elaborate on why only class files should be cleaned by configurations? |
|
I didn't have any strong opinion about this in the beginning, but over the couple of days at Lambda World I talked with @jvican and he basically opened my eyes on some basic things about scoping in sbt that I didn't understand (or understood wrong) before. I think that this should be scoped by task, because it makes sense conceptually: you clean only the products of this task (in whatever configuration scope). And the source/resource-generation tasks mentioned above are another example where Another thing is the concern from #3678 (comment):
but I realised that this is something general about sbt design: because of the scope delegation user should just never have such expectation and always inspect keys he uses to see if they are actually defined in the given scope or delegated to some other. |
|
|
|
I agree it's not perfect, but compilation could happen as part of |
|
See also @retronym's super simple |
Wait, even if compilation happens because the user does Maybe someone can explain to me what's the value of having |
For me it comes down to usability and symmetry. Configuration scoping, in general I think is easier to understand for users. If you want to add scalacOptions in Compile configuration we do: Same goes for lots of other settings related to compilation. None of them are scoped to If you want to compile or clean things in |
|
@eed3si9n But note that your proposal is not at odds with mine, we can still scope it in the compile task, and then delegate to it from the configuration scope. The idea is that the configuration scope, in the future, removes all products produced by other tasks scoped in |
|
Closing this in favor of 172c8e9. |
Fixes #3542. I started it at the Lambda World Spree with great help from @jvican.
This is a simple ah-hoc solution, it could be improved in many ways. The main change here is that
compile:compile::cleancleans up only things incompile:classDirectorytest:compile::cleancleans up only things intest:classDirectoryAlso I'm not sure how it should handle generated sources/resources.