shellify-0.14.0.1: src/Options.hs
{-# LANGUAGE TemplateHaskell #-}
module Options (Options(..), OutputForm(..), Package(), Packages(Packages), parseCommandLine, setPackages) where
import Constants (hlDesc, noPackagesError)
import Control.Lens.Combinators (makeLenses, makePrisms)
import Data.Default (Default(def))
import Data.List (isPrefixOf)
import Data.Maybe (fromMaybe)
import Data.Set (Set(), fromList)
import Data.Text (Text())
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)
data OutputForm = Traditional
| Flake
deriving (Eq, Show)
newtype Packages = Packages (Set Package)
deriving (Eq, Monoid, Semigroup, Show)
type Package = Text
makePrisms ''Packages
setPackages = Packages . fromList
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 = mempty,
_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 =
if _packages transformedOptions == mempty then
Left noPackagesError
else
Right transformedOptions
where transformedOptions =
(Options <$> setPackages . ((++) <$> fromMaybe mempty . __packages
<*> shellArgs . __shellPackages)
<*> __command
<*> \case
f | __withFlake f -> Flake
| (hasShellArg . __shellPackages) f -> Flake
_ | otherwise -> Traditional
<*> __prioritiseLocalPinnedSystem) originalParsedOptions
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 [] = []