module Handler.StackageHome where import Data.BlobStore (storeExists) import Import import Data.Time (FormatTime) import Data.Slug (SnapSlug) import qualified Database.Esqueleto as E import Handler.PackageList (cachedWidget) getStackageHomeR :: SnapSlug -> Handler Html getStackageHomeR slug = do stackage <- runDB $ do Entity _ stackage <- getBy404 $ UniqueSnapshot slug return stackage hasBundle <- storeExists $ SnapshotBundle $ stackageIdent stackage let minclusive = if "inclusive" `isSuffixOf` stackageTitle stackage then Just True else if "exclusive" `isSuffixOf` stackageTitle stackage then Just False else Nothing base = maybe 0 (const 1) minclusive :: Int Entity sid _stackage <- runDB $ getBy404 $ UniqueSnapshot slug defaultLayout $ do setTitle $ toHtml $ stackageTitle stackage cachedWidget (20 * 60) ("package-list-" ++ toPathPiece slug) $ do let maxPackages = 5000 (packageListClipped, packages') <- handlerToWidget $ runDB $ do packages' <- E.select $ E.from $ \(u,m,p) -> do E.where_ $ (m E.^. MetadataName E.==. u E.^. UploadedName) E.&&. (m E.^. MetadataName E.==. p E.^. PackageName') E.&&. (p E.^. PackageStackage E.==. E.val sid) E.orderBy [E.asc $ u E.^. UploadedName] E.groupBy ( u E.^. UploadedName , m E.^. MetadataSynopsis ) E.limit maxPackages return ( u E.^. UploadedName , m E.^. MetadataSynopsis , E.max_ (p E.^. PackageVersion) , E.max_ $ E.case_ [ ( p E.^. PackageHasHaddocks , p E.^. PackageVersion ) ] (E.val (Version "")) ) packageCount <- count [PackageStackage ==. sid] let packageListClipped = packageCount > maxPackages return (packageListClipped, packages') let packages = flip map packages' $ \(name, syn, latestVersion, forceNotNull -> mversion) -> ( E.unValue name , fmap unVersion $ E.unValue latestVersion , strip $ E.unValue syn , (<$> mversion) $ \version -> HaddockR slug $ return $ concat [ toPathPiece $ E.unValue name , "-" , version ] ) forceNotNull (E.Value Nothing) = Nothing forceNotNull (E.Value (Just (Version v))) | null v = Nothing | otherwise = Just v $(widgetFile "stackage-home") where strip x = fromMaybe x (stripSuffix "." x) getStackageMetadataR :: SnapSlug -> Handler TypedContent getStackageMetadataR slug = do Entity sid _ <- runDB $ getBy404 $ UniqueSnapshot slug respondSourceDB typePlain $ do sendChunkBS "Override packages\n" sendChunkBS "=================\n" stream sid True sendChunkBS "\nPackages from Hackage\n" sendChunkBS "=====================\n" stream sid False where stream sid isOverwrite = selectSource [ PackageStackage ==. sid , PackageOverwrite ==. isOverwrite ] [ Asc PackageName' , Asc PackageVersion ] $= mapC (Chunk . toBuilder . showPackage) showPackage (Entity _ p) = concat [ toPathPiece $ packageName' p , "-" , toPathPiece $ packageVersion p , "\n" ] getStackageCabalConfigR :: SnapSlug -> Handler TypedContent getStackageCabalConfigR slug = do Entity sid _ <- runDB $ getBy404 $ UniqueSnapshot slug render <- getUrlRender mdownload <- lookupGetParam "download" when (mdownload == Just "true") $ addHeader "Content-Disposition" "attachment; filename=cabal.config" mglobal <- lookupGetParam "global" let isGlobal = mglobal == Just "true" respondSourceDB typePlain $ stream isGlobal render sid where stream isGlobal render sid = selectSource [ PackageStackage ==. sid ] [ Asc PackageName' , Asc PackageVersion ] $= (if isGlobal then conduitGlobal else conduitLocal) render conduitGlobal render = do headerGlobal render mapC (Chunk . showPackageGlobal) conduitLocal render = do headerLocal render goFirst mapC (Chunk . showPackageLocal) yield $ Chunk $ toBuilder '\n' headerGlobal render = yield $ Chunk $ toBuilder (asText "-- Stackage snapshot from: ") ++ toBuilder (render $ SnapshotR slug StackageHomeR) ++ toBuilder (asText "\n-- Please place these contents in your global cabal config file.\n-- To only use tested packages, uncomment the following line\n-- and comment out other remote-repo lines:\n-- remote-repo: stackage-") ++ toBuilder (toPathPiece slug) ++ toBuilder ':' ++ toBuilder (render $ SnapshotR slug StackageHomeR) ++ toBuilder '\n' headerLocal render = yield $ Chunk $ toBuilder (asText "-- Stackage snapshot from: ") ++ toBuilder (render $ SnapshotR slug StackageHomeR) ++ toBuilder (asText "\n-- Please place this file next to your .cabal file as cabal.config\n-- To only use tested packages, uncomment the following line:\n-- remote-repo: stackage-") ++ toBuilder (toPathPiece slug) ++ toBuilder ':' ++ toBuilder (render $ SnapshotR slug StackageHomeR) ++ toBuilder '\n' constraint p | Just True <- packageCore p = toBuilder $ asText " installed" | otherwise = toBuilder (asText " ==") ++ toBuilder (toPathPiece $ packageVersion p) showPackageGlobal (Entity _ p) = toBuilder (asText "constraint: ") ++ toBuilder (toPathPiece $ packageName' p) ++ constraint p ++ toBuilder '\n' goFirst = do mx <- await forM_ mx $ \(Entity _ p) -> yield $ Chunk $ toBuilder (asText "constraints: ") ++ toBuilder (toPathPiece $ packageName' p) ++ constraint p showPackageLocal (Entity _ p) = toBuilder (asText ",\n ") ++ toBuilder (toPathPiece $ packageName' p) ++ constraint p yearMonthDay :: FormatTime t => t -> String yearMonthDay = formatTime defaultTimeLocale "%Y-%m-%d" getOldStackageR :: PackageSetIdent -> [Text] -> Handler () getOldStackageR ident pieces = do Entity _ stackage <- runDB $ getBy404 $ UniqueStackage ident case parseRoute ("snapshot" : toPathPiece (stackageSlug stackage) : pieces, []) of Nothing -> notFound Just route -> redirect (route :: Route App) getSnapshotPackagesR :: SnapSlug -> Handler Html getSnapshotPackagesR slug = do Entity sid _stackage <- runDB $ getBy404 $ UniqueSnapshot slug defaultLayout $ do setTitle $ toHtml $ "Package list for " ++ toPathPiece slug cachedWidget (20 * 60) ("package-list-" ++ toPathPiece slug) $ do packages' <- handlerToWidget $ runDB $ E.select $ E.from $ \(u,m,p) -> do E.where_ $ (m E.^. MetadataName E.==. u E.^. UploadedName) E.&&. (m E.^. MetadataName E.==. p E.^. PackageName') E.&&. (p E.^. PackageStackage E.==. E.val sid) E.orderBy [E.asc $ u E.^. UploadedName] E.groupBy ( u E.^. UploadedName , m E.^. MetadataSynopsis ) return ( u E.^. UploadedName , m E.^. MetadataSynopsis , E.max_ $ E.case_ [ ( p E.^. PackageHasHaddocks , p E.^. PackageVersion ) ] (E.val (Version "")) ) let packages = flip map packages' $ \(name, syn, forceNotNull -> mversion) -> ( E.unValue name , mversion , strip $ E.unValue syn , (<$> mversion) $ \version -> HaddockR slug $ return $ concat [ toPathPiece $ E.unValue name , "-" , version ] ) forceNotNull (E.Value Nothing) = Nothing forceNotNull (E.Value (Just (Version v))) | null v = Nothing | otherwise = Just v $(widgetFile "package-list") where strip x = fromMaybe x (stripSuffix "." x) mback = Just (SnapshotR slug StackageHomeR, "Return to snapshot")