Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add --cabal-install #2995

Merged
merged 1 commit into from
Mar 20, 2017
Merged

Add --cabal-install #2995

merged 1 commit into from
Mar 20, 2017

Conversation

decentral1se
Copy link
Member

  • Any changes that could be relevant to users have been recorded in the ChangeLog.md
  • The documentation has been updated, if necessary.

Manually tested.

Based on #2386 (comment). Thanks @sjakobi for the pointers!

@@ -140,6 +140,8 @@ data SetupOpts = SetupOpts
, soptsUpgradeCabal :: !Bool
-- ^ Upgrade the global Cabal library in the database to the newest
-- version. Only works reliably with a stack-managed installation.
, soptsInstallCabal :: !(Maybe Version)
-- ^ Install a specific version of Cabal.
Copy link
Member

Choose a reason for hiding this comment

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

Can you fuse the soptsUpgradeCabal and soptsInstallCabal fields into one? This should make it impossible to have nonsensical states where soptsUpgradeCabal == True and soptsInstallCabal == Just <x>.

Maybe it would even be good to avoid the additional --install-cabal flag and only add an optional argument to --upgrade-cabal?! That would help combating CLI inflation :). Not sure if it's possible with optparse-applicative though…

Copy link
Member Author

Choose a reason for hiding this comment

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

This sounds like a good idea. I haven't seen an 'optional argument' but will have a look and see what is possible.

Copy link
Member Author

@decentral1se decentral1se Feb 12, 2017

Choose a reason for hiding this comment

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

Oh, I see that options with optional arguments are not supported but there is a hint to try something else. I think it implies having a default though ... which won't work.

Copy link
Member

Choose a reason for hiding this comment

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

Fusing the two fields and parsing the two options as alternatives would still make sense IMO. As a result the usage info should look roughly like this:

stack setup … [--upgrade-cabal | --install-cabal VERSION] …

The combined field should have a type like Maybe UpgradeTo with

data UpgradeTo = Latest | Specific Version

or so.

The default value (which applies when neither option is used) is Nothing.

Copy link
Member

Choose a reason for hiding this comment

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

BTW, as an example stack clean uses the Alternative instance of the option parser:

Usage: stack clean ([PACKAGE] | [--full]) [--help]

Copy link
Member Author

Choose a reason for hiding this comment

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

Oh! That was really helpful, thanks for even more pointers :)

@sjakobi
Copy link
Member

sjakobi commented Feb 11, 2017

I haven't done a thorough review yet, only added an inline comment on the design so far.

Could you in any case please fix your commit description to use the correct flag name? Cheers! :)

@decentral1se
Copy link
Member Author

decentral1se commented Feb 11, 2017

the correct flag name?

Oh yes, fixed that one 😄

@decentral1se
Copy link
Member Author

I've done another pass on this and reduced the diff quite a bit. It should be much easier to review. If there are any other ideas on the merge of --upgrade-cabal/--install-cabal, I'm all ears (see comments above).

@decentral1se
Copy link
Member Author

Latest stab at it is c0942c6.

Copy link
Member

@sjakobi sjakobi left a comment

Choose a reason for hiding this comment

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

Looks pretty good already but I had a few comments anyway.

$logWarn "This may fail, caveat emptor!"
upgradeCabal menv wc
upgradeCabal menv wc (fromJust cabalVersion)
Copy link
Member

Choose a reason for hiding this comment

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

It would be nicer to use forM_ instead of when isJust … and fromJust.

Copy link
Member Author

@decentral1se decentral1se Feb 19, 2017

Choose a reason for hiding this comment

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

Not sure how to get the when isJust out of it? Please see 734dae4.

