code cleanup
[pkg-find-outdated-cabal.git] / Main.hs
1 module Main (main) where
2
3 import qualified Codec.Compression.GZip as GZip
4 import Control.Monad
5 import qualified Data.ByteString.Lazy as Lazy
6 import Data.List
7 import Data.List.Utils
8 import Data.Version
9 import Distribution.Package
10 import Distribution.PackageDescription
11 import Distribution.Query
12 import HSH
13 import System.Directory
14 import System.FilePath
15 import System.FilePath.Glob
16 import Text.ParserCombinators.ReadP
17
18 indexURL :: String
19 indexURL = "http://hackage.haskell.org/packages/archive/00-index.tar.gz"
20
21 pkgsrcPath :: String
22 pkgsrcPath = "/usr/pkgsrc"
23
24 main :: IO ()
25 main = do appDir <- getAppUserDataDirectory "pkg-find-outdated-cabal"
26           createDirectoryIfMissing False appDir
27
28           let indexFile = appDir </> "00-index.tar.gz"
29
30           putStrLn "Downloading the Hackage index..."
31           cwd <- pwd
32           cd appDir
33           runIO ("wget", ["-N", indexURL])
34           cd cwd
35           putStrLn "Done."
36
37           indexBin <- fmap GZip.decompress $ Lazy.readFile indexFile
38           let runQuery q = queryIndex q indexBin
39
40           makefiles <- namesMatching (pkgsrcPath </> "*" </> "*" </> "Makefile")
41           scanPkgs runQuery makefiles
42
43 scanPkgs :: (Query -> [PackageDescription]) -> [FilePath] -> IO ()
44 scanPkgs runQuery = mapM_ scanPkg
45     where
46       scanPkg :: FilePath -> IO ()
47       scanPkg makPath
48           = do mak <- readFile makPath
49                case grep "mk/haskell.mk" (lines mak) of
50                  [] -> return ()
51                  _  -> checkPkg mak
52
53       checkPkg :: String -> IO ()
54       checkPkg mak
55           = case grep "DISTNAME=" (lines mak) of
56               [l] -> let line     = (trd ' ' . trd '\t') l
57                          distname = cut 1 '=' line
58                          name     = extractPkgName distname
59                          ver      = extractPkgVersion distname
60                          pkgId    = PackageIdentifier name ver
61                          query    = Id ((`isNewerThan` pkgId) . package)
62                      in
63                        case runQuery query of
64                          [] -> putStrLn (distname ++ ": is the LATEST")
65                          xs -> let sorted = sortBy cmpVers xs
66                                    latest = last sorted
67                                    lVer   = (pkgVersion . package) latest
68                                in
69                                  putStrLn (distname ++ ": has a newer version " ++ showVersion lVer)
70               _   -> return ()
71
72       isNewerThan :: PackageIdentifier -> PackageIdentifier -> Bool
73       isNewerThan a b
74           = pkgName    a == pkgName    b &&
75             pkgVersion a >  pkgVersion b
76
77       cmpVers :: PackageDescription -> PackageDescription -> Ordering
78       cmpVers a b = (pkgVersion . package) a `compare` (pkgVersion . package) b
79
80 extractPkgName :: String -> PackageName
81 extractPkgName = PackageName . head . split "-"
82
83 extractPkgVersion :: String -> Version
84 extractPkgVersion =  take' . readP_to_S parseVersion . last . split "-"
85     where
86       take' ((v, ""):_ ) = v
87       take' (_      :xs) = take' xs
88       take' []           = error "Unparsable version"