foliage/app/Foliage/CmdImportIndex.hs

110 lines
4.2 KiB
Haskell
Raw Normal View History

2022-05-19 10:01:57 +03:00
module Foliage.CmdImportIndex
( cmdImportIndex,
)
where
import Codec.Archive.Tar qualified as Tar
import Codec.Archive.Tar.Entry qualified as Tar
import Data.ByteString.Lazy qualified as BSL
import Data.Foldable (for_)
import Data.List (isSuffixOf)
import Data.Map.Strict (Map)
import Data.Map.Strict qualified as M
import Data.Maybe (fromMaybe)
import Data.Time.Clock.POSIX (posixSecondsToUTCTime)
2022-05-19 09:51:21 +03:00
import Distribution.Package (PackageIdentifier (PackageIdentifier, pkgVersion), pkgName)
import Distribution.Parsec (simpleParsec)
import Distribution.Pretty (prettyShow)
import Distribution.Types.PackageName (unPackageName)
import Foliage.Meta
import Foliage.Options
2022-05-16 11:54:27 +03:00
import System.Directory (createDirectoryIfMissing)
import System.Environment (getEnv)
import System.FilePath
2022-05-19 10:01:57 +03:00
cmdImportIndex :: ImportIndexOptions -> IO ()
cmdImportIndex opts = do
putStrLn "EXPERIMENTAL. Import the Hackage index from $HOME/.cabal. Make sure you have done `cabal update` recently."
home <- getEnv "HOME"
entries <- Tar.read <$> BSL.readFile (home </> ".cabal/packages/hackage.haskell.org/01-index.tar")
2022-05-19 10:01:57 +03:00
m <- importIndex indexfilter entries M.empty
for_ (M.toList m) $ uncurry finalise
2022-05-19 10:01:57 +03:00
where
indexfilter = case importOptsFilter opts of
Nothing -> const True
(Just f) -> mkFilter f
mkFilter (ImportFilter pn Nothing) = (== pn) . unPackageName . pkgName
mkFilter (ImportFilter pn (Just pv)) = (&&) <$> (== pn) . unPackageName . pkgName <*> (== pv) . prettyShow . pkgVersion
importIndex ::
Show e =>
2022-05-19 09:51:21 +03:00
(PackageIdentifier -> Bool) ->
Tar.Entries e ->
2022-05-19 09:51:21 +03:00
Map PackageIdentifier PackageVersionMeta ->
IO (Map PackageIdentifier PackageVersionMeta)
importIndex f (Tar.Next e es) m =
case isCabalFile e of
Just (pkgId, contents, time)
| f pkgId ->
do
2022-05-19 09:51:21 +03:00
putStrLn $ "Found cabal file " ++ prettyShow pkgId ++ " with timestamp " ++ show time
2022-05-16 11:54:27 +03:00
let -- new package
go Nothing =
pure $
Just $
PackageVersionMeta
{ packageVersionSource = TarballSource (pkgIdToHackageUrl pkgId) Nothing,
packageVersionTimestamp = Just time,
packageVersionRevisions = [],
packageVersionForce = False
2022-05-16 11:54:27 +03:00
}
-- Existing package, new revision
go (Just sm) = do
let revnum = 1 + fromMaybe 0 (latestRevisionNumber sm)
newRevision = RevisionMeta {revisionNumber = revnum, revisionTimestamp = time}
2022-05-16 11:54:27 +03:00
-- Repeatedly adding at the end of a list is bad performance but good for the moment.
let sm' = sm {packageVersionRevisions = packageVersionRevisions sm ++ [newRevision]}
2022-05-19 09:51:21 +03:00
let PackageIdentifier pkgName pkgVersion = pkgId
let outDir = "_sources" </> unPackageName pkgName </> prettyShow pkgVersion </> "revisions"
2022-05-16 11:54:27 +03:00
createDirectoryIfMissing True outDir
BSL.writeFile (outDir </> show revnum <.> "cabal") contents
return $ Just sm'
m' <- M.alterF go pkgId m
importIndex f es m'
_ -> importIndex f es m
importIndex _f Tar.Done m =
return m
importIndex _f (Tar.Fail e) _ =
error $ show e
2022-05-19 09:51:21 +03:00
pkgIdToHackageUrl :: PackageIdentifier -> String
pkgIdToHackageUrl pkgId =
"https://hackage.haskell.org/package" </> prettyShow pkgId </> prettyShow pkgId <.> "tar.gz"
finalise ::
2022-05-19 09:51:21 +03:00
PackageIdentifier ->
PackageVersionMeta ->
IO ()
2022-05-19 09:51:21 +03:00
finalise PackageIdentifier {pkgName, pkgVersion} meta = do
let dir = "_sources" </> unPackageName pkgName </> prettyShow pkgVersion
2022-05-16 11:54:27 +03:00
createDirectoryIfMissing True dir
writePackageVersionMeta (dir </> "meta.toml") meta
isCabalFile ::
Tar.Entry ->
2022-05-19 09:51:21 +03:00
Maybe (PackageIdentifier, BSL.ByteString, UTCTime)
isCabalFile
Tar.Entry
{ Tar.entryTarPath = Tar.fromTarPath -> path,
Tar.entryContent = Tar.NormalFile contents _,
Tar.entryTime = posixSecondsToUTCTime . fromIntegral -> time
}
| ".cabal" `isSuffixOf` path =
let [pkgName, pkgVersion, _] = splitDirectories path
2022-05-19 09:51:21 +03:00
Just name = simpleParsec pkgName
Just version = simpleParsec pkgVersion
packageId = PackageIdentifier name version
in Just (packageId, contents, time)
isCabalFile _ = Nothing