[] -> error "No Cabal library found in index, cannot upgrade"
[PackageIdentifier name' version]
| name == name' -> return version
[PackageIdentifier name' version] | name == name' -> return version
Copy link
Member

Choose a reason for hiding this comment

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

This block seems unnecessarily monadic, could be pure.

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 don't know what this means 😄

Copy link
Member

Choose a reason for hiding this comment

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

The only monadic bit about this case expression is the returns – this should be a let-expression instead of using <-.

, case cabalVersion of
Specific _ -> " (specified)"
Latest -> " (latest)"
, ". No work to be done."
Copy link
Member

Choose a reason for hiding this comment

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

The string that is being formed here doesn't look right. Anyway, I think we should support installing an older version here. Not sure if that requires adding logic to unregister or hide the old version.

Copy link
Member Author

Choose a reason for hiding this comment

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

This formatting corresponds to stopping the same version being installed. If you want to get an old version, you just fire off --install-cabal FOO instead of --upgrade-cabal. Good question regarding the unregister/hide stuff. Will investigate.

Copy link
Member Author

Choose a reason for hiding this comment

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

Examples are:

λ :main ["setup", "--upgrade-cabal"]
Currently installed Cabal is 1.24.2.0 (latest). No work to be done.

And:

λ :main ["setup", "--install-cabal", "1.24.2.0"]
Currently installed Cabal is 1.24.2.0 (specified). No work to be done.

Copy link
Member

Choose a reason for hiding this comment

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

Ok, I think I misread the diff a bit. Still, even when version < installed, we want to setup that old version of Cabal.

-- Nothing below: use the newest .cabal file revision
m <- unpackPackageIdents menv tmpdir Nothing (Map.singleton ident Nothing)

compilerPath <- join $ findExecutable menv (compilerExeName wc)
newestDir <- parseRelDir $ versionString newest
newestDir <- parseRelDir $ versionString version
Copy link
Member

Choose a reason for hiding this comment

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

For consistency, that should probably be "versionDir".

Copy link
Member Author

Choose a reason for hiding this comment

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

Fixed 👍

@@ -64,6 +65,9 @@ instance Exception VersionParseFail
instance Show VersionParseFail where
show (VersionParseFail bs) = "Invalid version: " ++ show bs

-- | A package version or the latest.
data UpgradeTo = Specific Version | Latest deriving (Show)

Copy link
Member

Choose a reason for hiding this comment

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

The description is way more general than the name of the type. Can you come up with a more general name maybe?

Copy link
Member Author

@decentral1se decentral1se Feb 19, 2017

Choose a reason for hiding this comment

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

Hmmm ... tried the description again. I like the name, it was your recommendation :)

@@ -494,7 +494,7 @@ ensureCompiler sopts = do
unless needLocal $ do
$logWarn "Trying to change a Cabal library on a GHC not installed by stack."
$logWarn "This may fail, caveat emptor!"
upgradeCabal menv wc (fromJust cabalVersion)
forM_ cabalVersion (upgradeCabal menv wc)
Copy link
Member

Choose a reason for hiding this comment

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

No, the forM_ should wrap the entire block:

forM_ cabalVersion $ \v -> do
  unless …

@mgsloan
Copy link
Contributor

mgsloan commented Feb 22, 2017

Looks like good stuff! I certainly recommend making sure the downgrade case works. I'd also have expected it to require unregistering the old one.

@snoyberg
Copy link
Contributor

Moving over the discussion from #3019:

Upgrading the global Cabal package is an ugly hack that I added in towards the beginning of Stack. It was necessary for cases where a custom setup script required some new functionality in Cabal that was not present in the shipped-with-GHC version. However, since then, we've had a significant change: custom-setup stanzas. With these, we're no longer trapped by random whims of the package database, and trying to guess what set of packages should be available to Setup.hs. In particular:

  • Stackage snapshots will now build packages reliably against the snapshot version of Cabal
  • If a specific Cabal version is needed, it can be specified in a .cabal file
  • Instead of being pinned to building against the global version of Cabal, we can build against the snapshot version

So I'd like to go in almost the opposite direction of this PR (apologies to @lwm and @sjakobi for only commenting now):

  • Get rid of the hack of upgrading global Cabal versions at all
  • Give massive warnings if a custom setup script does not specify its dependencies via custom-setup

I'd go so far as considering upstream—in Stackage itself—beginning to block packages that don't define a custom-setup stanza.

@sjakobi
Copy link
Member

sjakobi commented Feb 22, 2017

@snoyberg Interesting!

So to check that stack is compatible with Setup.hs files built with several versions of Cabal I'd simply use a different resolver (see e.g. #2350 for a usecase)?
Will overriding the resolver's version of Cabal via extra-deps or packages be supported?

@snoyberg
Copy link
Contributor

I'm pretty sure that overriding the Cabal version will work with master, though to be honest I haven't tested it explicitly.

@sjakobi
Copy link
Member

sjakobi commented Feb 22, 2017

@snoyberg

I'm pretty sure that overriding the Cabal version will work with master

Not sure if I'm missing something but it doesn't seem to work:

~/tmp $ stack --resolver lts-8.2 new cabal-setup
~/tmp $ cd cabal-setup/
~/t/cabal-setup $ vim stack.yaml # Add Cabal-1.24.0.0 to extra-deps
~/t/cabal-setup $ stack build
Warning: File listed in cabal-setup.cabal file does not exist: README.md
cabal-setup-0.1.0.0: configure (lib + exe)
Configuring cabal-setup-0.1.0.0...
cabal-setup-0.1.0.0: build (lib + exe)
Preprocessing library cabal-setup-0.1.0.0...
[1 of 1] Compiling Lib              ( src/Lib.hs, .stack-work/dist/x86_64-linux/Cabal-1.24.2.0/build/Lib.o )
Preprocessing executable 'cabal-setup-exe' for cabal-setup-0.1.0.0...
[1 of 1] Compiling Main             ( app/Main.hs, .stack-work/dist/x86_64-linux/Cabal-1.24.2.0/build/cabal-setup-exe/cabal-setup-exe-tmp/Main.o )
Linking .stack-work/dist/x86_64-linux/Cabal-1.24.2.0/build/cabal-setup-exe/cabal-setup-exe ...
Warning: File listed in cabal-setup.cabal file does not exist: README.md
cabal-setup-0.1.0.0: copy/register
Installing library in
/home/simon/tmp/cabal-setup/.stack-work/install/x86_64-linux/lts-8.2/8.0.2/lib/x86_64-linux-ghc-8.0.2/cabal-setup-0.1.0.0-Bd2jGUn5HBKJ5lzwApT2Rh
Installing executable(s) in
/home/simon/tmp/cabal-setup/.stack-work/install/x86_64-linux/lts-8.2/8.0.2/bin
Registering cabal-setup-0.1.0.0...

Judging from the build paths stack used Cabal-1.24.2.0 instead of 1.24.0.0 to build the Setup.hs.

@snoyberg
Copy link
Contributor

snoyberg commented Feb 22, 2017 via email

@sjakobi
Copy link
Member

sjakobi commented Feb 22, 2017

Is this using custom setup at all?

No, but should that be a requirement for testing compatibility between stack and Cabal?

@snoyberg
Copy link
Contributor

snoyberg commented Feb 22, 2017 via email

@sjakobi
Copy link
Member

sjakobi commented Feb 22, 2017

Ah, good! Maybe the usage info for --upgrade-cabal and install-cabal should note that these flags are only for debugging now.

@snoyberg
Copy link
Contributor

snoyberg commented Feb 22, 2017 via email

@decentral1se
Copy link
Member Author

Kind of fell off on this one. Is this PR still relevant? I see lots of movement around Cabal stuff.

@mgsloan
Copy link
Contributor

mgsloan commented Mar 16, 2017

@lwm I think the main unresolved issue is handling the downgrade case. Currently with this patch, if I have Cabal-1.24.2.0 and run stack setup --install-cabal 1.24.0.0, I get Currently installed Cabal is 1.24.2.0 (specified). No work to be done.

I think this is still relevant. I don't see how custom-setup obviates the need for this, since the global cabal is still used for everything else.

@decentral1se
Copy link
Member Author

Thanks for feedback @mgsloan and @sjakobi.

I've given this another stab. Apologies that the diff on this latest patch diverged so far but I tried a new approach. It appears the downgrade case is covered now but it takes so long to get a cabal install on my crappy machine, I didn't spend long testing ;)

