@@ -34,6 +34,7 @@ import Control.Concurrent.STM (TVar, atomically, modifyTVar,
3434 newTVarIO , readTVar ,
3535 readTVarIO , writeTVar )
3636import Control.Exception (assert )
37+ import Control.Exception.Enclosed (tryIO )
3738import Control.Monad (join , liftM , unless , void ,
3839 when )
3940import Control.Monad.Catch
@@ -49,6 +50,10 @@ import qualified Data.ByteString.Lazy as L
4950import Data.Either (partitionEithers )
5051import qualified Data.Foldable as F
5152import Data.Function (fix )
53+ import qualified Data.Git as Git
54+ import qualified Data.Git.Ref as Git
55+ import qualified Data.Git.Storage as Git
56+ import qualified Data.Git.Storage.Object as Git
5257import Data.List (intercalate )
5358import Data.List.NonEmpty (NonEmpty )
5459import qualified Data.List.NonEmpty as NE
@@ -58,6 +63,7 @@ import Data.Maybe (maybeToList, catMaybes)
5863import Data.Monoid ((<>) )
5964import Data.Set (Set )
6065import qualified Data.Set as Set
66+ import Data.String (fromString )
6167import qualified Data.Text as T
6268import Data.Text.Encoding (decodeUtf8 )
6369import Data.Typeable (Typeable )
@@ -74,7 +80,8 @@ import System.FilePath ((<.>))
7480import qualified System.FilePath as FP
7581import System.IO (IOMode (ReadMode ),
7682 SeekMode (AbsoluteSeek ), hSeek ,
77- withBinaryFile )
83+ withBinaryFile , openBinaryFile ,
84+ hClose )
7885import System.PosixCompat (setFileMode )
7986import Text.EditDistance as ED
8087
@@ -122,12 +129,16 @@ fetchPackages :: (MonadIO m, MonadBaseControl IO m, MonadReader env m, HasHttpMa
122129 => EnvOverride
123130 -> Set PackageIdentifier
124131 -> m ()
125- fetchPackages menv idents = do
132+ fetchPackages menv idents' = do
126133 resolved <- resolvePackages menv idents Set. empty
127134 ToFetchResult toFetch alreadyUnpacked <- getToFetch Nothing resolved
128135 assert (Map. null alreadyUnpacked) (return () )
129136 nowUnpacked <- fetchPackages' Nothing toFetch
130137 assert (Map. null nowUnpacked) (return () )
138+ where
139+ -- Since we're just fetching tarballs and not unpacking cabal files, we can
140+ -- always provide a Nothing Git SHA
141+ idents = Map. fromList $ map (, Nothing ) $ Set. toList idents'
131142
132143-- | Intended to work for the command line command.
133144unpackPackages :: (MonadIO m , MonadBaseControl IO m , MonadReader env m , HasHttpManager env , HasConfig env , MonadMask m , MonadLogger m )
@@ -140,7 +151,9 @@ unpackPackages menv dest input = do
140151 (names, idents) <- case partitionEithers $ map parse input of
141152 ([] , x) -> return $ partitionEithers x
142153 (errs, _) -> throwM $ CouldNotParsePackageSelectors errs
143- resolved <- resolvePackages menv (Set. fromList idents) (Set. fromList names)
154+ resolved <- resolvePackages menv
155+ (Map. fromList $ map (, Nothing ) idents)
156+ (Set. fromList names)
144157 ToFetchResult toFetch alreadyUnpacked <- getToFetch (Just dest') resolved
145158 unless (Map. null alreadyUnpacked) $
146159 throwM $ UnpackDirectoryAlreadyExists $ Set. fromList $ map toFilePath $ Map. elems alreadyUnpacked
@@ -168,7 +181,7 @@ unpackPackageIdents
168181 => EnvOverride
169182 -> Path Abs Dir -- ^ unpack directory
170183 -> Maybe (Path Rel Dir ) -- ^ the dist rename directory, see: https://github.com/fpco/stack/issues/157
171- -> Set PackageIdentifier
184+ -> Map PackageIdentifier ( Maybe GitSHA1 )
172185 -> m (Map PackageIdentifier (Path Abs Dir ))
173186unpackPackageIdents menv unpackDir mdistDir idents = do
174187 resolved <- resolvePackages menv idents Set. empty
@@ -179,12 +192,13 @@ unpackPackageIdents menv unpackDir mdistDir idents = do
179192data ResolvedPackage = ResolvedPackage
180193 { rpCache :: ! PackageCache
181194 , rpIndex :: ! PackageIndex
195+ , rpGitSHA1 :: ! (Maybe GitSHA1 )
182196 }
183197
184198-- | Resolve a set of package names and identifiers into @FetchPackage@ values.
185199resolvePackages :: (MonadIO m , MonadReader env m , HasHttpManager env , HasConfig env , MonadLogger m , MonadBaseControl IO m , MonadCatch m )
186200 => EnvOverride
187- -> Set PackageIdentifier
201+ -> Map PackageIdentifier ( Maybe GitSHA1 )
188202 -> Set PackageName
189203 -> m (Map PackageIdentifier ResolvedPackage )
190204resolvePackages menv idents0 names0 = do
@@ -203,7 +217,7 @@ resolvePackages menv idents0 names0 = do
203217
204218resolvePackagesAllowMissing
205219 :: (MonadIO m , MonadReader env m , HasHttpManager env , HasConfig env , MonadLogger m , MonadThrow m , MonadBaseControl IO m , MonadCatch m )
206- => Set PackageIdentifier
220+ => Map PackageIdentifier ( Maybe GitSHA1 )
207221 -> Set PackageName
208222 -> m (Set PackageName , Set PackageIdentifier , Map PackageIdentifier ResolvedPackage )
209223resolvePackagesAllowMissing idents0 names0 = do
@@ -214,16 +228,17 @@ resolvePackagesAllowMissing idents0 names0 = do
214228 (Map. lookup name versions))
215229 (Set. toList names0)
216230 (missingIdents, resolved) = partitionEithers $ map (goIdent caches)
217- $ Set . toList
218- $ idents0 <> Set . fromList idents1
231+ $ Map . toList
232+ $ idents0 <> Map . fromList ( map (, Nothing ) idents1)
219233 return (Set. fromList missingNames, Set. fromList missingIdents, Map. fromList resolved)
220234 where
221- goIdent caches ident =
235+ goIdent caches ( ident, mgitsha) =
222236 case Map. lookup ident caches of
223237 Nothing -> Left ident
224238 Just (index, cache) -> Right (ident, ResolvedPackage
225239 { rpCache = cache
226240 , rpIndex = index
241+ , rpGitSHA1 = mgitsha
227242 })
228243
229244data ToFetch = ToFetch
@@ -245,15 +260,42 @@ data ToFetchResult = ToFetchResult
245260withCabalFiles
246261 :: (MonadMask m , MonadIO m , MonadLogger m , MonadReader env m , HasConfig env )
247262 => IndexName
248- -> [(PackageIdentifier , PackageCache , a )]
263+ -> [(PackageIdentifier , PackageCache , Maybe GitSHA1 , a )]
249264 -> (PackageIdentifier -> a -> ByteString -> IO b )
250265 -> m [b ]
251266withCabalFiles name pkgs f = do
252267 indexPath <- configPackageIndex name
253- liftIO $ withBinaryFile (toFilePath indexPath) ReadMode $ \ h ->
254- mapM (goPkg h) pkgs
268+ mgitRepo <- configPackageIndexRepo name
269+ bracket
270+ (liftIO $ openBinaryFile (toFilePath indexPath) ReadMode )
271+ (liftIO . hClose) $ \ h ->
272+ let inner mgit = mapM (goPkg h mgit) pkgs
273+ in case mgitRepo of
274+ Nothing -> inner Nothing
275+ Just repo -> bracket
276+ (liftIO $ Git. openRepo
277+ $ fromString
278+ $ toFilePath repo FP. </> " .git" )
279+ (liftIO . Git. closeRepo)
280+ (inner . Just )
255281 where
256- goPkg h (ident, pc, tf) = do
282+ goPkg h (Just git) (ident, pc, Just (GitSHA1 sha), tf) = do
283+ let ref = Git. fromHex sha
284+ mobj <- liftIO $ tryIO $ Git. getObject git ref True
285+ case mobj of
286+ Right (Just (Git. ObjBlob (Git. Blob bs))) -> liftIO $ f ident tf (L. toStrict bs)
287+ -- fallback when the appropriate SHA isn't found
288+ e -> do
289+ $ logWarn $ mconcat
290+ [ " Did not find .cabal file for "
291+ , T. pack $ packageIdentifierString ident
292+ , " with Git SHA of "
293+ , decodeUtf8 sha
294+ , " \n "
295+ , T. pack $ show e
296+ ]
297+ goPkg h Nothing (ident, pc, Nothing , tf)
298+ goPkg h _mgit (ident, pc, _mgitsha, tf) = liftIO $ do
257299 hSeek h AbsoluteSeek $ fromIntegral $ pcOffset pc
258300 cabalBS <- S. hGet h $ fromIntegral $ pcSize pc
259301 f ident tf cabalBS
@@ -277,13 +319,14 @@ withCabalLoader menv inner = do
277319
278320 loadCaches <- getPackageCachesIO
279321 runInBase <- liftBaseWith $ \ run -> return (void . run)
322+ unlift <- askRunBase
280323
281324 -- TODO in the future, keep all of the necessary @Handle@s open
282325 let doLookup :: PackageIdentifier
283326 -> IO ByteString
284327 doLookup ident = do
285328 caches <- loadCaches
286- eres <- lookupPackageIdentifierExact ident env caches
329+ eres <- unlift $ lookupPackageIdentifierExact ident env cachesCurr
287330 case eres of
288331 Just bs -> return bs
289332 -- Update the cache and try again
@@ -327,7 +370,7 @@ lookupPackageIdentifierExact ident env caches =
327370 Nothing -> return Nothing
328371 Just (index, cache) -> do
329372 [bs] <- flip runReaderT env
330- $ withCabalFiles (indexName index) [(ident, cache, () )]
373+ $ withCabalFiles (indexName index) [(ident, cache, Nothing , () )]
331374 $ \ _ _ bs -> return bs
332375 return $ Just bs
333376
@@ -390,7 +433,7 @@ getToFetch mdest resolvedAll = do
390433 d = pcDownload $ rpCache resolved
391434 targz = T. pack $ packageIdentifierString ident ++ " .tar.gz"
392435 tarball <- configPackageTarball (indexName index) ident
393- return $ Left (indexName index, [(ident, rpCache resolved, ToFetch
436+ return $ Left (indexName index, [(ident, rpCache resolved, rpGitSHA1 resolved, ToFetch
394437 { tfTarball = tarball
395438 , tfDestDir = mdestDir
396439 , tfUrl = case d of
0 commit comments