maxsize overview display and --json support

This commit is contained in:
Joey Hess 2024-08-18 11:18:16 -04:00
parent 016edcf437
commit 99514f9d18
No known key found for this signature in database
GPG key ID: DB12DB0FF05F8F38
8 changed files with 109 additions and 27 deletions

View file

@ -21,7 +21,7 @@ git-annex (10.20240831) UNRELEASED; urgency=medium
* Support "balanced=" and "fullybalanced=" in preferred content expressions. * Support "balanced=" and "fullybalanced=" in preferred content expressions.
* Added --rebalance option. * Added --rebalance option.
* maxsize: New command to tell git-annex how large the expected maximum * maxsize: New command to tell git-annex how large the expected maximum
size of a repository is. size of a repository is, and to display repository sizes.
* vicfg: Include maxsize configuration. * vicfg: Include maxsize configuration.
* info: Improved speed. * info: Improved speed.

View file

@ -573,7 +573,8 @@ reposizes_stats count desc m = stat desc $ nojson $ do
let maxlen = maximum (map (length . snd) l) let maxlen = maximum (map (length . snd) l)
descm <- lift Remote.uuidDescriptions descm <- lift Remote.uuidDescriptions
-- This also handles json display. -- This also handles json display.
s <- lift $ Remote.prettyPrintUUIDsWith (Just "size") desc descm (Just . show) $ s <- lift $ Remote.prettyPrintUUIDsWith (Just "size") desc descm
(\sz -> Just $ show sz ++ ": ") $
map (\(u, sz) -> (u, Just $ mkdisp sz maxlen)) l map (\(u, sz) -> (u, Just $ mkdisp sz maxlen)) l
return $ if count return $ if count
then countRepoList (length l) s then countRepoList (length l) s

View file

