module BDCS.API.Recipe(bumpVersion,
getAllRecipeProjects,
parseRecipe,
recipeTOML,
recipeTomlFilename,
recipeBumpVersion,
Recipe(..),
RecipeModule(..))
where
import BDCS.API.TOMLMediaType
import BDCS.API.Utils(caseInsensitive)
import Data.Aeson
import Data.Aeson.Types(Result(..))
import Data.List(nub, sortBy)
import Data.Maybe(fromMaybe)
import qualified Data.SemVer as SV
import Data.String.Conversions(cs)
import qualified Data.Text as T
import Text.Printf(printf)
import Text.Toml(parseTomlDoc)
data Recipe =
Recipe { rName :: String
, rVersion :: Maybe String
, rDescription :: String
, rPackages :: [RecipeModule]
, rModules :: [RecipeModule]
} deriving (Eq, Show)
instance FromJSON Recipe where
parseJSON = withObject "recipe" $ \o -> do
rName <- o .: "name"
rVersion <- o .:? "version"
rDescription <- o .: "description"
rPackages <- o .:? "packages" .!= []
rModules <- o .:? "modules" .!= []
return Recipe{..}
instance ToJSON Recipe where
toJSON Recipe{..} = object [
"name" .= rName
, "version" .= fromMaybe "" rVersion
, "description" .= rDescription
, "packages" .= rPackages
, "modules" .= rModules ]
instance ToTOML Recipe where
toTOML recipe = cs $ recipeTOML recipe
instance FromTOML Recipe where
parseTOML toml = parseRecipe $ cs toml
data RecipeModule =
RecipeModule { rmName :: String
, rmVersion :: String
} deriving (Eq, Show)
instance FromJSON RecipeModule where
parseJSON = withObject "recipe module" $ \o -> do
rmName <- o .: "name"
rmVersion <- o .: "version"
return RecipeModule{..}
instance ToJSON RecipeModule where
toJSON RecipeModule{..} = object [
"name" .= rmName
, "version" .= rmVersion ]
parseRecipe :: T.Text -> Either String Recipe
parseRecipe xs =
case parseTomlDoc "" xs of
Left err -> Left ("Parsing TOML document failed. " ++ show err)
Right table -> do
let jsonValue = toJSON table
case (fromJSON jsonValue :: Result Recipe) of
Error err -> Left ("Converting from JSON to Recipe failed. " ++ show err)
Success r -> Right r
recipeTOML :: Recipe -> T.Text
recipeTOML Recipe{..} = T.concat [nameText, versionText, descriptionText, modulesText, packagesText]
where
nameText = T.pack $ printf "name = \"%s\"\n" rName
versionText = T.pack $ printf "version = \"%s\"\n" $ fromMaybe "" rVersion
descriptionText = T.pack $ printf "description = \"%s\"\n\n" rDescription
moduleText :: T.Text -> RecipeModule -> T.Text
moduleText name RecipeModule{..} = T.pack $ printf "[[%s]]\nname = \"%s\"\nversion = \"%s\"\n\n" name rmName rmVersion
packagesText = T.concat $ map (moduleText "packages") rPackages
modulesText = T.concat $ map (moduleText "modules") rModules
recipeTomlFilename :: String -> T.Text
recipeTomlFilename name = T.append (T.replace " " "-" (T.pack name)) ".toml"
bumpVersion :: Maybe String -> Maybe String -> Either String String
bumpVersion Nothing Nothing = Right "0.0.1"
bumpVersion Nothing (Just new_ver) =
case SV.fromText (T.pack new_ver) of
Right _ -> Right new_ver
Left _ -> Left ("Failed to parse version: " ++ new_ver)
bumpVersion (Just prev_ver) Nothing =
case SV.fromText (T.pack prev_ver) of
Right version -> Right $ SV.toString $ SV.incrementPatch version
Left _ -> Left ("Failed to parse version: " ++ prev_ver)
bumpVersion (Just prev_ver) (Just new_ver)
| prev_ver == new_ver = bumpNewVer
| otherwise = checkNewVer
where
bumpNewVer =
case SV.fromText (T.pack new_ver) of
Right version -> Right $ SV.toString $ SV.incrementPatch version
Left _ -> Left ("Failed to parse version: " ++ new_ver)
checkNewVer =
case SV.fromText (T.pack new_ver) of
Right _ -> Right new_ver
Left _ -> Left ("Failed to parse version: " ++ new_ver)
recipeBumpVersion :: Recipe -> Maybe String -> Either String Recipe
recipeBumpVersion recipe prev_version = case bumpVersion prev_version (rVersion recipe) of
Right version -> Right recipe { rVersion = Just version }
Left err -> Left err
getAllRecipeProjects :: Recipe -> [String]
getAllRecipeProjects recipe = sortBy caseInsensitive $ nub $ map rmName (rModules recipe ++ rPackages recipe)