@@ -26,8 +26,10 @@ import Control.Monad.Trans.Control (liftBaseWith)
2626import qualified Data.ByteString as S
2727import qualified Data.ByteString.Char8 as S8
2828import qualified Data.ByteString.Lazy as L
29+ import Data.Char (toLower )
2930import Data.Data (Data , Typeable , cast , gmapT )
3031import Data.Either (partitionEithers )
32+ import Data.IORef (newIORef , readIORef , writeIORef )
3133import Data.List
3234import Data.List.Extra (nubOrd )
3335import Data.List.NonEmpty (NonEmpty )
@@ -42,8 +44,10 @@ import qualified Data.Text.Lazy as TL
4244import qualified Data.Text.Lazy.Encoding as TLE
4345import Data.Time.Clock.POSIX
4446import Distribution.Package (Dependency (.. ))
47+ import qualified Distribution.PackageDescription as Cabal
4548import qualified Distribution.PackageDescription.Check as Check
4649import Distribution.PackageDescription.PrettyPrint (showGenericPackageDescription )
50+ import Distribution.Text (display )
4751import Distribution.Version (simplifyVersionRange , orLaterVersion , earlierVersion )
4852import Distribution.Version.Extra
4953import Path
@@ -91,17 +95,25 @@ getSDistTarball
9195 :: (StackM env m , HasEnvConfig env )
9296 => Maybe PvpBounds -- ^ Override Config value
9397 -> Path Abs Dir -- ^ Path to local package
94- -> m (FilePath , L. ByteString ) -- ^ Filename and tarball contents
98+ -> m (FilePath , L. ByteString , Maybe (PackageIdentifier , L. ByteString ))
99+ -- ^ Filename, tarball contents, and option cabal file revision to upload
95100getSDistTarball mpvpBounds pkgDir = do
96101 config <- view configL
97- let pvpBounds = fromMaybe (configPvpBounds config) mpvpBounds
102+ let PvpBounds pvpBounds asRevision = fromMaybe (configPvpBounds config) mpvpBounds
98103 tweakCabal = pvpBounds /= PvpBoundsNone
99104 pkgFp = toFilePath pkgDir
100105 lp <- readLocalPackage pkgDir
101106 $ logInfo $ " Getting file list for " <> T. pack pkgFp
102107 (fileList, cabalfp) <- getSDistFileList lp
103108 $ logInfo $ " Building sdist tarball for " <> T. pack pkgFp
104109 files <- normalizeTarballPaths (lines fileList)
110+
111+ -- We're going to loop below and eventually find the cabal
112+ -- file. When we do, we'll upload this reference, if the
113+ -- mpvpBounds value indicates that we should be uploading a cabal
114+ -- file revision.
115+ cabalFileRevisionRef <- liftIO (newIORef Nothing )
116+
105117 -- NOTE: Could make this use lazy I/O to only read files as needed
106118 -- for upload (both GZip.compress and Tar.write are lazy).
107119 -- However, it seems less error prone and more predictable to read
@@ -116,8 +128,16 @@ getSDistTarball mpvpBounds pkgDir = do
116128 packWith f isDir fp = liftIO $ f (pkgFp FP. </> fp) =<< tarPath isDir fp
117129 packDir = packWith Tar. packDirectoryEntry True
118130 packFile fp
131+ -- This is a cabal file, we're going to tweak it, but only
132+ -- tweak it as a revision.
133+ | tweakCabal && isCabalFp fp && asRevision = do
134+ lbsIdent <- getCabalLbs pvpBounds (Just 1 ) $ toFilePath cabalfp
135+ liftIO (writeIORef cabalFileRevisionRef (Just lbsIdent))
136+ packWith packFileEntry False fp
137+ -- Same, except we'll include the cabal file in the
138+ -- original tarball upload.
119139 | tweakCabal && isCabalFp fp = do
120- lbs <- getCabalLbs pvpBounds $ toFilePath cabalfp
140+ (_ident, lbs) <- getCabalLbs pvpBounds Nothing $ toFilePath cabalfp
121141 currTime <- liftIO getPOSIXTime -- Seconds from UNIX epoch
122142 tp <- liftIO $ tarPath False fp
123143 return $ (Tar. fileEntry tp lbs) { Tar. entryTime = floor currTime }
@@ -127,11 +147,16 @@ getSDistTarball mpvpBounds pkgDir = do
127147 pkgId = packageIdentifierString (packageIdentifier (lpPackage lp))
128148 dirEntries <- mapM packDir (dirsFromFiles files)
129149 fileEntries <- mapM packFile files
130- return (tarName, GZip. compress (Tar. write (dirEntries ++ fileEntries)))
150+ mcabalFileRevision <- liftIO (readIORef cabalFileRevisionRef)
151+ return (tarName, GZip. compress (Tar. write (dirEntries ++ fileEntries)), mcabalFileRevision)
131152
132153-- | Get the PVP bounds-enabled version of the given cabal file
133- getCabalLbs :: (StackM env m , HasEnvConfig env ) => PvpBounds -> FilePath -> m L. ByteString
134- getCabalLbs pvpBounds fp = do
154+ getCabalLbs :: (StackM env m , HasEnvConfig env )
155+ => PvpBoundsType
156+ -> Maybe Int -- ^ optional revision
157+ -> FilePath
158+ -> m (PackageIdentifier , L. ByteString )
159+ getCabalLbs pvpBounds mrev fp = do
135160 bs <- liftIO $ S. readFile fp
136161 (_warnings, gpd) <- readPackageUnresolvedBS Nothing bs
137162 (_, sourceMap) <- loadSourceMap AllowNoTargets defaultBuildOptsCLI
@@ -143,7 +168,24 @@ getCabalLbs pvpBounds fp = do
143168 }
144169 sourceMap
145170 let gpd' = gtraverseT (addBounds sourceMap installedMap) gpd
146- return $ TLE. encodeUtf8 $ TL. pack $ showGenericPackageDescription gpd'
171+ gpd'' =
172+ case mrev of
173+ Nothing -> gpd'
174+ Just rev -> gpd'
175+ { Cabal. packageDescription
176+ = (Cabal. packageDescription gpd')
177+ { Cabal. customFieldsPD
178+ = ((" x-revision" , show rev): )
179+ $ filter (\ (x, _) -> map toLower x /= " x-revision" )
180+ $ Cabal. customFieldsPD
181+ $ Cabal. packageDescription gpd'
182+ }
183+ }
184+ ident <- parsePackageIdentifierFromString $ display $ Cabal. package $ Cabal. packageDescription gpd''
185+ return
186+ ( ident
187+ , TLE. encodeUtf8 $ TL. pack $ showGenericPackageDescription gpd''
188+ )
147189 where
148190 addBounds :: SourceMap -> InstalledMap -> Dependency -> Dependency
149191 addBounds sourceMap installedMap dep@ (Dependency cname range) =
0 commit comments