module Command.Map where
-import qualified Data.Map as M
-
import Command
import qualified Git
import qualified Git.Url
import Types.TrustLevel
import qualified Remote.Helper.Ssh as Ssh
import qualified Utility.Dot as Dot
+import qualified Messages.JSON as JSON
+import Messages.JSON ((.=))
+import Utility.Aeson (packString)
+
+import qualified Data.Map as M
-- a repo and its remotes
type RepoRemotes = (Git.Repo, [Git.Repo])
cmd :: Command
-cmd = dontCheck repoExists $
+cmd = dontCheck repoExists $ withAnnexOptions [jsonOptions] $
command "map" SectionQuery
"generate map of repositories"
paramNothing (withParams seek)
umap <- uuidDescMap
trustmap <- trustMapLoad
- file <- (</>)
- <$> fromRepo gitAnnexDir
- <*> pure (literalOsPath "map.dot")
-
- liftIO $ writeFile (fromOsPath file) (drawMap rs trustmap umap)
- next $
- ifM (Annex.getRead Annex.fast)
- ( runViewer file []
- , runViewer file
- [ ("xdot", [File (fromOsPath file)])
- , ("dot", [Param "-Tx11", File (fromOsPath file)])
- ]
- )
+ ifM (outputJSONMap rs trustmap umap)
+ ( next $ return True
+ , do
+ file <- (</>)
+ <$> fromRepo gitAnnexDir
+ <*> pure (literalOsPath "map.dot")
+
+ liftIO $ writeFile (fromOsPath file) (drawMap rs trustmap umap)
+ next $
+ ifM (Annex.getRead Annex.fast)
+ ( runViewer file []
+ , runViewer file
+ [ ("xdot", [File (fromOsPath file)])
+ , ("dot", [Param "-Tx11", File (fromOsPath file)])
+ ]
+ )
+ )
runViewer :: OsPath -> [(String, [CommandParam])] -> Annex Bool
runViewer file [] = do
{- reads the config of a remote, with progress display -}
scan :: Git.Repo -> Annex Git.Repo
scan r = do
- showStartMessage (StartMessage "map" (ActionItemOther (Just $ UnquotedString $ Git.repoDescribe r)) (SeekInput []))
+ unlessM jsonOutputEnabled $
+ showStartMessage (StartMessage "map" (ActionItemOther (Just $ UnquotedString $ Git.repoDescribe r)) (SeekInput []))
v <- tryScan r
case v of
Just r' -> do
configlist
ok -> return ok
- sshnote = do
+ sshnote = unlessM jsonOutputEnabled $ do
showAction "sshing"
showOutput
case result of
Left _ -> return Nothing
Right r' -> return $ Just r'
+
+outputJSONMap :: [RepoRemotes] -> TrustMap -> UUIDDescMap -> Annex Bool
+outputJSONMap rs trustmap umap =
+ showFullJSON $ JSON.AesonObject $ case mapo of
+ JSON.Object obj -> obj
+ _ -> error "internal"
+ where
+ mapo = JSON.object
+ [ "nodes" .= map mknode (filterdead fst rs)
+ ]
+
+ mknode (r, remotes) = JSON.object
+ [ "name" .= packString (repoName umap r)
+ , "uuid" .= mkuuid (getUncachedUUID r)
+ , "url" .= packString (Git.repoLocation r)
+ , "remotes" .= map mkremote (filterdead id remotes)
+ ]
+
+ mkremote r = JSON.object
+ [ "name" .= packString (repoName umap r)
+ , "uuid" .= mkuuid (getUncachedUUID r)
+ , "url" .= packString (Git.repoLocation r)
+ ]
+
+ mkuuid NoUUID = Nothing
+ mkuuid u = Just $ packString $ fromUUID u
+
+ filterdead f = filter
+ (\i -> M.lookup (getUncachedUUID (f i)) trustmap /= Just DeadTrusted)
+
--- /dev/null
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 2"""
+ date="2025-05-28T18:11:34Z"
+ content="""
+I went ahead and implemented `git-annx map --json`.
+
+Example output, after being passed through `jq` to pretty-print it:
+
+ {
+ "nodes": [
+ {
+ "name": "joey@darkstar:~/tmp/mapbench/a",
+ "remotes": [
+ {
+ "name": "joey@darkstar:~/tmp/mapbench/b",
+ "url": "/home/joey/tmp/mapbench/b",
+ "uuid": "645d92d8-6461-43c1-b23c-6dd04dc3a015"
+ }
+ ],
+ "url": "/home/joey/tmp/mapbench/a",
+ "uuid": "3f34e4c2-dd19-433a-ab04-9fd4be959325"
+ },
+ {
+ "name": "joey@darkstar:~/tmp/mapbench/b",
+ "remotes": [
+ {
+ "name": "joey@darkstar:~/tmp/mapbench/a",
+ "url": "/home/joey/tmp/mapbench/a",
+ "uuid": "3f34e4c2-dd19-433a-ab04-9fd4be959325"
+ }
+ ],
+ "url": "/home/joey/tmp/mapbench/b",
+ "uuid": "645d92d8-6461-43c1-b23c-6dd04dc3a015"
+ },
+ {
+ "name": "unknown",
+ "remotes": [
+ {
+ "name": "joey@darkstar:~/tmp/mapbench/b",
+ "url": "/home/joey/tmp/mapbench/b",
+ "uuid": "645d92d8-6461-43c1-b23c-6dd04dc3a015"
+ }
+ ],
+ "url": ".",
+ "uuid": null
+ }
+ ],
+ "error-messages": []
+ }
+"""]]