command line options API updates, possibly fixing hledger-web build
This commit is contained in:
parent
13f8c0f938
commit
a66a715eeb
@ -11,14 +11,12 @@ import Data.List
|
|||||||
import Data.Ord
|
import Data.Ord
|
||||||
import Hledger
|
import Hledger
|
||||||
import Hledger.Cli
|
import Hledger.Cli
|
||||||
import Hledger.Cli.Print (print')
|
|
||||||
|
|
||||||
main = do
|
main = do
|
||||||
opts <- getHledgerCliOpts []
|
opts <- getCliOpts (defCommandMode ["hledger-print-unique"])
|
||||||
withJournalDo opts $
|
withJournalDo opts $
|
||||||
\opts j@Journal{jtxns=ts} -> print' opts j{jtxns=uniquify ts}
|
\opts j@Journal{jtxns=ts} -> print' opts j{jtxns=uniquify ts}
|
||||||
where
|
where
|
||||||
uniquify = nubBy (\t1 t2 -> thingToCompare t1 == thingToCompare t2) . sortBy (comparing thingToCompare)
|
uniquify = nubBy (\t1 t2 -> thingToCompare t1 == thingToCompare t2) . sortBy (comparing thingToCompare)
|
||||||
|
thingToCompare = tdescription
|
||||||
thingToCompare = tdescription
|
-- thingToCompare = tdate
|
||||||
-- thingToCompare = tdate
|
|
||||||
|
|||||||
@ -40,9 +40,9 @@ main = do
|
|||||||
|
|
||||||
runWith :: WebOpts -> IO ()
|
runWith :: WebOpts -> IO ()
|
||||||
runWith opts
|
runWith opts
|
||||||
| "help" `in_` (rawopts_ $ cliopts_ opts) = putStr (showModeHelp webmode) >> exitSuccess
|
| "help" `inRawOpts` (rawopts_ $ cliopts_ opts) = putStr (showModeHelp webmode) >> exitSuccess
|
||||||
| "version" `in_` (rawopts_ $ cliopts_ opts) = putStrLn prognameandversion >> exitSuccess
|
| "version" `inRawOpts` (rawopts_ $ cliopts_ opts) = putStrLn prognameandversion >> exitSuccess
|
||||||
| "binary-filename" `in_` (rawopts_ $ cliopts_ opts) = putStrLn (binaryfilename progname)
|
| "binary-filename" `inRawOpts` (rawopts_ $ cliopts_ opts) = putStrLn (binaryfilename progname)
|
||||||
| otherwise = do
|
| otherwise = do
|
||||||
requireJournalFileExists =<< journalFilePathFromOpts (cliopts_ opts)
|
requireJournalFileExists =<< journalFilePathFromOpts (cliopts_ opts)
|
||||||
withJournalDo' opts web
|
withJournalDo' opts web
|
||||||
|
|||||||
@ -31,11 +31,11 @@ webflags = [
|
|||||||
webmode :: Mode [([Char], [Char])]
|
webmode :: Mode [([Char], [Char])]
|
||||||
webmode = (mode "hledger-web" [("command","web")]
|
webmode = (mode "hledger-web" [("command","web")]
|
||||||
"start serving the hledger web interface"
|
"start serving the hledger web interface"
|
||||||
mainargsflag []){
|
(argsFlag "[PATTERNS]") []){
|
||||||
modeGroupFlags = Group {
|
modeGroupFlags = Group {
|
||||||
groupUnnamed = webflags
|
groupUnnamed = webflags
|
||||||
,groupHidden = [flagNone ["binary-filename"] (setboolopt "binary-filename") "show the download filename for this executable, and exit"]
|
,groupHidden = [flagNone ["binary-filename"] (setboolopt "binary-filename") "show the download filename for this executable, and exit"]
|
||||||
,groupNamed = [(generalflagstitle, generalflags1)]
|
,groupNamed = [generalflagsgroup1]
|
||||||
}
|
}
|
||||||
,modeHelpSuffix=[
|
,modeHelpSuffix=[
|
||||||
-- "Reads your ~/.hledger.journal file, or another specified by $LEDGER_FILE or -f, and starts the full-window curses ui."
|
-- "Reads your ~/.hledger.journal file, or another specified by $LEDGER_FILE or -f, and starts the full-window curses ui."
|
||||||
@ -61,7 +61,7 @@ defwebopts = WebOpts
|
|||||||
|
|
||||||
toWebOpts :: RawOpts -> IO WebOpts
|
toWebOpts :: RawOpts -> IO WebOpts
|
||||||
toWebOpts rawopts = do
|
toWebOpts rawopts = do
|
||||||
cliopts <- toCliOpts rawopts
|
cliopts <- rawOptsToCliOpts rawopts
|
||||||
let p = fromMaybe defport $ maybeintopt "port" rawopts
|
let p = fromMaybe defport $ maybeintopt "port" rawopts
|
||||||
return defwebopts {
|
return defwebopts {
|
||||||
port_ = p
|
port_ = p
|
||||||
|
|||||||
@ -99,7 +99,7 @@ main = do
|
|||||||
addons <- getHledgerAddonCommands
|
addons <- getHledgerAddonCommands
|
||||||
|
|
||||||
-- parse arguments with cmdargs
|
-- parse arguments with cmdargs
|
||||||
opts <- getHledgerCliOpts addons
|
opts <- argsToCliOpts args addons
|
||||||
|
|
||||||
-- select an action and run it.
|
-- select an action and run it.
|
||||||
let
|
let
|
||||||
|
|||||||
@ -7,7 +7,7 @@ Command-line options for the hledger program, and related utilities.
|
|||||||
|
|
||||||
module Hledger.Cli.Options (
|
module Hledger.Cli.Options (
|
||||||
|
|
||||||
-- * cmdargs modes
|
-- * cmdargs modes & flags
|
||||||
-- | These tell cmdargs how to parse the command line arguments.
|
-- | These tell cmdargs how to parse the command line arguments.
|
||||||
-- There's one mode for each internal subcommand, plus a main mode.
|
-- There's one mode for each internal subcommand, plus a main mode.
|
||||||
mainmode,
|
mainmode,
|
||||||
@ -22,6 +22,14 @@ module Hledger.Cli.Options (
|
|||||||
statsmode,
|
statsmode,
|
||||||
testmode,
|
testmode,
|
||||||
convertmode,
|
convertmode,
|
||||||
|
defCommandMode,
|
||||||
|
argsFlag,
|
||||||
|
helpflags,
|
||||||
|
inputflags,
|
||||||
|
reportflags,
|
||||||
|
generalflagsgroup1,
|
||||||
|
generalflagsgroup2,
|
||||||
|
generalflagsgroup3,
|
||||||
|
|
||||||
-- * raw options
|
-- * raw options
|
||||||
-- | To allow the cmdargs modes to be reused and extended by other
|
-- | To allow the cmdargs modes to be reused and extended by other
|
||||||
@ -30,6 +38,14 @@ module Hledger.Cli.Options (
|
|||||||
-- association list, not a fixed ADT.
|
-- association list, not a fixed ADT.
|
||||||
RawOpts,
|
RawOpts,
|
||||||
inRawOpts,
|
inRawOpts,
|
||||||
|
boolopt,
|
||||||
|
intopt,
|
||||||
|
maybeintopt,
|
||||||
|
stringopt,
|
||||||
|
maybestringopt,
|
||||||
|
listofstringopt,
|
||||||
|
setopt,
|
||||||
|
setboolopt,
|
||||||
|
|
||||||
-- * CLI options
|
-- * CLI options
|
||||||
-- | Raw options are converted to a more convenient,
|
-- | Raw options are converted to a more convenient,
|
||||||
@ -37,10 +53,9 @@ module Hledger.Cli.Options (
|
|||||||
-- throughout hledger CLI code.
|
-- throughout hledger CLI code.
|
||||||
CliOpts(..),
|
CliOpts(..),
|
||||||
defcliopts,
|
defcliopts,
|
||||||
toCliOpts,
|
|
||||||
|
|
||||||
-- * CLI option accessors
|
-- * CLI option accessors
|
||||||
-- | Some options require more processing. Possibly these should be merged into toCliOpts.
|
-- | Some options require more processing. Possibly these should be merged into argsToCliOpts.
|
||||||
aliasesFromOpts,
|
aliasesFromOpts,
|
||||||
formatFromOpts,
|
formatFromOpts,
|
||||||
journalFilePathFromOpts,
|
journalFilePathFromOpts,
|
||||||
@ -53,10 +68,15 @@ module Hledger.Cli.Options (
|
|||||||
|
|
||||||
-- * utilities
|
-- * utilities
|
||||||
getHledgerAddonCommands,
|
getHledgerAddonCommands,
|
||||||
getHledgerCliOpts,
|
argsToCliOpts,
|
||||||
moveFlagsAfterCommand,
|
moveFlagsAfterCommand,
|
||||||
|
decodeRawOpts,
|
||||||
|
checkCliOpts,
|
||||||
|
rawOptsToCliOpts,
|
||||||
optserror,
|
optserror,
|
||||||
showModeHelp,
|
showModeHelp,
|
||||||
|
debugArgs,
|
||||||
|
getCliOpts,
|
||||||
|
|
||||||
-- * tests
|
-- * tests
|
||||||
tests_Hledger_Cli_Options
|
tests_Hledger_Cli_Options
|
||||||
@ -66,9 +86,11 @@ where
|
|||||||
|
|
||||||
import qualified Control.Exception as C
|
import qualified Control.Exception as C
|
||||||
-- import Control.Monad (filterM)
|
-- import Control.Monad (filterM)
|
||||||
|
import Control.Monad (when)
|
||||||
import Data.List
|
import Data.List
|
||||||
import Data.List.Split
|
import Data.List.Split
|
||||||
import Data.Maybe
|
import Data.Maybe
|
||||||
|
import Data.PPrint (pprint)
|
||||||
import Data.Time.Calendar
|
import Data.Time.Calendar
|
||||||
import Safe
|
import Safe
|
||||||
import System.Console.CmdArgs
|
import System.Console.CmdArgs
|
||||||
@ -76,6 +98,7 @@ import System.Console.CmdArgs.Explicit
|
|||||||
import System.Console.CmdArgs.Text
|
import System.Console.CmdArgs.Text
|
||||||
import System.Directory
|
import System.Directory
|
||||||
import System.Environment
|
import System.Environment
|
||||||
|
import System.Exit
|
||||||
import Test.HUnit
|
import Test.HUnit
|
||||||
import Text.ParserCombinators.Parsec as P
|
import Text.ParserCombinators.Parsec as P
|
||||||
import Text.Printf
|
import Text.Printf
|
||||||
@ -107,7 +130,7 @@ helpflags = [
|
|||||||
inputflags = [
|
inputflags = [
|
||||||
flagReq ["file","f"] (\s opts -> Right $ setopt "file" s opts) "FILE" "use a different journal file; - means stdin"
|
flagReq ["file","f"] (\s opts -> Right $ setopt "file" s opts) "FILE" "use a different journal file; - means stdin"
|
||||||
,flagReq ["rules-file"] (\s opts -> Right $ setopt "rules-file" s opts) "RULESFILE" "conversion rules for CSV (default: FILE.rules)"
|
,flagReq ["rules-file"] (\s opts -> Right $ setopt "rules-file" s opts) "RULESFILE" "conversion rules for CSV (default: FILE.rules)"
|
||||||
,flagReq ["alias"] (\s opts -> Right $ setopt "alias" s opts) "ACCT=ALIAS" "display ACCT's name as ALIAS in reports"
|
,flagReq ["alias"] (\s opts -> Right $ setopt "alias" s opts) "ACCT=ALIAS" "convert ACCT's name to ALIAS"
|
||||||
]
|
]
|
||||||
|
|
||||||
-- | Common report-related flags: --period, --cost, --display etc.
|
-- | Common report-related flags: --period, --cost, --display etc.
|
||||||
@ -137,7 +160,9 @@ generalflagsgroup1 = (generalflagstitle, inputflags ++ reportflags ++ helpflags)
|
|||||||
generalflagsgroup2 = (generalflagstitle, inputflags ++ helpflags)
|
generalflagsgroup2 = (generalflagstitle, inputflags ++ helpflags)
|
||||||
generalflagsgroup3 = (generalflagstitle, helpflags)
|
generalflagsgroup3 = (generalflagstitle, helpflags)
|
||||||
|
|
||||||
-- | Template for creating our modes.
|
-- cmdargs modes
|
||||||
|
|
||||||
|
-- | A basic mode template.
|
||||||
defMode :: Mode RawOpts
|
defMode :: Mode RawOpts
|
||||||
defMode = Mode {
|
defMode = Mode {
|
||||||
modeNames = []
|
modeNames = []
|
||||||
@ -147,11 +172,44 @@ defMode = Mode {
|
|||||||
,modeCheck = Right
|
,modeCheck = Right
|
||||||
,modeReform = const Nothing
|
,modeReform = const Nothing
|
||||||
,modeExpandAt = True
|
,modeExpandAt = True
|
||||||
,modeGroupFlags = toGroup []
|
,modeGroupFlags = Group {
|
||||||
|
groupNamed = []
|
||||||
|
,groupUnnamed = [
|
||||||
|
flagNone ["help","h","?"] (setboolopt "help") "Display command help."
|
||||||
|
]
|
||||||
|
,groupHidden = []
|
||||||
|
}
|
||||||
,modeArgs = ([], Nothing)
|
,modeArgs = ([], Nothing)
|
||||||
,modeGroupModes = toGroup []
|
,modeGroupModes = toGroup []
|
||||||
}
|
}
|
||||||
|
|
||||||
|
-- | A basic subcommand mode with the given command name(s).
|
||||||
|
defCommandMode names = defMode {
|
||||||
|
modeNames=names
|
||||||
|
,modeValue=[("command", headDef "" names)]
|
||||||
|
,modeArgs = ([], Just $ argsFlag "[PATTERNS]")
|
||||||
|
}
|
||||||
|
|
||||||
|
-- | A basic subcommand mode suitable for an add-on command.
|
||||||
|
defAddonCommandMode addon = defMode {
|
||||||
|
modeNames = [addon]
|
||||||
|
,modeHelp = printf "run %s-%s" progname addon
|
||||||
|
,modeValue=[("command",addon)]
|
||||||
|
,modeGroupFlags = Group {
|
||||||
|
groupUnnamed = []
|
||||||
|
,groupHidden = []
|
||||||
|
,groupNamed = [generalflagsgroup1]
|
||||||
|
}
|
||||||
|
,modeArgs = ([], Just $ argsFlag "[ARGS]")
|
||||||
|
}
|
||||||
|
|
||||||
|
-- | Add command aliases to the command's help string.
|
||||||
|
withAliases :: String -> [String] -> String
|
||||||
|
s `withAliases` [] = s
|
||||||
|
s `withAliases` (a:[]) = s ++ " (alias: " ++ a ++ ")"
|
||||||
|
s `withAliases` as = s ++ " (aliases: " ++ intercalate ", " as ++ ")"
|
||||||
|
|
||||||
|
|
||||||
-- | The top-level cmdargs mode for hledger.
|
-- | The top-level cmdargs mode for hledger.
|
||||||
mainmode addons = defMode {
|
mainmode addons = defMode {
|
||||||
modeNames = [progname]
|
modeNames = [progname]
|
||||||
@ -211,49 +269,7 @@ mainmode addons = defMode {
|
|||||||
-- -- ,"When using both, not: comes last."
|
-- -- ,"When using both, not: comes last."
|
||||||
-- ]
|
-- ]
|
||||||
|
|
||||||
--
|
-- visible subcommand modes
|
||||||
-- cmdargs modes for subcommands
|
|
||||||
--
|
|
||||||
|
|
||||||
-- | Make a basic command mode given the command's name and any aliases.
|
|
||||||
defCommandMode names = defMode {
|
|
||||||
modeNames=names
|
|
||||||
,modeValue=[("command", headDef "" names)]
|
|
||||||
,modeArgs = ([], Just $ argsFlag "[PATTERNS]")
|
|
||||||
}
|
|
||||||
|
|
||||||
-- | Make a basic command mode suitable for an add-on command.
|
|
||||||
defAddonCommandMode addon = defMode {
|
|
||||||
modeNames = [addon]
|
|
||||||
,modeHelp = printf "run %s-%s" progname addon
|
|
||||||
,modeValue=[("command",addon)]
|
|
||||||
,modeGroupFlags = Group {
|
|
||||||
groupUnnamed = []
|
|
||||||
,groupHidden = []
|
|
||||||
,groupNamed = [generalflagsgroup1]
|
|
||||||
}
|
|
||||||
,modeArgs = ([], Just $ argsFlag "[ARGS]")
|
|
||||||
}
|
|
||||||
|
|
||||||
withAliases :: String -> [String] -> String
|
|
||||||
s `withAliases` [] = s
|
|
||||||
s `withAliases` (a:[]) = s ++ " (alias: " ++ a ++ ")"
|
|
||||||
s `withAliases` as = s ++ " (aliases: " ++ intercalate ", " as ++ ")"
|
|
||||||
|
|
||||||
-- hidden commands
|
|
||||||
|
|
||||||
convertmode = (defCommandMode ["convert"]) {
|
|
||||||
modeValue = [("command","convert")]
|
|
||||||
,modeHelp = "convert is no longer needed, just use -f FILE.csv"
|
|
||||||
,modeArgs = ([], Just $ argsFlag "[CSVFILE]")
|
|
||||||
,modeGroupFlags = Group {
|
|
||||||
groupUnnamed = []
|
|
||||||
,groupHidden = helpflags
|
|
||||||
,groupNamed = []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
-- visible commands
|
|
||||||
|
|
||||||
addmode = (defCommandMode ["add"]) {
|
addmode = (defCommandMode ["add"]) {
|
||||||
modeHelp = "prompt for new transaction entries and add them to the journal"
|
modeHelp = "prompt for new transaction entries and add them to the journal"
|
||||||
@ -375,6 +391,19 @@ testmode = (defCommandMode ["test"]) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
-- hidden commands
|
||||||
|
|
||||||
|
convertmode = (defCommandMode ["convert"]) {
|
||||||
|
modeValue = [("command","convert")]
|
||||||
|
,modeHelp = "convert is no longer needed, just use -f FILE.csv"
|
||||||
|
,modeArgs = ([], Just $ argsFlag "[CSVFILE]")
|
||||||
|
,modeGroupFlags = Group {
|
||||||
|
groupUnnamed = []
|
||||||
|
,groupHidden = helpflags
|
||||||
|
,groupNamed = []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
--
|
--
|
||||||
-- 2. A package-specific data structure holding options used in this
|
-- 2. A package-specific data structure holding options used in this
|
||||||
-- package and above, parsed from RawOpts. This represents the
|
-- package and above, parsed from RawOpts. This represents the
|
||||||
@ -411,8 +440,8 @@ instance Default CliOpts where def = defcliopts
|
|||||||
-- | Parse raw option string values to the desired final data types.
|
-- | Parse raw option string values to the desired final data types.
|
||||||
-- Any relative smart dates will be converted to fixed dates based on
|
-- Any relative smart dates will be converted to fixed dates based on
|
||||||
-- today's date. Parsing failures will raise an error.
|
-- today's date. Parsing failures will raise an error.
|
||||||
toCliOpts :: RawOpts -> IO CliOpts
|
rawOptsToCliOpts :: RawOpts -> IO CliOpts
|
||||||
toCliOpts rawopts = do
|
rawOptsToCliOpts rawopts = do
|
||||||
d <- getCurrentDay
|
d <- getCurrentDay
|
||||||
return defcliopts {
|
return defcliopts {
|
||||||
rawopts_ = rawopts
|
rawopts_ = rawopts
|
||||||
@ -451,16 +480,15 @@ toCliOpts rawopts = do
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
-- | Parse hledger CLI options from the command line arguments and
|
-- | Parse hledger CLI options from these command line arguments and
|
||||||
-- specified add-on command names, or raise any error.
|
-- add-on command names, or raise any error.
|
||||||
getHledgerCliOpts :: [String] -> IO CliOpts
|
argsToCliOpts :: [String] -> [String] -> IO CliOpts
|
||||||
getHledgerCliOpts addons = do
|
argsToCliOpts args addons = do
|
||||||
args <- getArgs
|
|
||||||
let
|
let
|
||||||
args' = moveFlagsAfterCommand args
|
args' = moveFlagsAfterCommand args
|
||||||
cmdargsopts = System.Console.CmdArgs.Explicit.processValue (mainmode addons) args'
|
cmdargsopts = System.Console.CmdArgs.Explicit.processValue (mainmode addons) args'
|
||||||
cmdargsopts' = decodeRawOpts cmdargsopts
|
cmdargsopts' = decodeRawOpts cmdargsopts
|
||||||
toCliOpts cmdargsopts' >>= checkCliOpts
|
rawOptsToCliOpts cmdargsopts' >>= checkCliOpts
|
||||||
|
|
||||||
-- | A hacky workaround for cmdargs not accepting flags before the
|
-- | A hacky workaround for cmdargs not accepting flags before the
|
||||||
-- subcommand name: try to detect and move such flags after the
|
-- subcommand name: try to detect and move such flags after the
|
||||||
@ -505,7 +533,9 @@ checkCliOpts opts@CliOpts{reportopts_=ropts} = do
|
|||||||
Right _ -> return ()
|
Right _ -> return ()
|
||||||
return opts
|
return opts
|
||||||
|
|
||||||
|
--
|
||||||
-- utils
|
-- utils
|
||||||
|
--
|
||||||
|
|
||||||
-- | Get the unique suffixes (without hledger-) of hledger-* executables
|
-- | Get the unique suffixes (without hledger-) of hledger-* executables
|
||||||
-- found in the current user's PATH, or the empty list if there is any
|
-- found in the current user's PATH, or the empty list if there is any
|
||||||
@ -677,6 +707,31 @@ showModeHelp =
|
|||||||
.
|
.
|
||||||
(helpText [] HelpFormatDefault :: Mode a -> [Text])
|
(helpText [] HelpFormatDefault :: Mode a -> [Text])
|
||||||
|
|
||||||
|
-- | Print debug info about arguments and options if --debug is present.
|
||||||
|
debugArgs :: [String] -> CliOpts -> IO ()
|
||||||
|
debugArgs args opts =
|
||||||
|
when ("--debug" `elem` args) $ do
|
||||||
|
progname <- getProgName
|
||||||
|
putStrLn $ "running: " ++ progname
|
||||||
|
putStrLn $ "raw args: " ++ show args
|
||||||
|
putStrLn $ "processed opts:\n" ++ show opts
|
||||||
|
putStrLn . show =<< pprint opts
|
||||||
|
d <- getCurrentDay
|
||||||
|
putStrLn $ "search query: " ++ (show $ queryFromOpts d $ reportopts_ opts)
|
||||||
|
|
||||||
|
-- | Parse hledger CLI options from the command line using the given
|
||||||
|
-- cmdargs mode, and either return them or, if a help flag is present,
|
||||||
|
-- print the mode help and exit the program.
|
||||||
|
getCliOpts :: Mode RawOpts -> IO CliOpts
|
||||||
|
getCliOpts mode = do
|
||||||
|
args <- getArgs
|
||||||
|
let rawopts = decodeRawOpts $ processValue mode args
|
||||||
|
opts <- rawOptsToCliOpts rawopts >>= checkCliOpts
|
||||||
|
debugArgs args opts
|
||||||
|
-- if any (`elem` args) ["--help","-h","-?"]
|
||||||
|
when ("help" `inRawOpts` rawopts_ opts) $
|
||||||
|
putStr (showModeHelp mode) >> exitSuccess
|
||||||
|
return opts
|
||||||
|
|
||||||
tests_Hledger_Cli_Options = TestList
|
tests_Hledger_Cli_Options = TestList
|
||||||
[
|
[
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user