packages feed

hellage-0.1: hellage-genmeta.hs

{-# LANGUAGE ViewPatterns, BangPatterns #-}

import qualified Codec.Compression.GZip as GZip
import qualified Codec.Archive.Tar as Tar
import qualified Data.ByteString as BS
import qualified Data.ByteString.Lazy as BSL
import qualified Data.ByteString.Lazy.UTF8 as BUL
import qualified Data.Map as Map
import Control.Concurrent.STM.TVar
import Control.Concurrent.STM
import Control.Exception (evaluate)
import Control.Monad
import Data.List
import Data.Maybe
import Hellnet.Meta
import Hellnet.Network
import Hellnet.Storage
import Hellnet.Utils
import Network.HTTP
import Hellnet
import Safe
import System.Directory
import System.Environment
import System.IO
import Text.HJson as JSON
import Text.JSON.JPath


filterNormals a xs = xs ++ [Tar.entryPath a]

queryNodeG :: String -> Node -> IO (Maybe BS.ByteString)
queryNodeG s node = do
	rep <- ((return . Just) =<< simpleHTTP (mkRequest GET $ mkUrl node s)) `catch` const (return Nothing)
	return $ maybe Nothing (either (const Nothing) (\rsp -> if rspCode rsp == (2,0,0) then Just (rspBody rsp) else Nothing)) rep

main = do
	hSetBuffering stdout NoBuffering
	args <- getArgs
	let tempFileName = "/tmp/hellage-temp.json"
	case args of
		[keyname, metaname] -> do
			keyId <- resolveKeyName $ keyname
			putStrLn "Getting index..."
			targz <- queryNodeGet "/packages/archive/00-index.tar.gz" ("hackage.haskell.org", 80) >>= (return . fromMaybe (error "Couldn't download index"))
			indexLink <- insertData Nothing targz
			let tar = GZip.decompress targz
			let entries = Tar.foldEntries (filterNormals) [] (error "Tar unpacking error") $ Tar.read tar
			hellageMetaM <- getMeta keyId metaname
			let hellageMeta = fromMaybe (emptyMeta {
				metaName = metaname,
				keyID = keyId
				}) hellageMetaM
			metaContentM <- findMetaContent hellageMeta
			let metaContentClean = fromMaybe (JObject Map.empty) metaContentM
			let metaContent = jPathModify' "index" (const $ JString $ show indexLink) metaContentClean
			!jsP <- catch (readFile tempFileName) (const $ return "{}")
			let jsParsed = fromMaybe (either (const JNull) (id) $ fromString jsP)
				$ headMay $ jPath' "packages" metaContent
			metaVar <- atomically $ newTVar jsParsed
			let getPackageTar _ path = case explode '/' path of
				[".", package, version, _] -> do
					js <- atomically $ readTVar metaVar
					case jPath' (intercalate "/" [package,version]) js of
						[_] -> do
							putStrLn $ "Found in temp:" ++ show (package, version)
						[] -> do
							let queryString = "/packages/archive/" ++ package ++ "/" ++ version ++ "/" ++ package ++ "-" ++ version ++ ".tar.gz"
							putStr $ "Getting " ++ queryString ++ "..."
							packagetarM <- queryNodeG queryString ("hackage.haskell.org", 80)
							putStrLn "got."
							case packagetarM of
								Just packagetar -> do
									putStr $ "Inserting " ++ show (package, version) ++ "..."
									packageURI <- insertData Nothing $ BSL.pack $ BS.unpack $ packagetar
									putStr "Writing JSON..."
									let js' = jPathModify' (intercalate "/" [package,version]) (const $ JString $ show $ packageURI) js
									writeFile tempFileName $ JSON.toString js'
									atomically $ writeTVar metaVar js'
									putStrLn "wrote."
									return ()
								otherwise -> return ()
							return ()
				otherwise -> return ()
			foldM (getPackageTar) () entries
			finalJs <- catch (readFile tempFileName) (const $ return $ JSON.toString metaContent) >>= return . either (const $ JObject Map.empty) (id) . JSON.fromString
			newMetaURI <- insertData Nothing $ BUL.fromString $ JSON.toString $ jPathModify' "packages" (const finalJs) metaContent
			newMeta <- regenMeta hellageMeta { contentURI = newMetaURI }
			case newMeta of
				Nothing -> error "Failed to sign meta. Check if you have private key."
				Just m -> do
					storeMeta m
					catch (removeFile tempFileName) (const $ return ())
					putStrLn "Success."
		otherwise -> error "Usage: genMeta.hs <key id or alias> <meta name>"