packages feed

hask-home-2006.3.23: hask-home.hs

#!/usr/bin/env runghc

import Control.Exception
import Control.Monad
import Data.Char
import Data.List
import Data.Maybe
import Distribution.PackageDescription
import Distribution.Simple
import Distribution.Simple.Utils
import Prelude hiding (catch)
import System.Directory
import System.Environment
import System.Cmd
import Text.Regex

import Text.XHtml

docDir = "doc"
haddockDirRel = "api"
downloadDir = "download"
haddockDir = docDir ++ "/" ++ haddockDirRel
indexFile = docDir ++ "/" ++ "index.html"

standardPackages = ["base","stm","mtl","fgl","QuickCheck",
                    "Cabal","network","readline","unix","parsec",
                    "haskell98","posix"]

knownPackages = [("fps",("FastPackedString","http://www.cse.unsw.edu.au/~dons/fps.html")),
                 ("Crypto",("The Haskell Cryptographic Library","http://haskell.org/crypto/")),
                 ("HTTP",("The Haskell HTTP package","http://haskell.org/http/")),
                 ("XmlRpc",("HaXR - the Haskell XML-RPC library","http://haskell.org/haxr/")),
                 ("xhtml",("Text.XHtml","http://www.cs.chalmers.se/~bringert/darcs/haskell-xhtml/doc/")),
                 ("cgi",("NewCGI","http://www.cs.chalmers.se/~bringert/darcs/haskell-cgi/doc/"))
                ]

stylesheet = unlines $
 [
  "body { background-color: white; color: black; margin: 0; padding: 0; }",
  "h1, .footer { background-color:silver; color: black; margin: 0; border: 0 solid black; }",
  "h1 { border-bottom-width: thin; padding: 1em; }",
  ".footer { font-size: smaller; text-align:center; border-top-width: thin; padding: 0.25em 1em; }",
  ".footer span { padding: 0 0.25em; } ",
  "hr { display: none; }",
  ".section { padding: 0; margin: 0 5em; }"
 ]

buildHaddock :: PackageDescription -> IO ()
buildHaddock desc = 
    do
    let desc' = desc { description = synopsis desc }
    showExceptions $ withArgs ["haddock","-v"] $ defaultMainNoRead desc'
    let haddockOutputDir = "dist/doc/html"
    rawSystem "rm" ["-rf", haddockDir]
    rawSystem "cp" ["-r", haddockOutputDir, haddockDir]
    return ()
  where
--  formatDesc p = p { description = format (description p) }
--      where format = unlines . map formatLine . lines
--            formatLine l | match "^\\s*\\*" l = "\n" ++ l
--                         | otherwise = l

match :: String -> String -> Bool
match p s = isJust $ matchRegex (mkRegex p) s

distDir :: PackageDescription -> String
distDir desc = showPackageId (package desc)

distFile :: PackageDescription -> String
distFile desc = distDir desc ++ ".tar.gz"

mkTarball :: PackageDescription -> IO ()
mkTarball desc = 
    do
    system ("darcs dist --dist-name=" ++ distDir desc)
    createDirectoryIfMissing True downloadDir
    let f = downloadDir ++ "/" ++ distFile desc
    renameFile (distFile desc) f