@ -5,21 +5,28 @@
- Licensed under the GNU AGPL version 3 or higher. - Licensed under the GNU AGPL version 3 or higher.
-} -}
{-# LANGUAGE OverloadedStrings #-}
module Command.MaxSize where module Command.MaxSize where
import Command import Command
import qualified Remote import qualified Remote
import Annex.RepoSize
import Types.RepoSize
import Logs.MaxSize import Logs.MaxSize
import Utility.SafeOutput import Logs.Trust
import Utility.DataUnits import Utility.DataUnits
import qualified Data.Map as M import qualified Data.Map as M
import qualified Data.Set as S
import qualified Data.Text as T
cmd :: Command cmd :: Command
cmd = noMessages $ command "maxsize" SectionSetup cmd = noMessages $ withAnnexOptions [jsonOptions] $
"configure maximum size of repositoriy" command "maxsize" SectionSetup
(paramPair paramRepository (paramOptional paramSize)) "configure maximum size of repositoriy"
(seek <$$> optParser) (paramPair paramRepository (paramOptional paramSize))
(seek <$$> optParser)
data MaxSizeOptions = MaxSizeOptions data MaxSizeOptions = MaxSizeOptions
{ cmdparams :: CmdParams { cmdparams :: CmdParams
@ -37,16 +44,17 @@ optParser desc = MaxSizeOptions
seek :: MaxSizeOptions -> CommandSeek seek :: MaxSizeOptions -> CommandSeek
seek o = case cmdparams o of seek o = case cmdparams o of
(rname:[]) -> commandAction $ do (rname:[]) -> commandAction $ do
u <- Remote.nameToUUID rname enableNormalOutput
startingCustomOutput (ActionItemOther Nothing) $ do showCustom "maxsize" (SeekInput [rname]) $ do
u <- Remote.nameToUUID rname
v <- M.lookup u <$> getMaxSizes v <- M.lookup u <$> getMaxSizes
liftIO $ putStrLn $ safeOutput $ case v of maybeAddJSONField "maxsize" (fromMaxSize <$> v)
showRaw $ encodeBS $ case v of
Just (MaxSize n) -> Just (MaxSize n) ->
if bytesOption o formatSize o (preciseSize storageUnits True) n
then show n
else preciseSize storageUnits False n
Nothing -> "" Nothing -> ""
next $ return True return True
stop
(rname:sz:[]) -> commandAction $ do (rname:sz:[]) -> commandAction $ do
u <- Remote.nameToUUID rname u <- Remote.nameToUUID rname
let si = SeekInput (cmdparams o) let si = SeekInput (cmdparams o)
@ -57,4 +65,51 @@ seek o = case cmdparams o of
Just n -> do Just n -> do
recordMaxSize u (MaxSize n) recordMaxSize u (MaxSize n)
next $ return True next $ return True
_ -> giveup "Specify a repository." [] -> commandAction $ sizeOverview o
_ -> giveup "Too many parameters"
sizeOverview :: MaxSizeOptions -> CommandStart
sizeOverview o = do
enableNormalOutput
showCustom "maxsize" (SeekInput []) $ do
descmap <- Remote.uuidDescriptions
deadset <- S.fromList <$> trustGet DeadTrusted
maxsizes <- getMaxSizes
reposizes <- flip M.withoutKeys deadset <$> getRepoSizes True
let l = reverse $ sortOn snd $ M.toList $
M.mapWithKey (gather maxsizes) reposizes
v <- Remote.prettyPrintUUIDsWith' False (Just "size")
"repositories" descmap showsizes l
showRaw $ encodeBS $ tableheader
showRaw $ encodeBS $ dropWhileEnd (== '\n') v
return True
stop
where
sizefield = "size" :: T.Text
maxsizefield = "maxsize" :: T.Text
gather maxsizes u (RepoSize currsize) = Just $
M.fromList
[ (sizefield, Just currsize)
, (maxsizefield, fromMaxSize <$> M.lookup u maxsizes)
]
tableheader = tablerow ["size", "maxsize", "repository"]
showsizes m = do
size <- M.lookup sizefield m
maxsize <- M.lookup maxsizefield m
return $ tablerow [formatsize size, formatsize maxsize, ""]
formatsize = maybe "" (formatSize o (roughSize' storageUnits True 0))
padcolumn s = replicate (7 - length s) ' ' ++ s
tablerow [] = ""
tablerow (s:[]) = " " ++ s
tablerow (s:l) = padcolumn s ++ " " ++ tablerow l
formatSize :: MaxSizeOptions -> (ByteSize -> String) -> ByteSize -> String
formatSize o f n
| bytesOption o = show n
| otherwise = f n

View file

@ -55,6 +55,7 @@ module Messages (
mkPrompter, mkPrompter,
sanitizeTopLevelExceptionMessages, sanitizeTopLevelExceptionMessages,
countdownToMessage, countdownToMessage,
enableNormalOutput,
) where ) where
import Control.Concurrent import Control.Concurrent
@ -87,9 +88,7 @@ showStartMessage (StartMessage command ai si) =
where where
json = JSON.startActionItem command ai si json = JSON.startActionItem command ai si
showStartMessage (StartUsualMessages command ai si) = do showStartMessage (StartUsualMessages command ai si) = do
outputType <$> Annex.getState Annex.output >>= \case enableNormalOutput
QuietOutput -> Annex.setOutput NormalOutput
_ -> noop
showStartMessage (StartMessage command ai si) showStartMessage (StartMessage command ai si)
showStartMessage (StartNoMessage _) = noop showStartMessage (StartNoMessage _) = noop
showStartMessage (CustomOutput _) = showStartMessage (CustomOutput _) =
@ -379,3 +378,9 @@ countdownToMessage n showmsg
| otherwise = do | otherwise = do
let !n' = pred n let !n' = pred n
return n' return n'
enableNormalOutput :: Annex ()
enableNormalOutput =
outputType <$> Annex.getState Annex.output >>= \case
QuietOutput -> Annex.setOutput NormalOutput
_ -> noop

View file

@ -40,6 +40,7 @@ module Remote (
prettyPrintUUIDs, prettyPrintUUIDs,
prettyPrintUUIDsDescs, prettyPrintUUIDsDescs,
prettyPrintUUIDsWith, prettyPrintUUIDsWith,
prettyPrintUUIDsWith',
prettyListUUIDs, prettyListUUIDs,
prettyUUID, prettyUUID,
remoteFromUUID, remoteFromUUID,
@ -229,11 +230,25 @@ prettyPrintUUIDsWith
-> (v -> Maybe String) -> (v -> Maybe String)
-> [(UUID, Maybe v)] -> [(UUID, Maybe v)]
-> Annex String -> Annex String
prettyPrintUUIDsWith optfield header descm showval uuidvals = do prettyPrintUUIDsWith = prettyPrintUUIDsWith' True
prettyPrintUUIDsWith'
:: ToJSON' v
=> Bool
-> Maybe String
-> String
-> UUIDDescMap
-> (v -> Maybe String)
-> [(UUID, Maybe v)]
-> Annex String
prettyPrintUUIDsWith' indented optfield header descm showval uuidvals = do
hereu <- getUUID hereu <- getUUID
maybeShowJSON $ JSONChunk [(header, V.fromList $ map (jsonify hereu) uuidvals)] maybeShowJSON $ JSONChunk [(header, V.fromList $ map (jsonify hereu) uuidvals)]
return $ unwords $ map (\u -> "\t" ++ prettify hereu u ++ "\n") uuidvals return $ concatMap
(\u -> tabindent ++ prettify hereu u ++ "\n")
uuidvals
where where
tabindent = if indented then "\t" else ""
finddescription u = fromUUIDDesc $ M.findWithDefault mempty u descm finddescription u = fromUUIDDesc $ M.findWithDefault mempty u descm
prettify hereu (u, optval) prettify hereu (u, optval)
| not (null d) = addoptval $ fromUUID u ++ " -- " ++ d | not (null d) = addoptval $ fromUUID u ++ " -- " ++ d
@ -247,7 +262,7 @@ prettyPrintUUIDsWith optfield header descm showval uuidvals = do
| otherwise = n | otherwise = n
addoptval s = case showval =<< optval of addoptval s = case showval =<< optval of
Nothing -> s Nothing -> s
Just val -> val ++ ": " ++ s Just val -> val ++ s
jsonify hereu (u, optval) = object $ catMaybes jsonify hereu (u, optval) = object $ catMaybes
[ Just ("uuid", toJSON' (fromUUID u :: String)) [ Just ("uuid", toJSON' (fromUUID u :: String))
, Just ("description", toJSON' $ finddescription u) , Just ("description", toJSON' $ finddescription u)

View file

@ -10,9 +10,9 @@
module Types.RepoSize where module Types.RepoSize where
-- The current size of a repo. -- The current size of a repo.
newtype RepoSize = RepoSize Integer newtype RepoSize = RepoSize { fromRepoSize :: Integer }
deriving (Show, Eq, Ord, Num) deriving (Show, Eq, Ord, Num)
-- The maximum size of a repo. -- The maximum size of a repo.
newtype MaxSize = MaxSize Integer newtype MaxSize = MaxSize { fromMaxSize :: Integer }
deriving (Show, Eq, Ord) deriving (Show, Eq, Ord)

View file

@ -8,11 +8,15 @@ git annex maxsize repository size
git annex maxsize repository git annex maxsize repository
git annex maxsize
# DESCRIPTION # DESCRIPTION
This configures the maximum combined size of annexed files that can be This configures the maximum combined size of annexed files that can be
stored in a repository. When run without a size, stored in a repository. When run with a repository but without a size,
it displays the currently configured maxsize. it displays the currently configured maxsize. When run without a
repository, it displays an overview of the size and maxsize of all
repositories.
The repository can be specified by git remote name or The repository can be specified by git remote name or
by uuid. For the current repository, use "here". by uuid. For the current repository, use "here".
@ -35,6 +39,10 @@ gigabyte, then it would make sense to run
Displays the maximum size in bytes, disabling the default nicer units. Displays the maximum size in bytes, disabling the default nicer units.
* `--json`
Enable JSON output.
* The [[git-annex-common-options]](1) can also be used. * The [[git-annex-common-options]](1) can also be used.
# SEE ALSO # SEE ALSO

View file

@ -86,8 +86,6 @@ Planned schedule of work:
overLocationLogs. In the other path it does not, and this should be fixed overLocationLogs. In the other path it does not, and this should be fixed
for consistency and correctness. for consistency and correctness.
* `git-annex info` can use maxsize to display how full repositories are
* implement size-based balancing, so all balanced repositories are around * implement size-based balancing, so all balanced repositories are around
the same percent full, either as the default or as another preferred the same percent full, either as the default or as another preferred
content expression. content expression.