Skip to content

Instantly share code, notes, and snippets.

@thelissimus
Created October 17, 2025 22:36
Show Gist options
  • Select an option

  • Save thelissimus/cf9c6cc2fac56062a250d797476d677e to your computer and use it in GitHub Desktop.

Select an option

Save thelissimus/cf9c6cc2fac56062a250d797476d677e to your computer and use it in GitHub Desktop.
{-# LANGUAGE ApplicativeDo #-}
module Main (main) where
import Data.List
import Options.Applicative
import System.Exit
data Cmd
= Query QueryOpts
| Sync SyncOpts
deriving stock (Show)
data QueryOpts = MkQueryOpts
{ info :: [String]
, search :: [String]
}
deriving stock (Show)
data SyncOpts = MkSyncOpts
{ search :: [String]
, info :: Bool
, packages :: [String]
}
deriving stock (Show)
parseQueryOpts :: Parser QueryOpts
parseQueryOpts = do
info' <- many $ strOption (long "info" <> short 'i' <> help "view package information")
search <- many $ strOption (long "search" <> short 's' <> help "search locally installed packages for matching strings")
pure MkQueryOpts{info = info', search}
parseSyncOpts :: Parser SyncOpts
parseSyncOpts = do
search <- many $ strOption (long "search" <> short 's' <> help "search remote repositories for matching strings")
info' <- switch (long "info" <> short 'i' <> help "view package information")
packages <- many $ strArgument (help "packages")
pure MkSyncOpts{search, info = info', packages}
parseCmd :: Parser Cmd
parseCmd =
hsubparser . mconcat
$ [ command "query" (info (Query <$> parseQueryOpts) (progDesc "Query the package database."))
, command "Q" (info (Query <$> parseQueryOpts) (progDesc "Query the package database."))
, command "sync" (info (Sync <$> parseSyncOpts) (progDesc "Synchronize packages."))
, command "S" (info (Sync <$> parseSyncOpts) (progDesc "Synchronize packages."))
]
parserInfo :: ParserInfo Cmd
parserInfo = info (helper <*> infoOption "5.2.1" (long "version") <*> parseCmd) (progDesc "package manager utility")
runQuery :: QueryOpts -> IO ()
runQuery opt = case (opt.info, opt.search) of
([], []) -> putStrLn "Displaying all locally installed packages..."
(_ : _, _ : _) -> putStrLn "error: --info conflicts with --search" >> exitFailure
(xs, []) -> putStrLn $ "Retrieving info for " <> intercalate ", " xs <> "..."
([], qs) -> putStrLn $ "Searching Locally for " <> intercalate ", " qs <> "..."
runSync :: SyncOpts -> IO ()
runSync opt = case (opt.search, opt.info, opt.packages) of
(_ : _, True, _) -> putStrLn "error: --search conflicts with --info and PACKAGE..." >> exitFailure
(_ : _, _, _ : _) -> putStrLn "error: --search conflicts with --info and PACKAGE..." >> exitFailure
(qs@(_ : _), _, []) -> putStrLn $ "Searching for " <> intercalate ", " qs <> "..."
([], _, []) -> putStrLn "error: PACKAGE... is required unless --search is used" >> exitFailure
([], True, xs) -> putStrLn $ "Retrieving info for " <> intercalate ", " xs <> "..."
([], False, xs) -> putStrLn $ "Installing " <> intercalate ", " xs <> "..."
main :: IO ()
main =
execParser parserInfo >>= \case
Sync o -> runSync o
Query o -> runQuery o
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment