1616-- | Dealing with Cabal.
1717
1818module Stack.Package
19- (readPackage
19+ (readPackageDir
20+ ,readPackageUnresolvedDir
21+ ,readPackageUnresolvedIndex
2022 ,readPackageDescriptionDir
2123 ,readDotBuildinfo
22- ,readPackageUnresolved
23- ,readPackageUnresolvedFromIndex
2424 ,resolvePackage
25- ,CabalWarnings (.. )
2625 ,packageFromPackageDescription
27- ,findOrGenerateCabalFile
28- ,hpack
2926 ,Package (.. )
3027 ,PackageDescriptionPair (.. )
3128 ,GetPackageFiles (.. )
@@ -37,12 +34,14 @@ module Stack.Package
3734 ,packageDescTools
3835 ,packageDependencies
3936 ,autogenDir
40- ,cabalFilePackageId )
37+ ,cabalFilePackageId
38+ ,gpdPackageIdentifier
39+ ,gpdPackageName
40+ ,gpdVersion )
4141 where
4242
4343import qualified Data.ByteString as BS
4444import qualified Data.ByteString.Char8 as C8
45- import qualified Data.HashSet as HashSet
4645import Data.List (isSuffixOf , partition , isPrefixOf )
4746import Data.List.Extra (nubOrd )
4847import qualified Data.Map.Strict as M
@@ -115,38 +114,44 @@ instance HasBuildConfig Ctx
115114instance HasEnvConfig Ctx where
116115 envConfigL = lens ctxEnvConfig (\ x y -> x { ctxEnvConfig = y })
117116
118- data CabalWarnings
119- = CWNoPrint
120- | CWPrint ! (Path Abs File )
121-
122- -- | Parse a cabal file from the given location. This performs caching
123- -- (based on the 'PackageLocationIndex'), and will only use the second
124- -- argument to grab a 'ByteString' on a cache miss. If we actually
125- -- perform a parse, and there are warnings, and the third argument is
126- -- 'True', then they will be printed.
127- cachedCabalFileParse
128- :: forall env . HasRunner env
117+ -- | A helper function that performs the basic character encoding
118+ -- necessary.
119+ rawParseGPD
120+ :: MonadThrow m
129121 => Either PackageIdentifierRevision (Path Abs File )
130- -> CabalWarnings
131- -> RIO env BS. ByteString -- ^ get the bytestring contents
132- -> RIO env GenericPackageDescription
133- cachedCabalFileParse key cw getBS = do
122+ -> BS. ByteString
123+ -> m ([PWarning ], GenericPackageDescription )
124+ rawParseGPD key bs =
125+ case parseGenericPackageDescription chars of
126+ ParseFailed e -> throwM $ PackageInvalidCabalFile key e
127+ ParseOk warnings gpkg -> return (warnings,gpkg)
128+ where
129+ chars = T. unpack (dropBOM (decodeUtf8With lenientDecode bs))
130+
131+ -- https://github.com/haskell/hackage-server/issues/351
132+ dropBOM t = fromMaybe t $ T. stripPrefix " \xFEFF " t
133+
134+ -- | Read the raw, unresolved package information from a file.
135+ readPackageUnresolvedDir
136+ :: forall env . HasConfig env
137+ => Path Abs Dir -- ^ directory holding the cabal file
138+ -> Bool -- ^ print warnings?
139+ -> RIO env (GenericPackageDescription , Path Abs File )
140+ readPackageUnresolvedDir dir printWarnings = do
134141 ref <- view $ runnerL. to runnerParsedCabalFiles
135- m0 <- readIORef ref
136- case M. lookup key m0 of
137- Just val -> return val
142+ (_, m) <- readIORef ref
143+ case M. lookup dir m of
144+ Just x -> return x
138145 Nothing -> do
139- bs <- getBS
140- val <-
141- case rawParseGPD bs of
142- Left e -> throwM $ PackageInvalidCabalFile key e
143- Right (warnings, gpd) -> do
144- case cw of
145- CWNoPrint -> return ()
146- CWPrint src -> mapM_ (prettyWarnL . toPretty (toFilePath src)) warnings
147- return gpd
148- atomicModifyIORef' ref $ \ m -> (M. insert key val m, () )
149- return val
146+ cabalfp <- findOrGenerateCabalFile dir
147+ bs <- liftIO $ BS. readFile $ toFilePath cabalfp
148+ (warnings, gpd) <- rawParseGPD (Right cabalfp) bs
149+ when printWarnings
150+ $ mapM_ (prettyWarnL . toPretty (toFilePath cabalfp)) warnings
151+ checkCabalFileName (gpdPackageName gpd) cabalfp
152+ let ret = (gpd, cabalfp)
153+ atomicModifyIORef' ref $ \ (m1, m2) ->
154+ ((m1, M. insert dir ret m2), ret)
150155 where
151156 toPretty :: String -> PWarning -> [Doc AnsiAnn ]
152157 toPretty src (PWarning x) =
@@ -160,66 +165,57 @@ cachedCabalFileParse key cw getBS = do
160165 , flow msg
161166 ]
162167
163- -- | A helper function that performs the basic character encoding
164- -- necessary.
165- rawParseGPD :: BS. ByteString
166- -> Either PError ([PWarning ], GenericPackageDescription )
167- rawParseGPD bs =
168- case parseGenericPackageDescription chars of
169- ParseFailed per -> Left per
170- ParseOk warnings gpkg -> Right (warnings,gpkg)
171- where
172- chars = T. unpack (dropBOM (decodeUtf8With lenientDecode bs))
168+ -- | Check if the given name in the @Package@ matches the name of the .cabal file
169+ checkCabalFileName :: MonadThrow m => PackageName -> Path Abs File -> m ()
170+ checkCabalFileName name cabalfp = do
171+ -- Previously, we just use parsePackageNameFromFilePath. However, that can
172+ -- lead to confusing error messages. See:
173+ -- https://github.com/commercialhaskell/stack/issues/895
174+ let expected = packageNameString name ++ " .cabal"
175+ when (expected /= toFilePath (filename cabalfp))
176+ $ throwM $ MismatchedCabalName cabalfp name
173177
174- -- https://github.com/haskell/hackage-server/issues/351
175- dropBOM t = fromMaybe t $ T. stripPrefix " \xFEFF " t
178+ gpdPackageIdentifier :: GenericPackageDescription -> PackageIdentifier
179+ gpdPackageIdentifier = fromCabalPackageIdentifier . D. package . D. packageDescription
176180
177- -- | Read the raw, unresolved package information from a file.
178- readPackageUnresolved
179- :: forall env . HasRunner env
180- => Path Abs File -- ^ cabal file location
181- -> Bool -- ^ print warnings?
182- -> RIO env GenericPackageDescription
183- readPackageUnresolved cabalfp printWarnings = do
184- gpd <- cachedCabalFileParse
185- (Right cabalfp)
186- (if printWarnings then CWPrint cabalfp else CWNoPrint )
187- (liftIO (BS. readFile (FL. toFilePath cabalfp)))
188- let PackageIdentifier name _version =
189- fromCabalPackageIdentifier
190- $ D. package
191- $ D. packageDescription gpd
192- checkCabalFileName name cabalfp
193- return gpd
181+ gpdPackageName :: GenericPackageDescription -> PackageName
182+ gpdPackageName = packageIdentifierName . gpdPackageIdentifier
183+
184+ gpdVersion :: GenericPackageDescription -> Version
185+ gpdVersion = packageIdentifierVersion . gpdPackageIdentifier
194186
195187-- | Read the 'GenericPackageDescription' from the given
196188-- 'PackageIdentifierRevision'.
197- readPackageUnresolvedFromIndex
189+ readPackageUnresolvedIndex
198190 :: forall env . HasRunner env
199191 => (PackageIdentifierRevision -> IO ByteString ) -- ^ load the raw bytes
200192 -> PackageIdentifierRevision
201193 -> RIO env GenericPackageDescription
202- readPackageUnresolvedFromIndex loadFromIndex pir@ (PackageIdentifierRevision pi' _) = do
203- gpd <- cachedCabalFileParse
204- (Left pir)
205- CWNoPrint
206- (liftIO $ loadFromIndex pir)
207- let foundPI =
208- fromCabalPackageIdentifier
209- $ D. package
210- $ D. packageDescription gpd
211- unless (pi' == foundPI) $ throwM $ MismatchedCabalIdentifier pir foundPI
212- return gpd
194+ readPackageUnresolvedIndex loadFromIndex pir@ (PackageIdentifierRevision pi' _) = do
195+ ref <- view $ runnerL. to runnerParsedCabalFiles
196+ (m, _) <- readIORef ref
197+ case M. lookup pir m of
198+ Just gpd -> return gpd
199+ Nothing -> do
200+ bs <- liftIO $ loadFromIndex pir
201+ (_warnings, gpd) <- rawParseGPD (Left pir) bs
202+ let foundPI =
203+ fromCabalPackageIdentifier
204+ $ D. package
205+ $ D. packageDescription gpd
206+ unless (pi' == foundPI) $ throwM $ MismatchedCabalIdentifier pir foundPI
207+ atomicModifyIORef' ref $ \ (m1, m2) ->
208+ ((M. insert pir gpd m1, m2), gpd)
213209
214210-- | Reads and exposes the package information
215- readPackage
216- :: forall env . HasRunner env
211+ readPackageDir
212+ :: forall env . HasConfig env
217213 => PackageConfig
218- -> Path Abs File
214+ -> Path Abs Dir
219215 -> Bool -- ^ print warnings from cabal file parsing?
220- -> RIO env Package
221- readPackage packageConfig cabalfp printWarnings =
222- resolvePackage packageConfig <$> readPackageUnresolved cabalfp printWarnings
216+ -> RIO env ( Package , Path Abs File )
217+ readPackageDir packageConfig dir printWarnings =
218+ first ( resolvePackage packageConfig) <$> readPackageUnresolvedDir dir printWarnings
223219
224220-- | Get 'GenericPackageDescription' and 'PackageDescription' reading info
225221-- from given directory.
@@ -230,8 +226,7 @@ readPackageDescriptionDir
230226 -> Bool -- ^ print warnings?
231227 -> RIO env (GenericPackageDescription , PackageDescriptionPair )
232228readPackageDescriptionDir config pkgDir printWarnings = do
233- cabalfp <- findOrGenerateCabalFile pkgDir
234- gdesc <- readPackageUnresolved cabalfp printWarnings
229+ (gdesc, _) <- readPackageUnresolvedDir pkgDir printWarnings
235230 return (gdesc, resolvePackageDescription config gdesc)
236231
237232-- | Read @<package>.buildinfo@ ancillary files produced by some Setup.hs hooks.
@@ -245,16 +240,6 @@ readDotBuildinfo :: MonadIO m
245240readDotBuildinfo buildinfofp =
246241 liftIO $ readHookedBuildInfo D. silent (toFilePath buildinfofp)
247242
248- -- | Check if the given name in the @Package@ matches the name of the .cabal file
249- checkCabalFileName :: MonadThrow m => PackageName -> Path Abs File -> m ()
250- checkCabalFileName name cabalfp = do
251- -- Previously, we just use parsePackageNameFromFilePath. However, that can
252- -- lead to confusing error messages. See:
253- -- https://github.com/commercialhaskell/stack/issues/895
254- let expected = packageNameString name ++ " .cabal"
255- when (expected /= toFilePath (filename cabalfp))
256- $ throwM $ MismatchedCabalName cabalfp name
257-
258243-- | Resolve a parsed cabal file into a 'Package', which contains all of
259244-- the info needed for stack to build the 'Package' given the current
260245-- configuration.
@@ -1345,7 +1330,7 @@ findOrGenerateCabalFile pkgDir = do
13451330-- | Generate .cabal file from package.yaml, if necessary.
13461331hpack :: (MonadIO m , MonadUnliftIO m , MonadLogger m , HasRunner env , HasConfig env , MonadReader env m )
13471332 => Path Abs Dir -> m ()
1348- hpack pkgDir = don'tHpackTwice $ do
1333+ hpack pkgDir = do
13491334 let hpackFile = pkgDir </> $ (mkRelFile Hpack. packageConfig)
13501335 exists <- liftIO $ doesFileExist hpackFile
13511336 when exists $ do
@@ -1378,14 +1363,6 @@ hpack pkgDir = don'tHpackTwice $ do
13781363 envOverride <- getMinimalEnvOverride
13791364 let cmd = Cmd (Just pkgDir) command envOverride []
13801365 runCmd cmd Nothing
1381- where
1382- don'tHpackTwice inner = do
1383- ref <- view $ runnerL. to runnerHpackRun
1384- let fp = toFilePath pkgDir
1385- join $ atomicModifyIORef' ref $ \ hs ->
1386- if fp `HashSet.member` hs
1387- then (hs, return () )
1388- else (HashSet. insert fp hs, inner)
13891366
13901367-- | Path for the package's build log.
13911368buildLogPath :: (MonadReader env m , HasBuildConfig env , MonadThrow m )
0 commit comments