Skip to content

Deprecates Extracted#append for appendWithSession#3865

Merged
dwijnand merged 1 commit intosbt:1.1.xfrom
dwijnand:fix-Extracted.append
Jan 17, 2018
Merged

Deprecates Extracted#append for appendWithSession#3865
dwijnand merged 1 commit intosbt:1.1.xfrom
dwijnand:fix-Extracted.append

Conversation

@dwijnand
Copy link
Member

@dwijnand dwijnand commented Jan 10, 2018

Adds Extracted#appendWithSession as a better alternative to Extracted#append because it preserves session settings.

  1. A week ago @2m contacted me because he was using append in conjunction with + and finding that append discarded the scalaVersion that + set in the session.
  2. The next day @jastice, in his unexpected initialization order of settings overridden in source dependencies #3850 issue, mentioned that append was discarding the settings set with the apply command.
  3. Yesterday @SethTisue created a PR (upgrade build from sbt 0.13 -> sbt 1 [ci: last-only] scala/scala#6256) to migrate the Scala build from sbt 0.13 to sbt 1 and asked how to migrate the workaround code that avoided Extracted#append and used Load, which as of sbt 1 is now internal API.

@dwijnand
Copy link
Member Author

The test ParseKey failed with:

[info] ! Key parser test.An explicitly specified axis is always parsed to that explicit value: Falsified after 51 passed tests.
[info] > Labels of failing property: 
[info] Key string: 'q / g'
[info] Structure: Env:
[info]     Tasks:
[info]     f (delegates: qq)
[info]     q (delegates: qq)
[info]     g (delegates: qq)
[info]     ka (delegates: qq)
[info]     someNfu (delegates: qq)
[info]     qq (delegates: )
[info] Build mfh:nam#cwhvfd :
[info]     Project q
[info]       Delegates:
[info]         ProjectRef(mfh:nam#cwhvfd,jqqdsp)
[info]       Configurations:
[info]         a
[info]         wz
[info]     Project jqqdsp
[info]       Delegates:
[info]         
[info]       Configurations:
[info]         a
[info]         wz
[info] current: ProjectRef(mfh:nam#cwhvfd,q)
[info] Settings:
[info] 	ProjectRef(uri("mfh:nam#cwhvfd"), "jqqdsp") / A / <key>
[info] 	   qq,ka,f,q,g,someNfu
[info] 
[info] 	ProjectRef(uri("mfh:nam#cwhvfd"), "jqqdsp") / A / qq / <key>
[info] 	   qq,ka,f,q,g,someNfu
[info] 
[info] 	ProjectRef(uri("mfh:nam#cwhvfd"), "jqqdsp") / A / someNfu / <key>
[info] 	   qq,ka,f,q,g,someNfu
[info] 
[info] 	ProjectRef(uri("mfh:nam#cwhvfd"), "jqqdsp") / Wz / <key>
[info] 	   qq,ka,f,q,g,someNfu
[info] 
[info] 	ProjectRef(uri("mfh:nam#cwhvfd"), "jqqdsp") / Wz / f / <key>
[info] 	   qq,ka,f,q,g,someNfu
[info] 
[info] 	ProjectRef(uri("mfh:nam#cwhvfd"), "jqqdsp") / Wz / g / <key>
[info] 	   qq,ka,f,q,g,someNfu
[info] 
[info] 	ProjectRef(uri("mfh:nam#cwhvfd"), "jqqdsp") / Wz / ka / <key>
[info] 	   qq,ka,f,q,g,someNfu
[info] 
[info] 	ProjectRef(uri("mfh:nam#cwhvfd"), "jqqdsp") / Wz / qq / <key>
[info] 	   qq,ka,f,q,g,someNfu
[info] 
[info] 	ProjectRef(uri("mfh:nam#cwhvfd"), "jqqdsp") / Wz / someNfu / <key>
[info] 	   qq,ka,f,q,g,someNfu
[info] 
[info] 	ProjectRef(uri("mfh:nam#cwhvfd"), "jqqdsp") / f / <key>
[info] 	   qq,ka,f,q,g,someNfu
[info] 
[info] 	ProjectRef(uri("mfh:nam#cwhvfd"), "jqqdsp") / qq / <key>
[info] 	   qq,ka,f,q,g,someNfu
[info] 
[info] 	ProjectRef(uri("mfh:nam#cwhvfd"), "q") / ka / <key>
[info] 	   qq,ka,f,q,g,someNfu
[info] 
[info] 	ProjectRef(uri("mfh:nam#cwhvfd"), "q") / someNfu / <key>
[info] 	   qq,ka,f,q,g,someNfu
[info] All keys:
[info] 	qq, ka, f, q, g, someNfu
[info] Expected: ProjectRef(uri("mfh:nam#cwhvfd"), "q") / q / g
[info] Scope(Select(ProjectRef(mfh:nam#cwhvfd,q)), Zero, Zero, Zero) == Scope(Select(ProjectRef(mfh:nam#cwhvfd,q)), Zero, Select(q), Zero): false
[info] ScopedKey(Scope(Select(ProjectRef(mfh:nam#cwhvfd,q)), Zero, Zero, Zero),g).key == ScopedKey(Scope(Select(ProjectRef(mfh:nam#cwhvfd,q)), Zero, Select(q), Zero),g).key: true
[info] Parsed: Right(ProjectRef(uri("mfh:nam#cwhvfd"), "q") / g)
[info] Mask: ScopeMask(false,false,true,false)
[info] Key: {mfh:nam#cwhvfd} / Wz / q / g
[info] > ARG_0: sbt.ParseKey$StructureKeyMask@626bae4c

I wonder if this is spurious? I'll rerun Travis CI now that I've copy/pasted the failing output.

val appendSettings =
Load.transformSettings(Load.projectScope(currentRef), currentRef.build, rootProject, settings)
val newStructure = Load.reapply(session.original ++ appendSettings, structure)
val newStructure = Load.reapply(session.mergeSettings ++ appendSettings, structure)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead changing append's behaviour, add another method (or 2) which has well defined semantics.

@dwijnand dwijnand force-pushed the fix-Extracted.append branch from f808746 to 1f8e286 Compare January 10, 2018 17:01
@dwijnand dwijnand changed the title Fixes Extracted#append to preserve session settings Add Extracted#appendWithSession, better than append Jan 10, 2018
@dwijnand dwijnand force-pushed the fix-Extracted.append branch from 1f8e286 to f1a6b77 Compare January 10, 2018 17:54
@dwijnand
Copy link
Member Author

@eed3si9n WDYT now?

display.show(ScopedKey(scope, key)) + " is undefined.")

def append(settings: Seq[Setting[_]], state: State): State = {
/** Appends the given settings to the original build state settings. */
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest adding information about the gotcha of discarding session settings, perhaps marking this as deprecated

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think being more explicit about session settings makes sense.

But if we're assuming that discarding them is intended behaviour and a valid use case, we can't mark this as deprecated.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It wasn't exactly intended behavior, at least originally. The method append, with the current semantics, should have been deprecated long ago. As a reference:

On 06/03/13 02:27, Mark Harrah wrote:

On 06/03/13 01:34, Antonio Cunei wrote:

However, I guess Extracted.append() could mirror more closely the
operation of the set command, otherwise the result may be surprising to
users. (Also, an equivalent to "set every" might be handy). Is this
analysis correct, or is there a different recommended way to patch the
session?

Your understanding is correct. There are different semantics that are useful at different times. I'm not real sure if it is the right thing for commands to effectively do the same as set. They don't tend to be saveable since there isn't a corresponding source. One way forward is to deprecate append and replace it with two (or more) methods with documented semantics.

Copy link
Member Author

@dwijnand dwijnand Jan 12, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should deprecate in favour of appendWithSession and appendDiscardingSession?

[edit: or appendWithoutSession]

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not that historical text by Mark should be taken as sacred, if I am reading this right he's saying that while he was unsure if it's the right thing, he was discarding intentionally and thus suggesting we have "two (or more) methods".

Here's my suggestion:

  1. Add appendWithoutSession(settings: Seq[Setting[_]], state: State) and appendWithSession(settings: Seq[Setting[_]], state: State).
  2. Deprecate append(...) explaining that the append discards session, and that the user is encourage to move to either appendWithSession(...) or appendWithoutSession(...).

I am also tempted to add an alias called set(...) for appendWithSession(...) as it would have the same semantics as the set command, but I'm afraid append vs set would be too subtle.

@dwijnand dwijnand force-pushed the fix-Extracted.append branch from f1a6b77 to 77e659f Compare January 12, 2018 12:12
Copy link
Member

@eed3si9n eed3si9n left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pending the discussion #3865 (comment)

@dwijnand dwijnand force-pushed the fix-Extracted.append branch from 77e659f to 168f2b9 Compare January 15, 2018 14:48
@dwijnand dwijnand force-pushed the fix-Extracted.append branch from 168f2b9 to 0885233 Compare January 15, 2018 14:49
@dwijnand dwijnand changed the title Add Extracted#appendWithSession, better than append Deprecates Extracted#append for appendWithSession Jan 15, 2018
@dwijnand
Copy link
Member Author

Should this be merged into 1.1.x or 1.x. Hmm. (My eternal bug fix vs improvement debate..)

@dwijnand dwijnand dismissed eed3si9n’s stale review January 16, 2018 06:51

Suggested implemented

@dwijnand dwijnand requested a review from eed3si9n January 16, 2018 06:51
@eed3si9n
Copy link
Member

For sbt, the point of a hotfix release is to improve the quality (often by fixing bugs) without introducing new breakages brought in by new features. Since introducing new method should not break existing code paths, this should a safe patch.
I agree that it's a borderline feature, but my vote is to include this into 1.1.1 for release within a week.

@SethTisue
Copy link
Member

SethTisue commented Jan 16, 2018

certainly seems appropriate for 1.1.1 to me (and besides, it would be sad if the Scala build had to wait for 1.2)

@dwijnand dwijnand merged commit 5333d0d into sbt:1.1.x Jan 17, 2018
@dwijnand dwijnand deleted the fix-Extracted.append branch January 17, 2018 10:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants