packages feed

nbparts-0.1.0.0: app/Nbparts/Cli/Options.hs

module Nbparts.Cli.Options where

import Control.Monad.Error.Class (throwError)
import Data.Version qualified as Version
import Nbparts.Pack (PackOptions (PackOptions))
import Nbparts.Run (Command (Pack, Unpack), Options (Options))
import Nbparts.Types (Format (FormatJson, FormatMarkdown, FormatYaml))
import Nbparts.Unpack (UnpackOptions (UnpackOptions))
import Options.Applicative
  ( Parser,
    ReadM,
    argument,
    command,
    customExecParser,
    eitherReader,
    fullDesc,
    help,
    helper,
    hidden,
    hsubparser,
    info,
    infoOption,
    long,
    metavar,
    option,
    optional,
    prefs,
    progDesc,
    short,
    showHelpOnEmpty,
    str,
    strOption,
    switch,
    value,
  )
import Paths_nbparts qualified

unpackOptionsParser :: Parser UnpackOptions
unpackOptionsParser =
  UnpackOptions
    <$> argument str (metavar "NOTEBOOK" <> help "Path to the notebook to unpack")
    <*> option
      parseSourcesFormat
      ( short 'S'
          <> long "sources-format"
          <> metavar "yaml|json|markdown"
          <> help "Output format for sources"
          <> value FormatYaml
      )
    <*> option
      parseMetadataFormat
      ( short 'M'
          <> long "metadata-format"
          <> metavar "yaml|json"
          <> help "Output format for metadata"
          <> value FormatYaml
      )
    <*> option
      parseOutputsFormat
      ( short 'O'
          <> long "outputs-format"
          <> metavar "yaml|json"
          <> help "Output format for outputs"
          <> value FormatYaml
      )
    <*> optional
      ( strOption $
          short 'o'
            <> long "output-path"
            <> metavar "OUTPUT_PATH"
            <> help "Directory to write the unpacked notebook to"
      )
    <*> switch
      ( short 'f'
          <> long "force"
          <> help "Overwrite existing files without confirmation"
      )

packOptionsParser :: Parser PackOptions
packOptionsParser =
  PackOptions
    <$> argument str (metavar "DIRECTORY" <> help "Path to the directory to pack into a notebook")
    <*> optional
      ( strOption $
          short 'o'
            <> long "output-path"
            <> metavar "OUTPUT_PATH"
            <> help "Path to write the notebook to"
      )
    <*> switch
      ( short 'f'
          <> long "force"
          <> help "Overwrite existing files without confirmation"
      )

commandParser :: Parser Command
commandParser =
  hsubparser $
    command "unpack" (info (Unpack <$> unpackOptionsParser) (progDesc "Unpack a notebook"))
      <> command "pack" (info (Pack <$> packOptionsParser) (progDesc "Pack a directory into a notebook"))

nbpartsOptionsParser :: Parser Options
nbpartsOptionsParser = Options <$> commandParser

parseSourcesFormat :: ReadM Format
parseSourcesFormat = eitherReader $ \case
  "yaml" -> pure FormatYaml
  "json" -> pure FormatJson
  "markdown" -> pure FormatMarkdown
  s -> throwError $ "Invalid sources format: " <> s

parseMetadataFormat :: ReadM Format
parseMetadataFormat = eitherReader $ \case
  "yaml" -> pure FormatYaml
  "json" -> pure FormatJson
  s -> throwError $ "Invalid sources format: " <> s

parseOutputsFormat :: ReadM Format
parseOutputsFormat = parseMetadataFormat

parseOpts :: IO Options
parseOpts =
  customExecParser (prefs showHelpOnEmpty) $
    info
      (helper <*> versioner <*> nbpartsOptionsParser)
      (fullDesc <> progDesc "Unpack a Jupyter notebook into its sources, metadata and outputs")
  where
    versioner =
      infoOption (Version.showVersion Paths_nbparts.version) $
        short 'V' <> long "version" <> help "Show nbparts version" <> hidden