@@ -95,6 +95,7 @@ data BuildPlanException
95
95
(Map PackageName (Maybe Version , Set PackageName )) -- truly unknown
96
96
(Map PackageName (Set PackageIdentifier )) -- shadowed
97
97
| SnapshotNotFound SnapName
98
+ | FilepathInDownloadedSnapshot T. Text
98
99
deriving (Typeable )
99
100
instance Exception BuildPlanException
100
101
instance Show BuildPlanException where
@@ -174,6 +175,11 @@ instance Show BuildPlanException where
174
175
$ Set. toList
175
176
$ Set. unions
176
177
$ Map. elems shadowed
178
+ show (FilepathInDownloadedSnapshot url) = unlines
179
+ [ " Downloaded snapshot specified a 'resolver: { location: filepath }' "
180
+ , " field, but filepaths are not allowed in downloaded snapshots.\n "
181
+ , " Filepath specified: " ++ T. unpack url
182
+ ]
177
183
178
184
-- | Determine the necessary packages to install to have the given set of
179
185
-- packages available.
@@ -221,8 +227,6 @@ toMiniBuildPlan :: (MonadIO m, MonadLogger m, MonadReader env m, HasHttpManager
221
227
-> Map PackageName (Version , Map FlagName Bool , [Text ], Maybe GitSHA1 ) -- ^ non-core packages
222
228
-> m MiniBuildPlan
223
229
toMiniBuildPlan compilerVersion requireAllowNewer corePackages packages = do
224
- $ logInfo " Caching build plan"
225
-
226
230
-- Determine the dependencies of all of the packages in the build plan. We
227
231
-- handle core packages specially, because some of them will not be in the
228
232
-- package index. For those, we allow missing packages to exist, and then
@@ -409,6 +413,24 @@ getToolMap mbp =
409
413
$ Set. toList
410
414
$ mpiExes mpi
411
415
416
+ loadResolver
417
+ :: (MonadIO m , MonadThrow m , MonadLogger m , MonadReader env m , HasHttpManager env , HasConfig env , HasGHCVariant env , MonadBaseControl IO m , MonadMask m )
418
+ => Maybe (Path Abs File )
419
+ -> Resolver
420
+ -> m MiniBuildPlan
421
+ loadResolver mconfigPath resolver =
422
+ case resolver of
423
+ ResolverSnapshot snap -> loadMiniBuildPlan snap
424
+ -- TODO(mgsloan): Not sure what this FIXME means
425
+ -- FIXME instead of passing the stackYaml dir we should maintain
426
+ -- the file URL in the custom resolver always relative to stackYaml.
427
+ ResolverCustom _ url -> parseCustomMiniBuildPlan mconfigPath url
428
+ ResolverCompiler compiler -> return MiniBuildPlan
429
+ { mbpCompilerVersion = compiler
430
+ , mbpPackages = mempty
431
+ , mbpAllowNewer = False
432
+ }
433
+
412
434
-- | Load up a 'MiniBuildPlan', preferably from cache
413
435
loadMiniBuildPlan
414
436
:: (MonadIO m , MonadLogger m , MonadReader env m , HasHttpManager env , HasConfig env , HasGHCVariant env , MonadBaseControl IO m , MonadMask m )
@@ -892,11 +914,20 @@ shadowMiniBuildPlan (MiniBuildPlan cv pkgs0 allowNewer) shadowed =
892
914
Just False -> Right
893
915
Nothing -> assert False Right
894
916
895
- parseCustomMiniBuildPlan :: (MonadIO m , MonadMask m , MonadLogger m , MonadReader env m , HasHttpManager env , HasConfig env , MonadBaseControl IO m )
896
- => Path Abs File -- ^ stack.yaml file location
897
- -> T. Text -> m MiniBuildPlan
898
- parseCustomMiniBuildPlan stackYamlFP url0 = do
899
- yamlFP <- getYamlFP url0
917
+ parseCustomMiniBuildPlan
918
+ :: (MonadIO m , MonadMask m , MonadLogger m , MonadReader env m , HasHttpManager env , HasConfig env , HasGHCVariant env , MonadBaseControl IO m )
919
+ => Maybe (Path Abs File ) -- ^ Root directory for when url is a filepath
920
+ -> T. Text
921
+ -> m MiniBuildPlan
922
+ parseCustomMiniBuildPlan mconfigPath url0 = do
923
+ $ logDebug $ " Loading " <> url0 <> " build plan"
924
+ eyamlFP <- getYamlFP url0
925
+ let yamlFP = either id id eyamlFP
926
+
927
+ -- FIXME: determine custom snapshot path based on contents. Ideally,
928
+ -- use a hash scheme that ignores formatting differences (works on
929
+ -- the data), so that an implicit snapshot (TBD) will hash to the
930
+ -- same thing as a custom snapshot.
900
931
901
932
yamlBS <- liftIO $ S. readFile $ toFilePath yamlFP
902
933
let yamlHash = S8. unpack $ B16. encode $ SHA256. hash yamlBS
@@ -905,36 +936,33 @@ parseCustomMiniBuildPlan stackYamlFP url0 = do
905
936
let binaryFP = customPlanDir </> $ (mkRelDir " bin" ) </> binaryFilename
906
937
907
938
taggedDecodeOrLoad binaryFP $ do
908
- WithJSONWarnings result warnings <-
939
+ WithJSONWarnings (cs0, mresolver) warnings <-
909
940
either (throwM . ParseCustomSnapshotException url0) return $
910
941
decodeEither' yamlBS
911
- logJSONWarnings (toFilePath yamlFP) warnings
912
- let (CustomSnapshot
913
- mcompilerVersion
914
- packages
915
- (PackageFlags flags)
916
- ghcOptions
917
- allowNewer) = result
918
- let addFlags :: PackageIdentifier -> (PackageName , (Version , Map FlagName Bool , [Text ]))
919
- addFlags (PackageIdentifier name ver) =
920
- ( name
921
- , ( ver
922
- , Map. findWithDefault Map. empty name flags
923
- -- NOTE: similar to 'allGhcOptions' in Stack.Types.Build
924
- , ghcOptionsFor name ghcOptions
925
- )
926
- )
927
- case mcompilerVersion of
928
- Just compilerVersion ->
929
- toMiniBuildPlan
930
- compilerVersion
931
- (fromMaybe False allowNewer)
932
- Map. empty
933
- (fmap addGitSHA $ Map. fromList $ map addFlags $ Set. toList packages)
934
- Nothing -> do
935
- -- TODO: proper exception type
942
+ logJSONWarnings (T. unpack url0) warnings
943
+ case (mresolver, csCompilerVersion cs0) of
944
+ (Nothing , Nothing ) ->
936
945
fail $ " Failed to load custom snapshot at " ++
937
- T. unpack url0 ++ " , because no compiler is specified."
946
+ T. unpack url0 ++
947
+ " , because no 'compiler' or 'resolver' is specified."
948
+ (Nothing , Just cv) ->
949
+ applyCustomSnapshot cs0 MiniBuildPlan
950
+ { mbpCompilerVersion = cv
951
+ , mbpPackages = mempty
952
+ , mbpAllowNewer = False
953
+ }
954
+ -- Even though we ignore the compiler version here, it gets
955
+ -- used due to applyCustomSnapshot
956
+ (Just resolver, _) -> do
957
+ -- Load referenced resolver. If the custom snapshot is
958
+ -- stored at a user location, then allow relative
959
+ -- filepath custom snapshots.
960
+ mbp <- loadResolver customFile resolver
961
+ applyCustomSnapshot cs0 mbp
962
+ where
963
+ customFile = case eyamlFP of
964
+ Left _ -> Nothing
965
+ Right fp -> Just fp
938
966
where
939
967
getCustomPlanDir = do
940
968
root <- asks $ configStackRoot . getConfig
@@ -953,12 +981,47 @@ parseCustomMiniBuildPlan stackYamlFP url0 = do
953
981
954
982
let cacheFP = customPlanDir </> $ (mkRelDir " yaml" ) </> hashFP
955
983
_ <- download req cacheFP
956
- return cacheFP
957
-
958
- getYamlFPFromFile url = do
959
- fp <- liftIO $ D. canonicalizePath $ toFilePath (parent stackYamlFP) FP. </> T. unpack (fromMaybe url $
960
- T. stripPrefix " file://" url <|> T. stripPrefix " file:" url)
961
- parseAbsFile fp
962
-
963
- -- we add a Nothing since we don't yet collect Git SHAs for custom snapshots
964
- addGitSHA (x, y, z) = (x, y, z, Nothing )
984
+ return (Left cacheFP)
985
+
986
+ getYamlFPFromFile url =
987
+ case mconfigPath of
988
+ Nothing -> throwM $ FilepathInDownloadedSnapshot url
989
+ Just configPath -> do
990
+ fp <- liftIO $ D. canonicalizePath $ toFilePath (parent configPath) FP. </> T. unpack (fromMaybe url $
991
+ T. stripPrefix " file://" url <|> T. stripPrefix " file:" url)
992
+ Right <$> parseAbsFile fp
993
+
994
+ applyCustomSnapshot
995
+ :: (MonadIO m , MonadLogger m , MonadReader env m , HasHttpManager env , MonadThrow m , HasConfig env , MonadBaseControl IO m , MonadMask m )
996
+ => CustomSnapshot
997
+ -> MiniBuildPlan
998
+ -> m MiniBuildPlan
999
+ applyCustomSnapshot cs mbp0 = do
1000
+ let CustomSnapshot mcompilerVersion
1001
+ packages
1002
+ dropPackages
1003
+ (PackageFlags flags)
1004
+ ghcOptions
1005
+ mallowNewer
1006
+ = cs
1007
+ addFlagsAndOpts :: PackageIdentifier -> (PackageName , (Version , Map FlagName Bool , [Text ], Maybe GitSHA1 ))
1008
+ addFlagsAndOpts (PackageIdentifier name ver) =
1009
+ ( name
1010
+ , ( ver
1011
+ , Map. findWithDefault Map. empty name flags
1012
+ -- NOTE: similar to 'allGhcOptions' in Stack.Types.Build
1013
+ , ghcOptionsFor name ghcOptions
1014
+ -- we add a Nothing since we don't yet collect Git SHAs for custom snapshots
1015
+ , Nothing
1016
+ )
1017
+ )
1018
+ packageMap = Map. fromList $ map addFlagsAndOpts $ Set. toList packages
1019
+ cv = fromMaybe (mbpCompilerVersion mbp0) mcompilerVersion
1020
+ packages0 =
1021
+ mbpPackages mbp0 `Map.difference` (Map. fromSet (\ _ -> () ) dropPackages)
1022
+ mbp1 <- toMiniBuildPlan cv False mempty packageMap
1023
+ return $ MiniBuildPlan
1024
+ { mbpCompilerVersion = cv
1025
+ , mbpPackages = Map. union (mbpPackages mbp1) packages0
1026
+ , mbpAllowNewer = fromMaybe (mbpAllowNewer mbp0) mallowNewer
1027
+ }
0 commit comments