feat: setup: first setup check: is hledger in PATH ?

This commit is contained in:
Simon Michael 2025-04-17 01:26:11 -10:00
parent cff831c3c0
commit 69232cae7a
5 changed files with 138 additions and 38 deletions

View File

@ -421,7 +421,7 @@ main = exitOnExceptions $ withGhcDebug' $ do
| manFlag -> runManForTopic "hledger" mmodecmdname
-- 6.5.2. builtin command which should not require or read the journal - run it
| cmdname `elem` ["commands","demo","help","test"] ->
| cmdname `elem` ["commands","demo","help","setup","test"] ->
cmdaction opts (ignoredjournal cmdname)
-- 6.5.3. builtin command which should create the journal if missing - do that and run it

View File

@ -295,7 +295,7 @@ commandsList progversion othercmds =
," diff compare an account's transactions in two journals"
,"+git save or view journal file history simply in git" -- hledger-git
,"+pijul save or view journal file history simply in pijul" -- hledger-pijul
," setup check and help set up various installation things"
," setup check and show the status of the hledger installation"
," test run some self tests"
,""
-----------------------------------------80-------------------------------------

View File

@ -1,6 +1,8 @@
{-|
Check and help set up various installation things.
Check and show the status of the hledger installation,
show extra info and hints,
and offer to fix problems where possible.
-}
@ -15,27 +17,18 @@ module Hledger.Cli.Commands.Setup (
)
where
-- import Data.Default (def)
-- import System.FilePath (takeFileName)
-- import Data.List (intercalate, nub, sortOn)
-- import Data.List.Extra (nubSort)
-- import qualified Data.Map as Map
-- import Data.Maybe (fromMaybe)
-- import Data.HashSet (size, fromList)
-- import qualified Data.Text as T
-- import qualified Data.Text.Lazy as TL
-- import qualified Data.Text.Lazy.Builder as TB
-- import Data.Time.Calendar (Day, addDays, diffDays)
-- import Data.Time.Clock.POSIX (getPOSIXTime)
-- import GHC.Stats
-- -- import System.Console.CmdArgs.Explicit hiding (Group)
-- import System.Mem (performMajorGC)
-- import Text.Printf (printf)
-- import Text.Tabular.AsciiWide
import System.FilePath
import Data.Text (Text)
import qualified Data.Text as T
import qualified Data.Text.IO as T
import Hledger
import Hledger.Cli.CliOptions
-- import Hledger.Cli.Utils (writeOutputLazyText)
import Control.Monad
import System.Info
import System.Directory
import System.IO
import Safe
-- import Text.Printf (printf)
setupmode = hledgerCommandMode
@ -45,20 +38,127 @@ setupmode = hledgerCommandMode
hiddenflags
([], Just $ argsFlag "[QUERY]")
-- like Register.summarisePostings
-- | Print various statistics for the journal.
-- | 1. Check and show the status of various aspects of the hledger installation.
-- 2. Show extra info and hints on how to fix problems.
-- 3. When possible, offer to help fix problems, interactively.
setup :: CliOpts -> Journal -> IO ()
setup _opts@CliOpts{rawopts_=_rawopts, reportspec_=_rspec} _j = do
print "setup"
setup _opts@CliOpts{rawopts_=_rawopts, reportspec_=_rspec} _ignoredj = do
-- This command is not given a journal and should not use _ignoredj;
-- instead detect it ourselves when we are ready.
let
p ok ymsg nmsg =
putStrLn $ unwords $ if ok then ["", y, "", ymsg] else ["", n, "", nmsg]
where
y = "yes ✅"
n = "no ❌"
putStrLn "hledger:"
-- let today = _rsDay rspec
-- verbose = boolopt "verbose" rawopts
-- q = _rsQuery rspec
-- l = ledgerFromJournal q j
-- intervalspans = snd $ reportSpanBothDates j rspec
-- ismultiperiod = length intervalspans > 1
-- (ls, txncounts) = unzip $ map (showLedgerStats verbose l today) intervalspans
-- numtxns = sum txncounts
-- txt = (if ismultiperiod then id else TL.init) $ TB.toLazyText $ unlinesB ls
-- writeOutputLazyText opts txt
putStr "- in PATH ?"
pathexes <- findExecutables progname
home <- getHomeDirectory
appdata <- getXdgDirectory XdgData ""
otherexes <- flip findExecutablesInDirectories progname $
[home </> ".local/bin"
,home </> ".cabal/bin"
,home </> ".nix-profile/bin"
,"/opt/homebrew/bin"
,"/usr/local/bin"
,"/usr/bin"
]
++ [appdata </> "local/bin" | os == "mingw32"]
++ [appdata </> "cabal/bin" | os == "mingw32"]
let
ok = not $ null pathexes
pathexe = quoteIfNeeded $ headDef (error' "showing nonexistent executable") pathexes
otherexe = quoteIfNeeded $ headDef (error' "showing nonexistent executable") otherexes
otherdir = takeDirectory otherexe
hint = if null otherexes
then ("Add " <> progname <> "'s directory to your shell's PATH.")
else unlines
["Add " <> otherdir <> " to PATH in your shell config."
," Eg on unix: echo 'export PATH=" <> otherdir <> ":$PATH' >> ~/.profile"
," and start a new shell session."
]
p ok pathexe hint
-- putStr "- runnable ?"
-- putStr "- up to date ?"
-- putStr "- native binary ?"
-- putStr "- eget installed ?"
putStr "\n"
-- putStrLn "config:"
-- putStr "- user config file exists ?"
-- putStr "\n"
-- putStr "- local config masking user config ?"
-- putStr "\n"
-- putStr "- config file readable ?"
-- putStr "\n"
-- putStr "- common general options configured ?"
-- putStr "\n"
-- putStr " --pretty --ignore-assertions --infer-costs"
-- putStr "\n"
-- putStr " print --explicit --show-costs"
-- putStr "\n"
-- putStr "\n"
-- putStrLn "files:"
-- putStr "- default journal file exists ?"
-- putStr "\n"
-- putStr "- default journal file readable ?"
-- putStr "\n"
-- putStr "\n"
-- putStrLn "accounts:"
-- putStr "- all account types declared or detected ?"
-- putStr "\n"
-- putStr " asset, liability, equity, revenue, expense, cash, conversion"
-- putStr "\n"
-- putStr "- untyped accounts ?"
-- putStr "\n"
-- putStr "- all used accounts declared ?"
-- putStr "\n"
-- putStr "\n"
-- putStrLn "commodities:"
-- putStr "- all used commodities declared ?"
-- putStr "\n"
-- putStr "\n"
-- putStrLn "tags:"
-- putStr "- all used tags declared ?"
-- putStr "\n"
-- putStr "\n"
{- | Ensure there is a journal file at the given path, creating an empty one if needed.
On Windows, also ensure that the path contains no trailing dots
which could cause data loss (see 'isWindowsUnsafeDotPath').
-}
_ensureJournalFileExists :: FilePath -> IO ()
_ensureJournalFileExists f = do
when (os == "mingw32" && isWindowsUnsafeDotPath f) $
error' $
"Part of file path \"" <> show f <> "\"\n ends with a dot, which is unsafe on Windows; please use a different path.\n"
exists <- doesFileExist f
unless exists $ do
hPutStrLn stderr $ "Creating hledger journal file " <> show f
-- note Hledger.Utils.UTF8.* do no line ending conversion on windows,
-- we currently require unix line endings on all platforms.
newJournalContent >>= T.writeFile f
{- | Does any part of this path contain non-. characters and end with a . ?
Such paths are not safe to use on Windows (cf #1056).
-}
isWindowsUnsafeDotPath :: FilePath -> Bool
isWindowsUnsafeDotPath = any (\x -> last x == '.' && any (/= '.') x) . splitDirectories
-- | Give the content for a new auto-created journal file.
newJournalContent :: IO Text
newJournalContent = do
d <- getCurrentDay
return $ "; journal created " <> T.pack (show d) <> " by hledger\n"

View File

@ -1,6 +1,6 @@
## setup
Check and help set up various installation things.
Check and show the status of the hledger installation.
```flags
Flags:

View File

@ -6515,7 +6515,7 @@ If you have installed more [add-on commands](../scripts.md), they also will be l
- [check](#check) - check for various kinds of error in the data
- [diff](#diff) - compare account transactions in two journal files
- [setup](#setup) - check and help set up various installation things
- [setup](#setup) - check and show the status of the hledger installation
- [test](#test) - run self tests