packages feed

hub-1.0.0: Hub/SaveLoad.hs

--
-- >>> Hub.SaveLoad <<<
--
-- This module saves the hub configuration in an archive type and loads
-- an archive file, performing some analysis on the target Hub to be loaded
-- (if there is one).
--
-- (c) 2011-2012 Chris Dornan


module Hub.SaveLoad
    ( save
    , PkgDiffs(..)
    , load
    ) where

import           Data.Char
import qualified Data.Map               as Map
import           Data.List
import           Hub.Oops
import           Hub.Hub
import           Hub.Directory
import           Hub.Discover
import           Hub.PackageDB


-- Generates the archive on the standard output.

save :: Hub -> IO ()
save hub =
     do pdb <- packageDB hub
        let cts = unlines $ hdr : map (prettyPkgNick . iden2nick) (Map.keys pdb)
        putStr cts
      where
        hdr = "^=" ++ maybe (name__HUB hub) glb_hnUHB (usr___HUB hub)

data PkgDiffs = PD { hubPD :: Hub, surPD, msgPD, allPD :: [PkgNick] }
                                                                deriving (Show)

-- Takes the name of the hub to be loaded, the existing hub (if it exists)
-- an a flag indicating whether the hub is bing loaded or verified, and
-- reads in the archive from the standard input and returns the new
-- and the packages it is missing and the packages to be added.
--
--   * If it is not passed a hub then it creates a new one.
--
--   * If it is passed a hub which does not have the right global database
--     then it will remove and recreate the hub with the right global databse
--     if loading or generate an error if verifying.

load :: HubName -> Maybe Hub -> Bool -> IO PkgDiffs
load hn mb_hub0 vy =
     do mb_prs   <- parse_input
        (gh,nks) <- case mb_prs of
                       Nothing -> oops HubO $ "parse error"
                       Just pr -> return pr
        mb_hub <-
            case mb_hub0 of
              Nothing  -> return Nothing
              Just hub ->
                case usr___HUB hub of
                  Just uhb | gh==glb_hnUHB uhb -> return $ Just hub
                           | not vy            -> r_noth $ deleteHub hub
                  _                            -> oops HubO mm_msg
        g_hub <- discover $ Just gh
        hub   <- case mb_hub of
                   Nothing  -> createHub' False g_hub hn False
                   Just hub -> return hub
        nks0 <- (map iden2nick . Map.keys) `fmap` packageDB hub
        return $ PD hub (nks0\\nks) (nks\\nks0) nks
      where
        r_noth = fmap (const Nothing)
        mm_msg = "global hub mismatch"

parse_input :: IO (Maybe (HubName,[PkgNick]))
parse_input =
     do cts <- getContents
        return $ parse_har cts

parse_har :: String -> Maybe (HubName,[PkgNick])
parse_har cts =
     do (gh,r) <- hdr_p $ pp cts
        (,) gh `fmap` bdy_p r

hdr_p :: [String] -> Maybe (HubName,[String])
hdr_p []       = Nothing
hdr_p (ln:lns) =
        case words ln of
          ['^':'=':hn]
            | isHubName hn == Just GlbHK
                -> Just (hn,lns)
          _     -> Nothing

bdy_p :: [String] -> Maybe [PkgNick]
bdy_p []       = Just []
bdy_p (ln:lns) =
        case words ln of
          [w] | Just nk <- parsePkgNick' w ->
             do nks <- bdy_p lns
                return $ nk:nks
          _ ->  Nothing

pp :: String -> [String]
pp = filter (not . all isSpace) . map sc . lines
      where
        sc ln = foldr cmt "" ln

        cmt '#' _ = ""
        cmt '-' t = case t of
                      '-':_ -> ""
                      _     -> '-':t
        cmt c   t = c:t