makeIndex :: PackageDescription -> String -> Html
makeIndex desc setupProg = (header << hdr) +++ (body << bdy)
  where
  hdr = [thetitle << t, 
         meta ! [name "generator", content "hask-home, http://www.cs.chalmers.se/~bringert/darcs/hask-home/doc/"],
         style ! [thetype "text/css"] << stylesheet
        ]
  t = pkgName (package desc) ++ " - " ++ synopsis desc
  bdy = [h1 << t, des, api, dow, req, ins, mai, lic, foo]
  des = section "Description" [primHtml (description desc)]
  api | not (needsHaddock desc) = noHtml
      | otherwise = section "API Documentation" 
                      [p << hlink (haddockDirRel ++ "/" ++ "index.html")
                                     << "Haddock-generated API documentation"]
  repo = reverse $ drop (length docDir) $ dropWhile (=='/') $ reverse $ homepage desc
  tarball = "../" ++ downloadDir ++ "/" ++ distFile desc
  dow = section "Download" 
         ((if null repo then [] else 
                    [h3 << "Darcs", pre << ("$ darcs get --partial " ++ repo)])
            ++ [h3 << "Tarball",
                   p << hlink tarball (distFile desc)])
  req | null reqs = noHtml
      | otherwise = section "Requirements" [ulist << reqs]
  reqs = catMaybes $ map formatReq (buildDepends desc)
  formatReq d@(Dependency p v)
      | p `elem` standardPackages = Nothing
      | otherwise = Just $ case lookup p knownPackages of
                               Just (n,u) -> li << hlink u n
                               Nothing -> li << p
  ins = section "Installation" 
                  [olist << [li << ("Unpack the sources and enter the source directory:"
                                    +++ pre << [unlines ["$ tar -zxf " ++ distFile desc,
                                                         "$ cd " ++ distDir desc]]),
                             li << ("Configure:"
                                    +++ pre << [unlines ["$ runghc " ++ setupProg ++ " configure"]]),
                             li << ("Build:"
                                    +++ pre << [unlines ["$ runghc " ++ setupProg ++ " build"]]),
                             li << ("Install (as root):"
                                    +++ pre << [unlines ["# runghc " ++ setupProg ++ " install"]])
                            ]
        ]
  mai = section "Maintainer" [p << maintainer desc]
  lic | null (licenseFile desc) = section "License" [p << show (license desc)]
      | otherwise = section "License" 
                       [p << ("See " 
                              +++ (hlink ("../" ++ licenseFile desc) 
                                   << licenseFile desc)
                              +++ ".")]
  validXHtml = thespan << hlink "http://validator.w3.org/check?uri=referer" "Validate XHTML" 
  validCSS = thespan << hlink "http://jigsaw.w3.org/css-validator/check/referer" "Validate CSS" 
  generator = thespan << ("Page generated by " 
              +++ hlink "http://www.cs.chalmers.se/~bringert/darcs/hask-home/doc/" "hask-home")
  foo = thediv ! [theclass "footer"] 
        << [hr, p << [generator +++ " " +++ validXHtml +++ " " +++ validCSS]]
  section h xs = thediv ! [theclass "section"] << ((h2 << [h]):xs)


needsHaddock :: PackageDescription -> Bool
needsHaddock = isJust . library

txt2html :: String -> IO String
txt2html s = 
    do
    let tmpInFile = "txt2html.txt.tmp"
        tmpOutFile = "txt2html.html.tmp"
    writeFile tmpInFile ("\n\n\n"++s)
    rawSystem "txt2tags" ["-H","--target=xhtml","--outfile="++tmpOutFile,tmpInFile]
    s' <- readFile tmpOutFile
    removeFile tmpInFile
    removeFile tmpOutFile
    return s'

desc2html :: PackageDescription -> IO PackageDescription
desc2html desc = 
    do
    d' <- txt2html $ description desc
    return $ desc { description = d' }

findSetup :: IO String
findSetup = do
            b <- doesFileExist "Setup.hs"
            if b then return "Setup.hs"
                 else do
                      b <- doesFileExist "Setup.lhs"
                      if b then return "Setup.lhs"
                           else fail "No setup program found"

hlink :: HTML a => String -> a -> Html
hlink u b = anchor ! [href u] << b

showExceptions a = catch a (\e -> print e >> throw e)

main = do
       packageDesc <- defaultPackageDesc
       desc <- readPackageDescription packageDesc
       createDirectoryIfMissing True docDir
       setupProg <- findSetup
       when (needsHaddock desc) $ buildHaddock desc
       mkTarball desc
       desc' <- desc2html desc
       writeFile indexFile $ renderHtml $ makeIndex desc' setupProg