{-# LANGUAGE LambdaCase #-}
module Main
( main
) where
import Control.Monad (when)
import Data.Semigroup ((<>))
import Data.Version (showVersion)
import System.Exit (die)
import System.IO (IOMode(ReadMode), hGetLine, hPrint, stderr, withFile)
import Options.Applicative
( Parser
, (<**>)
, (<|>)
, auto
, execParser
, flag'
, fullDesc
, header
, help
, helper
, info
, long
, metavar
, option
, optional
, short
, strOption
, switch
)
import System.Directory (createDirectoryIfMissing)
import System.Environment.XDG.BaseDir (getUserConfigDir, getUserConfigFile)
import qualified Web.OpenWeatherMap.Client as Client
import Web.OpenWeatherMap.Types.Location (Location(..))
import Paths_openweathermap (version) -- from cabal
import Print (printCurrectWeather, printForecastWeather)
appName :: String
appName = "openweathermap"
parseLocation :: Parser Location
parseLocation = byName <|> byCoord
where
byName =
Name <$>
strOption
(long "query" <> short 'q' <> metavar "STRING" <>
help "City name, e. g. Santiago or Santiago,CU")
byCoord =
Coord <$>
option
auto
(long "lat" <> metavar "NUM" <> help "Latitude in decimal degrees") <*>
option
auto
(long "lon" <> metavar "NUM" <> help "Longitude in decimal degrees")
data ApiKey
= ApiKeyFile FilePath
| ApiKey String
parseApiKey :: Parser ApiKey
parseApiKey = fromFile <|> inCmdLine
where
fromFile =
ApiKeyFile <$>
strOption
(long "api-key-file" <> short 'K' <> metavar "APIKEYFILE" <>
help "Read API key from this file")
inCmdLine =
ApiKey <$>
strOption
(long "api-key" <> short 'k' <> metavar "APIKEY" <> help "API key")
data Weather
= Current
| Forecast
parseWeather :: Parser Weather
parseWeather =
flag'
Current
(long "current" <> short 'n' <> help "current weather (default)") <|>
flag' Forecast (long "forecast" <> short 'f' <> help "forecast weather") <|>
pure Current
data Config =
Config
{ apikey :: Maybe ApiKey
, location :: Location
, weather :: Weather
, debug :: Bool
}
parseConfig :: Parser Config
parseConfig =
Config <$> optional parseApiKey <*> parseLocation <*> parseWeather <*>
switch (long "debug" <> short 'd' <> help "Enable debug")
getApiKey :: Maybe ApiKey -> IO String
getApiKey (Just (ApiKey key)) = return key
getApiKey (Just (ApiKeyFile f)) = withFile f ReadMode hGetLine
getApiKey Nothing = do
createDirectoryIfMissing True =<< getUserConfigDir appName
getUserConfigFile appName "key" >>= getApiKey . Just . ApiKeyFile
run :: Config -> IO ()
run cfg = do
appid <- getApiKey . apikey $ cfg
case weather cfg of
Current ->
Client.getWeather appid (location cfg) >>= \case
Left err -> die $ show err
Right cw -> do
when (debug cfg) $ hPrint stderr cw
printCurrectWeather cw
Forecast ->
Client.getForecast appid (location cfg) >>= \case
Left err -> die $ show err
Right fw -> do
when (debug cfg) $ hPrint stderr fw
printForecastWeather fw
main :: IO ()
main = run =<< execParser opts
where
opts = info (parseConfig <**> helper) (fullDesc <> header desc)
desc =
"openweathermap " ++
showVersion version ++
" - command-line client for https://openweathermap.org/api"