shellify-0.14.0.0: src/Options.hs
{-# LANGUAGE TemplateHaskell #-}
module Options (Options(..), OutputForm(..), Package(..), Packages(Packages), parseCommandLine) where
import Constants
import FlakeTemplate
import ShellifyTemplate
import Control.Lens.Combinators (makeLenses, makePrisms)
import Data.Default (Default(def))
import Data.List (isPrefixOf, sort)
import Data.Maybe (fromMaybe, isJust)
import Data.Text (pack, Text(), unpack)
import Data.Version (showVersion)
import Options.Applicative ((<**>), Parser, ParserResult(Success, Failure, CompletionInvoked), argument, command, defaultPrefs, execParserPure, fullDesc, header, help, helper, hidden, info, long, metavar, option, optional, progDesc, short, simpleVersioner, some, str, strOption, switch)
import Paths_shellify (version)
import System.Environment (getArgs)
data OutputForm = Traditional
| Flake
deriving (Eq, Show)
newtype Packages = Packages [ Package ] deriving Show
type Package = Text
instance Eq Packages where
Packages a == Packages b = sort a == sort b
makePrisms ''Packages
opts = info (commandParser <**> simpleVersioner (showVersion version)
<**> helper) $
fullDesc
<> progDesc hlDesc
<> header "Quickly generate shell.nix files once you have a working shell"
commandParser :: Parser CommandLineOptions
commandParser = CommandLineOptions
<$> optional (some (option str (
long "packages"
<> short 'p'
<> metavar "PACKAGE"
<> help "Packages to install in the shell.nix file. This option can be used multiple times to specify multiple packages"
)))
<*> optional (option str (
long "command"
<> long "run"
<> short 'c'
<> metavar "COMMAND"
<> help "Command to run on initial shell startup"
))
<*> switch (
long "with-flake"
<> help "When using the -p option to specify packages, use this switch to have a flake.nix created in addition to a shell.nix. This is recommended to ensure the versions of dependencies are kept for reproducibility and so that shells are cached to load faster."
)
<*> switch (
long "allow-local-pinned-registries-to-be-prioritized"
<> help "Pinned local repoisitory URLs are usually taken last when looking for URLs for generated flake.nix files. This is usually desired. If you do however want to see these pinned entries in the flake file as specified in your registry, then set this flag."
)
<*> optional (some (option str (
long "arg"
<> long "argstr"
<> hidden
)))
<*> optional (some (argument str (metavar "shell PACKAGES...")))
data Options = Options {
_packages :: !Packages
, _command :: !(Maybe Text)
, _outputForm :: !OutputForm
, _prioritiseLocalPinnedSystem :: !Bool
} deriving (Eq, Show)
data CommandLineOptions = CommandLineOptions {
__packages :: !(Maybe [Text])
, __command :: !(Maybe Text)
, __withFlake :: !Bool
, __prioritiseLocalPinnedSystem :: Bool
, __discard :: !(Maybe [String])
, __shellPackages :: Maybe [Package]
} deriving (Show)
makeLenses ''Options
instance Default Options where
def = Options{
_packages = Packages [],
_command = Nothing,
_outputForm = Traditional,
_prioritiseLocalPinnedSystem = False
}
parseCommandLine :: [String] -> Either Text (ParserResult Options)
parseCommandLine =
(\case
Success res -> fmap Success (parseCommandLineOptions res)
Failure failure -> Right $ Failure failure
CompletionInvoked f -> Right $ CompletionInvoked f)
. execParserPure defaultPrefs opts . fixupRequest
where parseCommandLineOptions :: CommandLineOptions -> Either Text Options
parseCommandLineOptions originalParsedOptions =
let transformedOptions =
(Options <$> Packages . ((++) <$> fromMaybe [] . __packages
<*> shellArgs . __shellPackages)
<*> __command
<*> \case
f | __withFlake f -> Flake
| (hasShellArg . __shellPackages) f -> Flake
_ | otherwise -> Traditional
<*> __prioritiseLocalPinnedSystem) originalParsedOptions
in if _packages transformedOptions == Packages [] then
Left noPackagesError
else
Right transformedOptions
where hasShellArg (Just ("shell":_)) = True
hasShellArg _ = False
shellArgs (Just ("shell": rst)) = rst
shellArgs _ = []
fixupRequest (a : b : c : d) | (a == "-p" || a == "--packages")
&& isNotASwitch b
&& isNotASwitch c =
a : b : fixupRequest ("-p" : c : d)
where isNotASwitch = not . isPrefixOf "-"
fixupRequest (a : b) = a : fixupRequest b
fixupRequest [] = []