@decentral1se
Copy link
Member Author

Failure unrelated ... tests seem to be borked:

src/test/Stack/ConfigSpec.hs:154:22:
    No instance for (FromJSON (WithJSONWarnings ConfigMonoid))
      arising from a use of decodeEither
    In the expression: decodeEither defaultConfigYaml
    In an equation for parsed’:
        parsed = decodeEither defaultConfigYaml
    In the expression:
      do { let parsed :: Either String (WithJSONWarnings ConfigMonoid)
               parsed = decodeEither defaultConfigYaml;
           isRight parsed `shouldBe` True }

@mgsloan
Copy link
Contributor

mgsloan commented Mar 19, 2017

@lwm My mistake, sorry! Should be fixed after rebasing.

@decentral1se
Copy link
Member Author

No worries @mgsloan! Travis said OK but now Appveyor said:

C:\stack\src\test\Stack\ConfigSpec.hs:154:53: error:
    * Exception when trying to run compile-time code:
        InvalidAbsDir "/"
CallStack (from HasCallStack):
  error, called at src/Path.hs:242:17 in path-0.5.12-DPixZY6jeMPCLEenb9rPGQ:Path
      Code: mkAbsDir "/"
    * In the untyped splice: $(mkAbsDir "/")
--  While building package stack-1.4.1 using:

The never ending pull request lives on!

@mgsloan
Copy link
Contributor

mgsloan commented Mar 20, 2017

Oops, fixed that too. I'm going to go ahead and merge this. Thanks!!

@mgsloan mgsloan merged commit 5f7c0f2 into commercialhaskell:master Mar 20, 2017
@decentral1se decentral1se deleted the add-cabal-install branch March 20, 2017 22:20
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.

4 participants