packages feed

cachix-0.2.1: src/Cachix/Client/OptionsParser.hs

module Cachix.Client.OptionsParser
  ( CachixCommand(..)
  , CachixOptions(..)
  , UseOptions(..)
  , PushArguments(..)
  , PushOptions(..)
  , BinaryCacheName
  , getOpts
  ) where

import Data.Bifunctor            (first)
import Protolude hiding          (option)
import URI.ByteString            (URIRef, Absolute, parseURI, strictURIParserOptions
                                 , serializeURIRef')
import Options.Applicative

import qualified Cachix.Client.Config as Config
import Cachix.Client.URI         (defaultCachixURI)

data CachixOptions = CachixOptions
  { host :: URIRef Absolute
  , configPath :: Config.ConfigPath
  , verbose :: Bool
  } deriving Show

parserCachixOptions :: Config.ConfigPath -> Parser CachixOptions
parserCachixOptions defaultConfigPath = CachixOptions
  <$> option uriOption ( long "host"
                       <> value defaultCachixURI
                       <> metavar "URI"
                       <> showDefaultWith (toS . serializeURIRef')
                       <> help "Host to connect to"
                       )
 <*> strOption ( long "config"
              <> short 'c'
              <> value defaultConfigPath
              <> metavar "CONFIGPATH"
              <> showDefault
              <> help "Cachix configuration file"
              )
  <*> switch ( long "verbose"
             <> short 'v'
             <> help "Verbose mode"
             )

uriOption :: ReadM (URIRef Absolute)
uriOption = eitherReader $ \s ->
  first show $ parseURI strictURIParserOptions $ toS s

type BinaryCacheName = Text

data CachixCommand
  = AuthToken Text
  | Create BinaryCacheName
  | GenerateKeypair BinaryCacheName
  | Push PushArguments
  | Use BinaryCacheName UseOptions
  | Version
  deriving Show

data UseOptions = UseOptions
  { useNixOS :: Bool
  , useNixOSFolder :: FilePath
  } deriving Show

data PushArguments
  = PushPaths PushOptions Text [Text]
  | PushWatchStore PushOptions Text
  deriving Show

data PushOptions = PushOptions
  { compressionLevel :: Int
  } deriving Show

parserCachixCommand :: Parser CachixCommand
parserCachixCommand = subparser $
  command "authtoken" (infoH authtoken (progDesc "Configure token for authentication to cachix.org")) <>
  command "create" (infoH create (progDesc "DEPRECATED: Go to https://cachix.org instead")) <>
  command "generate-keypair" (infoH generateKeypair (progDesc "Generate keypair for a binary cache")) <>
  command "push" (infoH push (progDesc "Upload Nix store paths to the binary cache")) <>
  command "use" (infoH use (progDesc "Configure nix.conf to enable binary cache during builds"))
  where
    nameArg = strArgument (metavar "NAME")
    authtoken = AuthToken <$> strArgument (metavar "TOKEN")
    create = Create <$> nameArg
    generateKeypair = GenerateKeypair <$> nameArg

    validatedLevel l =
      l <$ unless (l `elem` [0 .. 9]) (readerError $ "value " <> show l <> " not in expected range: [0..9]")

    pushOptions :: Parser PushOptions
    pushOptions = PushOptions
       <$> option (auto >>= validatedLevel)
            ( long "compression-level"
            <> metavar "[0..9]"
            <> help "The compression level for XZ compression.\
                   \ Take compressor *and* decompressor memory usage into account before using [7..9]!"
            <> showDefault
            <> value 2
            )

    push = (\opts cache f -> Push $ f opts cache) <$> pushOptions <*> nameArg <*> (pushPaths <|> pushWatchStore)
    pushPaths = (\paths opts cache -> PushPaths opts cache paths) <$>
                   many (strArgument (metavar "PATHS..."))
    pushWatchStore = (\() opts cache -> PushWatchStore opts cache) <$>
                  flag' () ( long "watch-store"
                          <> short 'w'
                          <> help "Run in daemon mode and push store paths as they are added to /nix/store"
                           )

    use = Use <$> nameArg
              <*> (UseOptions <$> switch ( long "nixos"
                                        <> short 'n'
                                        <> help "Write NixOS modules")
                              <*> strOption ( long "nixos-folder"
                                           <> short 'd'
                                           <> help "Base directory for NixOS configuration"
                                           <> value "/etc/nixos/"
                                           <> showDefault
                                           ))

getOpts :: IO (CachixOptions, CachixCommand)
getOpts = do
  configpath <- Config.getDefaultFilename
  customExecParser (prefs showHelpOnEmpty) (opts configpath)

opts :: Config.ConfigPath -> ParserInfo (CachixOptions, CachixCommand)
opts configpath = infoH parser desc
  where parser = (,) <$> parserCachixOptions configpath <*> (parserCachixCommand <|> versionParser)
        versionParser :: Parser CachixCommand
        versionParser = flag' Version ( long "version"
                     <> short 'V'
                     <> help "Show cachix version"
                     )

desc :: InfoMod a
desc = fullDesc
    <> progDesc "Sign into https://cachix.org to get started."
    <> header "cachix.org command interface"
    -- TODO: usage footer

infoH :: Parser a -> InfoMod a -> ParserInfo a
infoH a = info (helper <*> a)