parent
							
								
									02135bdbae
								
							
						
					
					
						commit
						9497e310ca
					
				| @ -49,7 +49,6 @@ import           Data.Char | |||||||
| import           Data.Either | import           Data.Either | ||||||
| import           Data.Functor | import           Data.Functor | ||||||
| import           Data.List                      ( intercalate, nub, sort, sortBy ) | import           Data.List                      ( intercalate, nub, sort, sortBy ) | ||||||
| import           Data.List.NonEmpty             (NonEmpty ((:|))) |  | ||||||
| import           Data.Maybe | import           Data.Maybe | ||||||
| import           Data.Text                      ( Text ) | import           Data.Text                      ( Text ) | ||||||
| import           Data.Versions           hiding ( str ) | import           Data.Versions           hiding ( str ) | ||||||
| @ -2749,13 +2748,15 @@ fromVersion' SetRecommended tool = do | |||||||
| fromVersion' (SetToolVersion v) tool = do | fromVersion' (SetToolVersion v) tool = do | ||||||
|   GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo |   GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo | ||||||
|   let vi = getVersionInfo (_tvVersion v) tool dls |   let vi = getVersionInfo (_tvVersion v) tool dls | ||||||
|   case pvp $ prettyVer (_tvVersion v) of |   case pvp $ prettyVer (_tvVersion v) of -- need to be strict here | ||||||
|     Left _ -> pure (v, vi) |     Left _ -> pure (v, vi) | ||||||
|     Right (PVP (major' :|[minor'])) -> |     Right pvpIn -> | ||||||
|       case getLatestGHCFor (fromIntegral major') (fromIntegral minor') dls of |       lift (getLatestToolFor tool pvpIn dls) >>= \case | ||||||
|         Just (v', vi') -> pure (GHCTargetVersion (_tvTarget v) v', Just vi') |         Just (pvp_, vi') -> do | ||||||
|  |           v' <- lift $ pvpToVersion pvp_ | ||||||
|  |           when (v' /= (_tvVersion v)) $ lift $ logWarn ("Assuming you meant version " <> prettyVer v') | ||||||
|  |           pure (GHCTargetVersion (_tvTarget v) v', Just vi') | ||||||
|         Nothing -> pure (v, vi) |         Nothing -> pure (v, vi) | ||||||
|     Right _ -> pure (v, vi) |  | ||||||
| fromVersion' (SetToolTag Latest) tool = do | fromVersion' (SetToolTag Latest) tool = do | ||||||
|   GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo |   GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo | ||||||
|   (\(x, y) -> (mkTVer x, Just y)) <$> getLatest dls tool ?? TagNotFound Latest tool |   (\(x, y) -> (mkTVer x, Just y)) <$> getLatest dls tool ?? TagNotFound Latest tool | ||||||
|  | |||||||
							
								
								
									
										11
									
								
								lib/GHCup.hs
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								lib/GHCup.hs
									
									
									
									
									
								
							| @ -59,6 +59,7 @@ import           Data.ByteString                ( ByteString ) | |||||||
| import           Data.Either | import           Data.Either | ||||||
| import           Data.List | import           Data.List | ||||||
| import           Data.Maybe | import           Data.Maybe | ||||||
|  | import           Data.List.NonEmpty             ( NonEmpty((:|)) ) | ||||||
| import           Data.String                    ( fromString ) | import           Data.String                    ( fromString ) | ||||||
| import           Data.Text                      ( Text ) | import           Data.Text                      ( Text ) | ||||||
| import           Data.Time.Clock | import           Data.Time.Clock | ||||||
| @ -1573,7 +1574,7 @@ listVersions lt' criteria = do | |||||||
| 
 | 
 | ||||||
|   currentGHCup :: Map.Map Version VersionInfo -> Maybe ListResult |   currentGHCup :: Map.Map Version VersionInfo -> Maybe ListResult | ||||||
|   currentGHCup av = |   currentGHCup av = | ||||||
|     let currentVer = pvpToVersion ghcUpVer |     let currentVer = fromJust $ pvpToVersion ghcUpVer | ||||||
|         listVer    = Map.lookup currentVer av |         listVer    = Map.lookup currentVer av | ||||||
|         latestVer  = fst <$> headOf (getTagged Latest) av |         latestVer  = fst <$> headOf (getTagged Latest) av | ||||||
|         recommendedVer = fst <$> headOf (getTagged Latest) av |         recommendedVer = fst <$> headOf (getTagged Latest) av | ||||||
| @ -1731,7 +1732,7 @@ rmGHCVer ver = do | |||||||
|       (\(e :: ParseError) -> lift $ logWarn (T.pack $ displayException e) >> pure Nothing) |       (\(e :: ParseError) -> lift $ logWarn (T.pack $ displayException e) >> pure Nothing) | ||||||
|     $ fmap Just |     $ fmap Just | ||||||
|     $ getMajorMinorV (_tvVersion ver) |     $ getMajorMinorV (_tvVersion ver) | ||||||
|   forM_ v' $ \(mj, mi) -> lift (getGHCForMajor mj mi (_tvTarget ver)) |   forM_ v' $ \(mj, mi) -> lift (getGHCForPVP (PVP (fromIntegral mj :| [fromIntegral mi])) (_tvTarget ver)) | ||||||
|     >>= mapM_ (\v -> liftE $ setGHC v SetGHC_XY) |     >>= mapM_ (\v -> liftE $ setGHC v SetGHC_XY) | ||||||
| 
 | 
 | ||||||
|   Dirs {..} <- lift getDirs |   Dirs {..} <- lift getDirs | ||||||
| @ -2539,6 +2540,7 @@ upgradeGHCup :: ( MonadMask m | |||||||
|                 , MonadCatch m |                 , MonadCatch m | ||||||
|                 , HasLog env |                 , HasLog env | ||||||
|                 , MonadThrow m |                 , MonadThrow m | ||||||
|  |                 , MonadFail m | ||||||
|                 , MonadResource m |                 , MonadResource m | ||||||
|                 , MonadIO m |                 , MonadIO m | ||||||
|                 , MonadUnliftIO m |                 , MonadUnliftIO m | ||||||
| @ -2563,7 +2565,8 @@ upgradeGHCup mtarget force' = do | |||||||
| 
 | 
 | ||||||
|   lift $ logInfo "Upgrading GHCup..." |   lift $ logInfo "Upgrading GHCup..." | ||||||
|   let latestVer = fromJust $ fst <$> getLatest dls GHCup |   let latestVer = fromJust $ fst <$> getLatest dls GHCup | ||||||
|   when (not force' && (latestVer <= pvpToVersion ghcUpVer)) $ throwE NoUpdate |   (Just ghcupPVPVer) <- pure $ pvpToVersion ghcUpVer | ||||||
|  |   when (not force' && (latestVer <= ghcupPVPVer)) $ throwE NoUpdate | ||||||
|   dli   <- liftE $ getDownloadInfo GHCup latestVer |   dli   <- liftE $ getDownloadInfo GHCup latestVer | ||||||
|   tmp   <- lift withGHCupTmpDir |   tmp   <- lift withGHCupTmpDir | ||||||
|   let fn = "ghcup" <> exeExt |   let fn = "ghcup" <> exeExt | ||||||
| @ -2626,7 +2629,7 @@ postGHCInstall ver@GHCTargetVersion {..} = do | |||||||
|     handle (\(e :: ParseError) -> lift $ logWarn (T.pack $ displayException e) >> pure Nothing) |     handle (\(e :: ParseError) -> lift $ logWarn (T.pack $ displayException e) >> pure Nothing) | ||||||
|     $ fmap Just |     $ fmap Just | ||||||
|     $ getMajorMinorV _tvVersion |     $ getMajorMinorV _tvVersion | ||||||
|   forM_ v' $ \(mj, mi) -> lift (getGHCForMajor mj mi _tvTarget) |   forM_ v' $ \(mj, mi) -> lift (getGHCForPVP (PVP (fromIntegral mj :| [fromIntegral mi])) _tvTarget) | ||||||
|     >>= mapM_ (\v -> liftE $ setGHC v SetGHC_XY) |     >>= mapM_ (\v -> liftE $ setGHC v SetGHC_XY) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -86,8 +86,37 @@ import qualified Data.Map.Strict               as Map | |||||||
| import qualified Data.Text                     as T | import qualified Data.Text                     as T | ||||||
| import qualified Data.Text.Encoding            as E | import qualified Data.Text.Encoding            as E | ||||||
| import qualified Text.Megaparsec               as MP | import qualified Text.Megaparsec               as MP | ||||||
|  | import qualified Data.List.NonEmpty            as NE | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | -- $setup | ||||||
|  | -- >>> :set -XOverloadedStrings | ||||||
|  | -- >>> :set -XDataKinds | ||||||
|  | -- >>> :set -XTypeApplications | ||||||
|  | -- >>> :set -XQuasiQuotes | ||||||
|  | -- >>> import System.Directory | ||||||
|  | -- >>> import URI.ByteString | ||||||
|  | -- >>> import qualified Data.Text as T | ||||||
|  | -- >>> import GHCup.Utils.Prelude | ||||||
|  | -- >>> import GHCup.Download | ||||||
|  | -- >>> import GHCup.Version | ||||||
|  | -- >>> import GHCup.Errors | ||||||
|  | -- >>> import GHCup.Types | ||||||
|  | -- >>> import GHCup.Types.Optics | ||||||
|  | -- >>> import Optics | ||||||
|  | -- >>> import GHCup.Utils.Version.QQ | ||||||
|  | -- >>> import qualified Data.Text.Encoding as E | ||||||
|  | -- >>> import Control.Monad.Reader | ||||||
|  | -- >>> import Haskus.Utils.Variant.Excepts | ||||||
|  | -- >>> import Text.PrettyPrint.HughesPJClass ( prettyShow ) | ||||||
|  | -- >>> let lc = LoggerConfig { lcPrintDebug = False, consoleOutter = mempty, fileOutter = mempty, fancyColors = False } | ||||||
|  | -- >>> dirs' <- getAllDirs | ||||||
|  | -- >>> let installedVersions = [ ([pver|8.10.7|], Nothing), ([pver|8.10.4|], Nothing), ([pver|8.8.4|], Nothing), ([pver|8.8.3|], Nothing) ] | ||||||
|  | -- >>> let settings = Settings True False Never Curl False GHCupURL True GPGNone False | ||||||
|  | -- >>> let leanAppState = LeanAppState settings dirs' defaultKeyBindings lc | ||||||
|  | -- >>> cwd <- getCurrentDirectory | ||||||
|  | -- >>> (Right ref) <- pure $ parseURI strictURIParserOptions $ "file://" <> E.encodeUtf8 (T.pack cwd) <> "/data/metadata/" <> (urlBaseName . view pathL' $ ghcupURL) | ||||||
|  | -- >>> (VRight r) <- (fmap . fmap) _ghcupDownloads $ flip runReaderT leanAppState . runE @'[DigestError, GPGError, JSONError , DownloadFailed , FileDoesNotExistError] $ liftE $ getBase ref | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @ -559,34 +588,83 @@ matchMajor v' major' minor' = case getMajorMinorV v' of | |||||||
|   Just (x, y) -> x == major' && y == minor' |   Just (x, y) -> x == major' && y == minor' | ||||||
|   Nothing     -> False |   Nothing     -> False | ||||||
| 
 | 
 | ||||||
|  | -- | Match PVP prefix. | ||||||
|  | -- | ||||||
|  | -- >>> matchPVPrefix [pver|8.8|] [pver|8.8.4|] | ||||||
|  | -- True | ||||||
|  | -- >>> matchPVPrefix [pver|8|] [pver|8.8.4|] | ||||||
|  | -- True | ||||||
|  | -- >>> matchPVPrefix [pver|8.10|] [pver|8.8.4|] | ||||||
|  | -- False | ||||||
|  | -- >>> matchPVPrefix [pver|8.10|] [pver|8.10.7|] | ||||||
|  | -- True | ||||||
|  | matchPVPrefix :: PVP -> PVP -> Bool | ||||||
|  | matchPVPrefix (toL -> prefix) (toL -> full) = and $ zipWith (==) prefix full | ||||||
| 
 | 
 | ||||||
| -- | Get the latest installed full GHC version that satisfies X.Y. | toL :: PVP -> [Int] | ||||||
| -- This reads `ghcupGHCBaseDir`. | toL (PVP inner) = fmap fromIntegral $ NE.toList inner | ||||||
| getGHCForMajor :: (MonadReader env m, HasDirs env, MonadIO m, MonadThrow m) | 
 | ||||||
|                => Int        -- ^ major version component | 
 | ||||||
|                -> Int        -- ^ minor version component | -- | Get the latest installed full GHC version that satisfies the given (possibly partial) | ||||||
|                -> Maybe Text -- ^ the target triple | -- PVP version. | ||||||
|                -> m (Maybe GHCTargetVersion) | getGHCForPVP :: (MonadReader env m, HasDirs env, MonadIO m, MonadThrow m) | ||||||
| getGHCForMajor major' minor' mt = do |              => PVP | ||||||
|  |              -> Maybe Text -- ^ the target triple | ||||||
|  |              -> m (Maybe GHCTargetVersion) | ||||||
|  | getGHCForPVP pvpIn mt = do | ||||||
|   ghcs <- rights <$> getInstalledGHCs |   ghcs <- rights <$> getInstalledGHCs | ||||||
|  |   -- we're permissive here... failed parse just means we have no match anyway | ||||||
|  |   let ghcs' = catMaybes $ flip fmap ghcs $ \GHCTargetVersion{..} -> do | ||||||
|  |         pvp_ <- versionToPVP _tvVersion | ||||||
|  |         pure (pvp_, _tvTarget) | ||||||
| 
 | 
 | ||||||
|   pure |   getGHCForPVP' pvpIn ghcs' mt | ||||||
|     . lastMay | 
 | ||||||
|     . sortBy (\x y -> compare (_tvVersion x) (_tvVersion y)) | -- | Like 'getGHCForPVP', except with explicit input parameter. | ||||||
|     . filter | -- | ||||||
|         (\GHCTargetVersion {..} -> | -- >>> fmap prettyShow $ getGHCForPVP' [pver|8|] installedVersions Nothing | ||||||
|           _tvTarget == mt && matchMajor _tvVersion major' minor' | -- "Just 8.10.7" | ||||||
|         ) | -- >>> fmap prettyShow $ getGHCForPVP' [pver|8.8|] installedVersions Nothing | ||||||
|     $ ghcs | -- "Just 8.8.4" | ||||||
|  | -- >>> fmap prettyShow $ getGHCForPVP' [pver|8.10.4|] installedVersions Nothing | ||||||
|  | -- "Just 8.10.4" | ||||||
|  | getGHCForPVP' :: MonadThrow m | ||||||
|  |              => PVP | ||||||
|  |              -> [(PVP, Maybe Text)] -- ^ installed GHCs | ||||||
|  |              -> Maybe Text          -- ^ the target triple | ||||||
|  |              -> m (Maybe GHCTargetVersion) | ||||||
|  | getGHCForPVP' pvpIn ghcs' mt = do | ||||||
|  |   let mResult = lastMay | ||||||
|  |                   . sortBy (\(x, _) (y, _) -> compare x y) | ||||||
|  |                   . filter | ||||||
|  |                       (\(pvp_, target) -> | ||||||
|  |                         target == mt && matchPVPrefix pvp_ pvpIn | ||||||
|  |                       ) | ||||||
|  |                   $ ghcs' | ||||||
|  |   forM mResult $ \(pvp_, target) -> do | ||||||
|  |     ver' <- pvpToVersion pvp_ | ||||||
|  |     pure (GHCTargetVersion target ver') | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| -- | Get the latest available ghc for X.Y major version. | -- | Get the latest available ghc for the given PVP version, which | ||||||
| getLatestGHCFor :: Int -- ^ major version component | -- may only contain parts. | ||||||
|                 -> Int -- ^ minor version component | -- | ||||||
|                 -> GHCupDownloads | -- >>> (fmap . fmap) fst $ getLatestToolFor GHC [pver|8|] r | ||||||
|                 -> Maybe (Version, VersionInfo) | -- Just (PVP {_pComponents = 8 :| [10,7]}) | ||||||
| getLatestGHCFor major' minor' dls = | -- >>> (fmap . fmap) fst $ getLatestToolFor GHC [pver|8.8|] r | ||||||
|   preview (ix GHC % to Map.toDescList) dls >>= lastMay . filter (\(v, _) -> matchMajor v major' minor') | -- Just (PVP {_pComponents = 8 :| [8,4]}) | ||||||
|  | -- >>> (fmap . fmap) fst $ getLatestToolFor GHC [pver|8.8.4|] r | ||||||
|  | -- Just (PVP {_pComponents = 8 :| [8,4]}) | ||||||
|  | getLatestToolFor :: MonadThrow m | ||||||
|  |                  => Tool | ||||||
|  |                  -> PVP | ||||||
|  |                  -> GHCupDownloads | ||||||
|  |                  -> m (Maybe (PVP, VersionInfo)) | ||||||
|  | getLatestToolFor tool pvpIn dls = do | ||||||
|  |   let ls = fromMaybe [] $ preview (ix tool % to Map.toDescList) dls | ||||||
|  |   let ps = catMaybes $ fmap (\(v, vi) -> (,vi) <$> versionToPVP v) ls | ||||||
|  |   pure . headMay . filter (\(v, _) -> matchPVPrefix pvpIn v) $ ps | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -22,6 +22,7 @@ module GHCup.Utils.Prelude where | |||||||
| #if defined(IS_WINDOWS) | #if defined(IS_WINDOWS) | ||||||
| import           GHCup.Types | import           GHCup.Types | ||||||
| #endif | #endif | ||||||
|  | import           GHCup.Errors | ||||||
| import           GHCup.Types.Optics | import           GHCup.Types.Optics | ||||||
| import {-# SOURCE #-} GHCup.Utils.Logger | import {-# SOURCE #-} GHCup.Utils.Logger | ||||||
| 
 | 
 | ||||||
| @ -35,10 +36,11 @@ import           Data.ByteString                ( ByteString ) | |||||||
| import           Data.List                      ( nub, intercalate, stripPrefix, isPrefixOf ) | import           Data.List                      ( nub, intercalate, stripPrefix, isPrefixOf ) | ||||||
| import           Data.Maybe | import           Data.Maybe | ||||||
| import           Data.Foldable | import           Data.Foldable | ||||||
|  | import           Data.List.NonEmpty             ( NonEmpty( (:|) )) | ||||||
| import           Data.String | import           Data.String | ||||||
| import           Data.Text                      ( Text ) | import           Data.Text                      ( Text ) | ||||||
| import           Data.Versions | import           Data.Versions | ||||||
| import           Data.Word8 | import           Data.Word8                  hiding ( isDigit ) | ||||||
| import           Haskus.Utils.Types.List | import           Haskus.Utils.Types.List | ||||||
| import           Haskus.Utils.Variant.Excepts | import           Haskus.Utils.Variant.Excepts | ||||||
| import           Text.PrettyPrint.HughesPJClass ( prettyShow, Pretty ) | import           Text.PrettyPrint.HughesPJClass ( prettyShow, Pretty ) | ||||||
| @ -59,6 +61,7 @@ import qualified Data.ByteString               as B | |||||||
| import qualified Data.ByteString.Lazy          as L | import qualified Data.ByteString.Lazy          as L | ||||||
| import qualified Data.Strict.Maybe             as S | import qualified Data.Strict.Maybe             as S | ||||||
| import qualified Data.List.Split               as Split | import qualified Data.List.Split               as Split | ||||||
|  | import qualified Data.List.NonEmpty            as NE | ||||||
| import qualified Data.Text                     as T | import qualified Data.Text                     as T | ||||||
| import qualified Data.Text.Encoding            as E | import qualified Data.Text.Encoding            as E | ||||||
| import qualified Data.Text.Encoding.Error      as E | import qualified Data.Text.Encoding.Error      as E | ||||||
| @ -296,12 +299,28 @@ removeLensFieldLabel str' = | |||||||
|   maybe str' T.unpack . T.stripPrefix (T.pack "_") . T.pack $ str' |   maybe str' T.unpack . T.stripPrefix (T.pack "_") . T.pack $ str' | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| pvpToVersion :: PVP -> Version | pvpToVersion :: MonadThrow m => PVP -> m Version | ||||||
| pvpToVersion = | pvpToVersion = | ||||||
|   either (\_ -> error "Couldn't convert PVP to Version") id |   either (\_ -> throwM $ ParseError "Couldn't convert PVP to Version") pure . version . prettyPVP | ||||||
|     . version |  | ||||||
|     . prettyPVP |  | ||||||
| 
 | 
 | ||||||
|  | versionToPVP :: MonadThrow m => Version -> m PVP | ||||||
|  | versionToPVP v = either (\_ -> alternative v) pure . pvp . prettyVer $ v | ||||||
|  |  where | ||||||
|  |   alternative :: MonadThrow m => Version -> m PVP | ||||||
|  |   alternative v' = case NE.takeWhile isDigit (_vChunks v') of | ||||||
|  |     [] -> throwM $ ParseError "Couldn't convert Version to PVP" | ||||||
|  |     xs -> pure $ pvpFromList (unsafeDigit <$> xs) | ||||||
|  | 
 | ||||||
|  |   isDigit :: VChunk -> Bool | ||||||
|  |   isDigit (Digits _ :| []) = True | ||||||
|  |   isDigit _                = False | ||||||
|  | 
 | ||||||
|  |   unsafeDigit :: VChunk -> Int | ||||||
|  |   unsafeDigit (Digits x :| []) = fromIntegral x | ||||||
|  |   unsafeDigit _ = error "unsafeDigit: wrong input" | ||||||
|  | 
 | ||||||
|  | pvpFromList :: [Int] -> PVP | ||||||
|  | pvpFromList = PVP . NE.fromList . fmap fromIntegral | ||||||
| 
 | 
 | ||||||
| -- | Safe 'decodeUtf8With'. Replaces an invalid input byte with | -- | Safe 'decodeUtf8With'. Replaces an invalid input byte with | ||||||
| -- the Unicode replacement character U+FFFD. | -- the Unicode replacement character U+FFFD. | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user