packdeps 0.2.0 → 0.3.0
raw patch · 3 files changed
+120/−28 lines, 3 filesdep +aesondep +cautious-filedep ~tarPVP ok
version bump matches the API change (PVP)
Dependencies added: aeson, cautious-file
Dependency ranges changed: tar
API changes (from Hackage documentation)
+ Distribution.PackDeps: DescInfo :: String -> [Dependency] -> PackageIdentifier -> String -> DescInfo
+ Distribution.PackDeps: PackInfo :: Version -> Maybe DescInfo -> EpochTime -> PackInfo
+ Distribution.PackDeps: data PackInfo
+ Distribution.PackDeps: diDeps :: DescInfo -> [Dependency]
+ Distribution.PackDeps: diHaystack :: DescInfo -> String
+ Distribution.PackDeps: diPackage :: DescInfo -> PackageIdentifier
+ Distribution.PackDeps: diSynopsis :: DescInfo -> String
+ Distribution.PackDeps: piDesc :: PackInfo -> Maybe DescInfo
+ Distribution.PackDeps: piEpoch :: PackInfo -> EpochTime
+ Distribution.PackDeps: piVersion :: PackInfo -> Version
Files
- Distribution/PackDeps.hs +11/−7
- packdeps.cabal +4/−2
- tools/packdeps-yesod.hs +105/−19
Distribution/PackDeps.hs view
@@ -21,6 +21,9 @@ , getReverses -- * Helpers , diName+ -- * Internal+ , PackInfo (..)+ , DescInfo (..) ) where import System.Directory (getAppUserDataDirectory)@@ -29,6 +32,7 @@ import Data.List (foldl', group, sort, isInfixOf, isPrefixOf) import Data.Time (UTCTime (UTCTime), addUTCTime) import Data.Maybe (mapMaybe, catMaybes)+import Control.Exception (throw) import Distribution.Package import Distribution.PackageDescription@@ -78,9 +82,9 @@ parseNewest :: L.ByteString -> Newest parseNewest = foldl' addPackage Map.empty . entriesToList . Tar.read -entriesToList :: Tar.Entries -> [Tar.Entry]+entriesToList :: Tar.Entries Tar.FormatError -> [Tar.Entry] entriesToList Tar.Done = []-entriesToList (Tar.Fail s) = error s+entriesToList (Tar.Fail s) = throw s entriesToList (Tar.Next e es) = e : entriesToList es addPackage :: Newest -> Tar.Entry -> Newest@@ -231,8 +235,8 @@ -- | Find all packages depended upon by the given list of packages. deepDeps :: Newest -> [DescInfo] -> [DescInfo]-deepDeps newest dis =- go Set.empty dis+deepDeps newest dis0 =+ go Set.empty dis0 where go _ [] = [] go viewed (di:dis)@@ -243,9 +247,9 @@ viewed' = Set.insert name viewed newDis = mapMaybe getDI $ diDeps di getDI :: Dependency -> Maybe DescInfo- getDI (Dependency (PackageName name) _) = do- pi <- Map.lookup name newest- piDesc pi+ getDI (Dependency (PackageName name') _) = do+ pi' <- Map.lookup name' newest+ piDesc pi' diName :: DescInfo -> String diName =
packdeps.cabal view
@@ -1,5 +1,5 @@ name: packdeps-version: 0.2.0+version: 0.3.0 license: BSD3 license-file: LICENSE author: Michael Snoyman <michael@snoyman.com>@@ -21,7 +21,7 @@ library build-depends: base >= 4 && < 5- , tar >= 0.3.1 && < 0.4+ , tar >= 0.4 && < 0.5 , split >= 0.1.2.3 && < 0.2 , bytestring >= 0.9 && < 0.10 , text >= 0.7 && < 0.12@@ -62,6 +62,8 @@ , hamlet , yesod-newsfeed , yesod >= 0.10+ , cautious-file >= 1.0 && < 1.1+ , aeson >= 0.6 && < 0.7 else Buildable: False
tools/packdeps-yesod.hs view
@@ -1,5 +1,6 @@ {-# LANGUAGE QuasiQuotes, TypeFamilies, OverloadedStrings, MultiParamTypeClasses #-} {-# LANGUAGE TemplateHaskell #-}+import Prelude hiding (writeFile) import Yesod import Yesod.AtomFeed import Yesod.Feed@@ -11,15 +12,22 @@ import Distribution.Package import Distribution.Text hiding (Text) import Control.Arrow-import Distribution.Version (withinRange)+import Distribution.Version (VersionRange, withinRange) import qualified Data.Map as Map import Data.Text (Text, pack, unpack, append) import Text.Hamlet (shamlet) import System.Environment (getArgs) import Data.List (sort)+import Data.Version (Version)+import System.IO.Cautious (writeFileL)+import qualified Data.ByteString.Lazy as L+import Data.Aeson+import Data.Aeson.Types (Parser)+import Control.Monad (mzero)+import Control.Applicative ((<$>), (<*>)) data PD = PD Newest Reverses-mkYesod "PD" [$parseRoutes|+mkYesod "PD" [parseRoutes| /favicon.ico FaviconR GET / RootR GET /feed FeedR GET@@ -32,12 +40,14 @@ /reverse ReverseListR GET /reverse/#Text ReverseR GET |]-instance Yesod PD where approot _ = ""+instance Yesod PD where+ approot = ApprootStatic "" getFaviconR :: Handler () getFaviconR = sendFile "image/x-icon" "favicon.ico" -mainCassius = [$cassius|+mainCassius :: CssUrl (Route PD)+mainCassius = [cassius| body font-family: Arial,Helvetica,sans-serif width: 600px@@ -63,9 +73,10 @@ text-align: center |] +getRootR :: Handler RepHtml getRootR = defaultLayout $ do setTitle "Hackage dependency monitor"- addCassius mainCassius+ addCassius mainCassius :: Widget -- just get rid of a warning by using Widget [whamlet| <h1>Hackage Dependency Monitor <form action="@{FeedR}">@@ -86,8 +97,12 @@ <a href="http://docs.yesodweb.com/">Powered by Yesod |] +isDeep :: Handler Bool isDeep = fmap (== Just "on") $ runInputGet $ iopt textField "deep" +getDeps :: Bool+ -> String+ -> Handler ([DescInfo], [((String, Version), ([(String, String)], UTCTime))]) getDeps deep needle = do PD newest _ <- getYesod let descs' = filterPackages needle newest@@ -110,7 +125,8 @@ let deepR = (FeedR, [("needle", needle), ("deep", "on")]) defaultLayout $ do setTitle $ toHtml title- addCassius [$cassius|body+ addCassius [cassius|+body font-family: Arial,Helvetica,sans-serif width: 600px margin: 2em auto@@ -165,14 +181,19 @@ <a href="http://hackage.haskell.org/package/#{name}">#{name} |] +getFeed2R :: Text -> Handler RepAtomRss getFeed2R needle = do (_, deps) <- getDeps False $ unpack needle feed2Helper needle deps +getFeed2DeepR :: Text -> Handler RepAtomRss getFeed2DeepR needle = do (_, deps) <- getDeps True $ unpack needle feed2Helper needle deps +feed2Helper :: Text+ -> [((String, Version), ([(String, String)], UTCTime))]+ -> Handler RepAtomRss feed2Helper needle deps = do now <- liftIO getCurrentTime newsFeed Feed@@ -185,13 +206,13 @@ , feedDescription = toHtml $ "Newer dependencies for " ++ unpack needle } where- go' ((name, version), (deps, time)) = FeedEntry+ go' ((name, version), (deps', time)) = FeedEntry { feedEntryLink = Feed3R needle (pack name) (pack $ display version) (pack $ show time) , feedEntryUpdated = time , feedEntryTitle = pack $ "Outdated dependencies for " ++ name ++ " " ++ display version , feedEntryContent = [shamlet| <table border="1">- $forall d <- deps+ $forall d <- deps' <tr> <th>#{fst d} <td>#{snd d}@@ -203,16 +224,79 @@ redirect $ "http://hackage.haskell.org/package/" `append` package +main :: IO () main = do args <- getArgs- if args == ["--save-newest"]+ if args == ["--save-reverses"] then do newest <- loadNewest- writeFile "newest" $ show newest+ writeFileL "reverses" $ encode (newest, getReverses newest) else do- newest <- read `fmap` readFile "newest"- warpDebug 5005 $ PD newest $ getReverses newest+ putStrLn "Loading reverses..."+ Just (newest, reverses) <- fmap decode' $ L.readFile "reverses"+ putStrLn "Done"+ warpDebug 5005 $ PD newest reverses +instance ToJSON Version where+ toJSON = toJSONShow+instance FromJSON Version where+ parseJSON = parseJSONRead++toJSONShow :: Show a => a -> Value+toJSONShow = String . pack . show++parseJSONRead :: Read a => Value -> Parser a+parseJSONRead (String t) =+ case reads $ unpack t of+ (v, _):_ -> return v+ _ -> mzero+parseJSON _ = mzero++instance ToJSON VersionRange where+ toJSON = toJSONShow+instance FromJSON VersionRange where+ parseJSON = parseJSONRead++instance ToJSON PackInfo where+ toJSON (PackInfo a b c) = Data.Aeson.object+ [ "version" .= a+ , "desc" .= b+ , "epoch" .= c+ ]++instance FromJSON PackInfo where+ parseJSON (Object v) = PackInfo+ <$> v .: "version"+ <*> v .: "desc"+ <*> v .: "epoch"+ parseJSON _ = mzero++instance ToJSON DescInfo where+ toJSON (DescInfo a b c d) = Data.Aeson.object+ [ "haystack" .= a+ , "deps" .= b+ , "package" .= c+ , "synopsis" .= d+ ]++instance FromJSON DescInfo where+ parseJSON (Object v) = DescInfo+ <$> v .: "haystack"+ <*> v .: "deps"+ <*> v .: "package"+ <*> v .: "synopsis"+ parseJSON _ = mzero++instance ToJSON PackageIdentifier where+ toJSON = toJSONShow+instance FromJSON PackageIdentifier where+ parseJSON = parseJSONRead++instance ToJSON Dependency where+ toJSON = toJSONShow+instance FromJSON Dependency where+ parseJSON = parseJSONRead+ getSpecificR :: Handler RepHtml getSpecificR = do packages' <- lookupGetParams "package"@@ -225,7 +309,8 @@ (_, v, WontAccept cd _) -> Just (v, cd) defaultLayout $ do setTitle $ toHtml title- addCassius [$cassius|body+ addCassius [cassius|+body font-family: Arial,Helvetica,sans-serif width: 600px margin: 2em auto@@ -264,6 +349,7 @@ <p>Invalid package name: #{fst p} |] +getSpecificFeedR :: Text -> Handler RepAtomRss getSpecificFeedR packages' = do PD newest _ <- getYesod let descs = mapMaybe (flip getPackage newest) $ words $ unpack packages'@@ -297,11 +383,11 @@ getReverseListR :: Handler RepHtml getReverseListR = do- PD _ reverse <- getYesod+ PD _ reverse' <- getYesod defaultLayout $ do setTitle "Reverse Dependencies" addCassius mainCassius- addHamlet [$hamlet|+ addHamlet [hamlet| <h1>Reverse Dependencies <p>Please choose a package below to view its reverse dependencies: those packages that depend upon it. This listing will also tell you which packages are incompatible with the current version of the package. <table@@ -309,7 +395,7 @@ <th>Package <th>Total Dependencies <th>Total Outdated Dependencies- $forall p <- Map.toList reverse+ $forall p <- Map.toList reverse' <tr> <td <a href=@{ReverseR $ pack $ fst p}>#{fst p}@@ -327,8 +413,8 @@ getReverseR :: Text -> Handler RepHtml getReverseR dep = do- PD _ reverse <- getYesod- (version, rels) <- maybe notFound return $ Map.lookup (unpack dep) reverse+ PD _ reverse' <- getYesod+ (version, rels) <- maybe notFound return $ Map.lookup (unpack dep) reverse' defaultLayout $ do setTitle [shamlet|Reverse dependencies for #{dep}|] addCassius mainCassius@@ -340,7 +426,7 @@ <th>Accepted versions $forall rel <- rels <tr>- $if Map.member (fst rel) reverse+ $if Map.member (fst rel) reverse' <td><a href=@{ReverseR $ pack $ fst rel}>#{fst rel} $else <td>#{fst rel}