ENH use cli flag for config path
This commit is contained in:
parent
7dc9b7b07b
commit
5d6038292e
93
app/Main.hs
93
app/Main.hs
|
@ -10,84 +10,101 @@ import Internal.Insert
|
||||||
import Internal.Types
|
import Internal.Types
|
||||||
import Internal.Utils
|
import Internal.Utils
|
||||||
|
|
||||||
-- import Import.Config
|
|
||||||
|
|
||||||
import Control.Monad.Trans.Reader
|
import Control.Monad.Trans.Reader
|
||||||
|
|
||||||
import Options.Applicative
|
import Options.Applicative
|
||||||
|
|
||||||
|
import System.FilePath
|
||||||
|
|
||||||
main :: IO ()
|
main :: IO ()
|
||||||
main = parse =<< execParser o
|
main = parse =<< execParser o
|
||||||
where
|
where
|
||||||
o = info (options <**> helper)
|
o = info (options <**> helper)
|
||||||
( fullDesc
|
( fullDesc
|
||||||
<> progDesc "Pwn your budget"
|
<> progDesc "Pwn your budget"
|
||||||
<> header "pwncase - your budget, your life"
|
<> header "pwncash - your budget, your life"
|
||||||
)
|
)
|
||||||
|
|
||||||
data Options = Reset
|
data Options = Options FilePath Mode
|
||||||
|
|
||||||
|
data Mode = Reset
|
||||||
| DumpCurrencies
|
| DumpCurrencies
|
||||||
| DumpAccounts
|
| DumpAccounts
|
||||||
| DumpAccountKeys
|
| DumpAccountKeys
|
||||||
| Sync
|
| Sync
|
||||||
|
|
||||||
options :: Parser Options
|
configFile :: Parser FilePath
|
||||||
options = reset
|
configFile = strOption
|
||||||
<|> dumpCurrencies
|
( long "config"
|
||||||
<|> dumpAccounts
|
<> short 'c'
|
||||||
<|> dumpAccountKeys
|
<> metavar "CONFIG"
|
||||||
<|> sync
|
<> value "main.dhall"
|
||||||
|
<> help "config file to use"
|
||||||
|
)
|
||||||
|
|
||||||
reset :: Parser Options
|
options :: Parser Options
|
||||||
|
options = getConf reset
|
||||||
|
<|> getConf dumpCurrencies
|
||||||
|
<|> getConf dumpAccounts
|
||||||
|
<|> getConf dumpAccountKeys
|
||||||
|
<|> getConf sync
|
||||||
|
where
|
||||||
|
getConf m = Options <$> configFile <*> m
|
||||||
|
|
||||||
|
reset :: Parser Mode
|
||||||
reset = flag' Reset
|
reset = flag' Reset
|
||||||
( long "reset"
|
( long "reset"
|
||||||
<> short 'r'
|
<> short 'R'
|
||||||
<> help "Reset the database"
|
<> help "Reset the database"
|
||||||
)
|
)
|
||||||
|
|
||||||
dumpCurrencies :: Parser Options
|
dumpCurrencies :: Parser Mode
|
||||||
dumpCurrencies = flag' DumpCurrencies
|
dumpCurrencies = flag' DumpCurrencies
|
||||||
( long "currencies"
|
( long "currencies"
|
||||||
<> short 'c'
|
<> short 'C'
|
||||||
<> help "Dump all currencies in the configuration"
|
<> help "Dump all currencies in the configuration"
|
||||||
)
|
)
|
||||||
|
|
||||||
dumpAccounts :: Parser Options
|
dumpAccounts :: Parser Mode
|
||||||
dumpAccounts = flag' DumpAccounts
|
dumpAccounts = flag' DumpAccounts
|
||||||
( long "accounts"
|
( long "accounts"
|
||||||
<> short 'a'
|
<> short 'A'
|
||||||
<> help "Dump all accounts in the configuration"
|
<> help "Dump all accounts in the configuration"
|
||||||
)
|
)
|
||||||
|
|
||||||
-- TODO 'alias' is a better name for these
|
-- TODO 'alias' is a better name for these
|
||||||
dumpAccountKeys :: Parser Options
|
dumpAccountKeys :: Parser Mode
|
||||||
dumpAccountKeys = flag' DumpAccountKeys
|
dumpAccountKeys = flag' DumpAccountKeys
|
||||||
( long "account_keys"
|
( long "account_keys"
|
||||||
<> short 'k'
|
<> short 'K'
|
||||||
<> help "Dump all account keys/aliases"
|
<> help "Dump all account keys/aliases"
|
||||||
)
|
)
|
||||||
|
|
||||||
sync :: Parser Options
|
sync :: Parser Mode
|
||||||
sync = pure Sync
|
sync = flag' Sync
|
||||||
|
( long "sync"
|
||||||
|
<> short 'S'
|
||||||
|
<> help "Sync config to database"
|
||||||
|
)
|
||||||
|
|
||||||
parse :: Options -> IO ()
|
parse :: Options -> IO ()
|
||||||
parse Reset = migrate_ nukeTables
|
parse (Options _ Reset) = migrate_ nukeTables
|
||||||
parse DumpAccounts = runDumpAccounts
|
parse (Options c DumpAccounts) = runDumpAccounts c
|
||||||
parse DumpAccountKeys = runDumpAccountKeys
|
parse (Options c DumpAccountKeys) = runDumpAccountKeys c
|
||||||
parse DumpCurrencies = runDumpCurrencies
|
parse (Options c DumpCurrencies) = runDumpCurrencies c
|
||||||
parse Sync = runSync
|
parse (Options c Sync) = runSync c
|
||||||
|
|
||||||
runDumpCurrencies :: IO ()
|
runDumpCurrencies :: FilePath -> IO ()
|
||||||
runDumpCurrencies = do
|
runDumpCurrencies c = do
|
||||||
cs <- currencies <$> readConfig "config/config.dhall"
|
cs <- currencies <$> readConfig c
|
||||||
putStrLn $ T.unpack $ T.unlines $ fmap fmt cs
|
putStrLn $ T.unpack $ T.unlines $ fmap fmt cs
|
||||||
where
|
where
|
||||||
fmt Currency { curSymbol = s, curFullname = f } =
|
fmt Currency { curSymbol = s, curFullname = f } =
|
||||||
T.concat [s, ": ", f]
|
T.concat [s, ": ", f]
|
||||||
|
|
||||||
runDumpAccounts :: IO ()
|
runDumpAccounts :: FilePath -> IO ()
|
||||||
runDumpAccounts = do
|
runDumpAccounts c = do
|
||||||
ar <- accounts <$> readConfig "config/config.dhall"
|
ar <- accounts <$> readConfig c
|
||||||
mapM_ (\(h, f) -> printTree h $ f ar) ps
|
mapM_ (\(h, f) -> printTree h $ f ar) ps
|
||||||
where
|
where
|
||||||
ps = [ ("Assets", arAssets)
|
ps = [ ("Assets", arAssets)
|
||||||
|
@ -107,9 +124,9 @@ runDumpAccounts = do
|
||||||
let ind = T.replicate (i * 2) " "
|
let ind = T.replicate (i * 2) " "
|
||||||
putStrLn $ T.unpack $ T.concat [ind, n, ": ", d]
|
putStrLn $ T.unpack $ T.concat [ind, n, ": ", d]
|
||||||
|
|
||||||
runDumpAccountKeys :: IO ()
|
runDumpAccountKeys :: FilePath -> IO ()
|
||||||
runDumpAccountKeys = do
|
runDumpAccountKeys c = do
|
||||||
ar <- accounts <$> readConfig "config/config.dhall"
|
ar <- accounts <$> readConfig c
|
||||||
let ks = paths2IDs
|
let ks = paths2IDs
|
||||||
$ fmap (double . fst)
|
$ fmap (double . fst)
|
||||||
$ concatMap (t3 . uncurry tree2Records)
|
$ concatMap (t3 . uncurry tree2Records)
|
||||||
|
@ -121,12 +138,12 @@ runDumpAccountKeys = do
|
||||||
t3 (_, _, x) = x
|
t3 (_, _, x) = x
|
||||||
double x = (x, x)
|
double x = (x, x)
|
||||||
|
|
||||||
runSync :: IO ()
|
runSync :: FilePath -> IO ()
|
||||||
runSync = do
|
runSync c = do
|
||||||
config <- readConfig "config/config.dhall"
|
config <- readConfig c
|
||||||
migrate_ $ do
|
migrate_ $ do
|
||||||
s <- getDBState config
|
s <- getDBState config
|
||||||
flip runReaderT s $ do
|
flip runReaderT (s $ takeDirectory c) $ do
|
||||||
insertBudget $ budget config
|
insertBudget $ budget config
|
||||||
insertStatements config
|
insertStatements config
|
||||||
showBalances
|
showBalances
|
||||||
|
|
|
@ -46,6 +46,7 @@ library
|
||||||
, data-fix
|
, data-fix
|
||||||
, dhall >=1.41.2
|
, dhall >=1.41.2
|
||||||
, esqueleto
|
, esqueleto
|
||||||
|
, filepath
|
||||||
, ghc >=9.0.2
|
, ghc >=9.0.2
|
||||||
, hashable
|
, hashable
|
||||||
, lens >=5.0.1
|
, lens >=5.0.1
|
||||||
|
@ -81,6 +82,7 @@ executable pwncash
|
||||||
, data-fix
|
, data-fix
|
||||||
, dhall >=1.41.2
|
, dhall >=1.41.2
|
||||||
, esqueleto
|
, esqueleto
|
||||||
|
, filepath
|
||||||
, ghc >=9.0.2
|
, ghc >=9.0.2
|
||||||
, hashable
|
, hashable
|
||||||
, lens >=5.0.1
|
, lens >=5.0.1
|
||||||
|
|
|
@ -72,6 +72,7 @@ data DBState = DBState
|
||||||
, kmBudgetInterval :: !MaybeBounds
|
, kmBudgetInterval :: !MaybeBounds
|
||||||
, kmStatementInterval :: !MaybeBounds
|
, kmStatementInterval :: !MaybeBounds
|
||||||
, kmNewCommits :: ![Int]
|
, kmNewCommits :: ![Int]
|
||||||
|
, kmConfigDir :: FilePath
|
||||||
}
|
}
|
||||||
|
|
||||||
type MappingT m a = ReaderT DBState (SqlPersistT m) a
|
type MappingT m a = ReaderT DBState (SqlPersistT m) a
|
||||||
|
|
|
@ -280,15 +280,18 @@ indexAcntRoot r =
|
||||||
where
|
where
|
||||||
(ars, aprs, ms) = unzip3 $ uncurry tree2Records <$> flattenAcntRoot r
|
(ars, aprs, ms) = unzip3 $ uncurry tree2Records <$> flattenAcntRoot r
|
||||||
|
|
||||||
getDBState :: MonadIO m => Config -> SqlPersistT m DBState
|
getDBState :: MonadIO m => Config -> SqlPersistT m (FilePath -> DBState)
|
||||||
getDBState c = do
|
getDBState c = do
|
||||||
am <- updateAccounts $ accounts c
|
am <- updateAccounts $ accounts c
|
||||||
cm <- updateCurrencies $ currencies c
|
cm <- updateCurrencies $ currencies c
|
||||||
hs <- updateHashes c
|
hs <- updateHashes c
|
||||||
return $ DBState
|
-- TODO not sure how I feel about this, probably will change this struct alot
|
||||||
|
-- in the future so whatever...for now
|
||||||
|
return $ \f -> DBState
|
||||||
{ kmCurrency = cm
|
{ kmCurrency = cm
|
||||||
, kmAccount = am
|
, kmAccount = am
|
||||||
, kmBudgetInterval = intervalMaybeBounds $ budgetInterval $ global c
|
, kmBudgetInterval = intervalMaybeBounds $ budgetInterval $ global c
|
||||||
, kmStatementInterval = intervalMaybeBounds $ statementInterval $ global c
|
, kmStatementInterval = intervalMaybeBounds $ statementInterval $ global c
|
||||||
, kmNewCommits = hs
|
, kmNewCommits = hs
|
||||||
|
, kmConfigDir = f
|
||||||
}
|
}
|
||||||
|
|
|
@ -252,7 +252,7 @@ insertManual m@Manual { manualDate = dp
|
||||||
insertImport :: MonadIO m => Import -> MappingT m ()
|
insertImport :: MonadIO m => Import -> MappingT m ()
|
||||||
insertImport i = whenHash CTImport i $ \c -> do
|
insertImport i = whenHash CTImport i $ \c -> do
|
||||||
bounds <- asks kmStatementInterval
|
bounds <- asks kmStatementInterval
|
||||||
bs <- liftIO $ readImport i
|
bs <- readImport i
|
||||||
-- TODO this isn't efficient, the whole file will be read and maybe no
|
-- TODO this isn't efficient, the whole file will be read and maybe no
|
||||||
-- transactions will be desired
|
-- transactions will be desired
|
||||||
rs <- mapM resolveTx $ filter (inMaybeBounds bounds . txDate) bs
|
rs <- mapM resolveTx $ filter (inMaybeBounds bounds . txDate) bs
|
||||||
|
|
|
@ -7,6 +7,9 @@ module Internal.Statement
|
||||||
( readImport
|
( readImport
|
||||||
) where
|
) where
|
||||||
|
|
||||||
|
import Control.Monad.IO.Class
|
||||||
|
import Control.Monad.Trans.Reader
|
||||||
|
|
||||||
import Data.Bifunctor
|
import Data.Bifunctor
|
||||||
import qualified Data.ByteString.Lazy as BL
|
import qualified Data.ByteString.Lazy as BL
|
||||||
import Data.Csv
|
import Data.Csv
|
||||||
|
@ -20,32 +23,36 @@ import qualified Data.Text.Encoding as TE
|
||||||
import Data.Time
|
import Data.Time
|
||||||
import qualified Data.Vector as V
|
import qualified Data.Vector as V
|
||||||
|
|
||||||
|
import Internal.Database.Model
|
||||||
import Internal.Types
|
import Internal.Types
|
||||||
import Internal.Utils
|
import Internal.Utils
|
||||||
|
|
||||||
import Numeric.Natural
|
import Numeric.Natural
|
||||||
|
|
||||||
|
import System.FilePath
|
||||||
|
|
||||||
-- TODO this probably won't scale well (pipes?)
|
-- TODO this probably won't scale well (pipes?)
|
||||||
|
|
||||||
readImport :: Import -> IO [BalTx]
|
readImport :: MonadIO m => Import -> MappingT m [BalTx]
|
||||||
readImport Import { impPaths = ps
|
readImport Import { impPaths = ps
|
||||||
, impMatches = ms
|
, impMatches = ms
|
||||||
, impTxOpts = ns
|
, impTxOpts = ns
|
||||||
, impDelim = d
|
, impDelim = d
|
||||||
, impSkipLines = n
|
, impSkipLines = n
|
||||||
-- , impTx = f
|
|
||||||
} = do
|
} = do
|
||||||
rs <- L.sort . concat <$> mapM (readImport_ n d ns) ps
|
rs <- L.sort . concat <$> mapM (readImport_ n d ns) ps
|
||||||
let (ts, es, notfound) = matchRecords ms rs
|
let (ts, es, notfound) = matchRecords ms rs
|
||||||
mapM_ putStrLn $ reverse es
|
liftIO $ mapM_ putStrLn $ reverse es
|
||||||
mapM_ print notfound
|
liftIO $ mapM_ print notfound
|
||||||
return ts
|
return ts
|
||||||
|
|
||||||
readImport_ :: Natural -> Word -> TxOpts -> FilePath -> IO [TxRecord]
|
readImport_ :: MonadIO m => Natural -> Word -> TxOpts -> FilePath
|
||||||
|
-> MappingT m [TxRecord]
|
||||||
readImport_ n delim tns p = do
|
readImport_ n delim tns p = do
|
||||||
bs <- BL.readFile p
|
dir <- asks kmConfigDir
|
||||||
|
bs <- liftIO $ BL.readFile $ dir </> p
|
||||||
case decodeByNameWithP (parseTxRecord tns) opts $ skip bs of
|
case decodeByNameWithP (parseTxRecord tns) opts $ skip bs of
|
||||||
Left m -> putStrLn m >> return []
|
Left m -> liftIO $ putStrLn m >> return []
|
||||||
Right (_, v) -> return $ catMaybes $ V.toList v
|
Right (_, v) -> return $ catMaybes $ V.toList v
|
||||||
where
|
where
|
||||||
opts = defaultDecodeOptions { decDelimiter = fromIntegral delim }
|
opts = defaultDecodeOptions { decDelimiter = fromIntegral delim }
|
||||||
|
|
|
@ -45,6 +45,7 @@ dependencies:
|
||||||
- optparse-applicative
|
- optparse-applicative
|
||||||
- recursion-schemes
|
- recursion-schemes
|
||||||
- data-fix
|
- data-fix
|
||||||
|
- filepath
|
||||||
|
|
||||||
library:
|
library:
|
||||||
source-dirs: lib/
|
source-dirs: lib/
|
||||||
|
|
Loading…
Reference in New Issue