haskell-te: 603da32a29ab9881890bb137bbb9ceea22f0176e

     1: {-# LANGUAGE OverloadedStrings #-}
     2: import           Control.Lens
     3: import           Data.Aeson
     4: import           Data.Aeson.Lens
     5: import qualified Data.ByteString as BS
     6: import           Data.Char
     7: import           Data.List
     8: import           Data.Semigroup
     9: import           Data.Text.Lens
    10: import           Data.Validation
    11: 
    12: import qualified GetDeps
    13: import qualified SexprHelper
    14: import qualified Types as GD.Types
    15: 
    16: -- Acts like `Either [String] a`, but combines the content
    17: type OrErrors = AccValidation [String]
    18: 
    19: instance (Semigroup e) => Monad (AccValidation e) where
    20:   return = pure
    21:   (AccSuccess x) >>= f = f x
    22:   (AccFailure e) >>= f = AccFailure e
    23: 
    24: -- Read stdin as a JSON array, apply addDeps to each entry and send to stdout
    25: main :: IO ()
    26: main = BS.interact (over _Array go)
    27:   where go vs = case traverse addDeps vs of
    28:                      AccFailure errs -> error (unlines (msg:errs))
    29:                      AccSuccess vs'  -> vs'
    30:         msg   = "getDepsScript: aborting due to errors"
    31: 
    32: -- Add a "dependencies" field containing this entry's dependencies
    33: addDeps :: Value -> OrErrors Value
    34: addDeps v = add <$> deps v
    35:   where add ds = v & _Object . at "dependencies" ?~ toJSON ds
    36: 
    37: -- Looks up the dependencies of an entry, and formats them
    38: deps :: Value -> OrErrors [Value]
    39: deps v = rawDeps v >>= traverse formatDep
    40: 
    41: -- Looks up the "ast" field of an entry, traverses it looking for global
    42: -- names and deduplicates the resulting list
    43: rawDeps :: Value -> OrErrors [GD.Types.Out]
    44: rawDeps v = case v ^? key "ast" . _String . unpacked of
    45:                  Nothing -> AccFailure ["No 'ast' in " ++ show v]
    46:                  Just a  -> AccSuccess (deps' a)
    47:   where deps' = nub . GetDeps.getDeps . SexprHelper.parseSexpr
    48: 
    49: -- Split package fields like "foo-1.2" into package "foo" and version "1.2"
    50: formatDep :: GD.Types.Out -> OrErrors Value
    51: formatDep o = case pair of
    52:                    Nothing     -> AccFailure ["No 'package' in " ++ show dep]
    53:                    Just (p, v) -> AccSuccess $ case v of
    54:                      Just v' -> dep & setP .~ p & setV .~ v'
    55:                      Nothing -> dep & setP .~ p
    56:   where dep  = toJSON o
    57:         pair = dep ^? key "package" . _String . unpacked . to splitOffVersion
    58:         setP = _Object . at "package" . _Just . _String . unpacked
    59:         setV = _Object . at "version" . _Just . _String . unpacked
    60: 
    61: -- Splits the version off a package name (if any)
    62: splitOffVersion :: String -> (String, Maybe String)
    63: splitOffVersion raw = if "-" `isPrefixOf` version
    64:                          then (name, Just (tail version))
    65:                          else (raw,  Nothing)
    66:   where (name, version) = (reverse n, reverse v)
    67:         (v,    n)       = span versionic (reverse raw)
    68:         versionic c     = isNumber c || c `elem` ['-', '.']

Generated by git2html.