Parse nix path-info output
in pkgs.mkShell {
nativeBuildInputs = [
- (haskellPackages.ghcWithPackages (p: with p; [ typed-process ]))
+ (haskellPackages.ghcWithPackages (p: with p; [ aeson typed-process ]))
haskellPackages.ghcid
haskellPackages.haskell-language-server
{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE RecordWildCards #-}
-import System.Process.Typed (runProcess_)
+import Data.Aeson qualified as Aeson
+import Data.Aeson (ToJSON(..), FromJSON(..), Value(..), (.:), (.=), object)
+import Data.Aeson.Types (prependFailure, typeMismatch)
+import Data.Text (Text)
+import GHC.Base (quotInt)
+import System.Process.Typed (readProcess_, proc)
main :: IO ()
main = do
- runProcess_ "false"
+ let gcroot = "per-user/avh4/current-home"
+ (json, _) <- readProcess_ $ proc "nix" [ "--extra-experimental-features", "nix-command"
+ , "path-info"
+ , "--recursive"
+ , "--size"
+ , "--json"
+ , "/nix/var/nix/gcroots/" ++ gcroot
+ ]
+ let pathInfos = Aeson.eitherDecode json :: Either String [PathInfo]
+ print $ fmap (formatFileSize. totalSize) pathInfos
+ return ()
+totalSize :: (Foldable f, Functor f) => f PathInfo -> Int
+totalSize = sum . fmap pathInfoNarSize
+
+formatFileSize :: Int -> String
+formatFileSize s
+ | s >= 10*1024*1024*1024 = show (s `quotInt` (1024*1024*1024)) ++ "GB"
+ | s >= 10*1024*1024 = show (s `quotInt` (1024*1024)) ++ "MB"
+ | s >= 10*1024 = show (s `quotInt` 1024) ++ "kb"
+ | otherwise = show s ++ "b"
+
+data PathInfo = PathInfo
+ { pathInfoNarSize :: Int
+ , pathInfoPath :: Text
+ } deriving (Show, Eq)
+
+instance FromJSON PathInfo where
+ parseJSON (Object v) = do
+ pathInfoNarSize <- v .: "narSize"
+ pathInfoPath <- v .: "path"
+ pure $ PathInfo{..}
+ parseJSON invalid = do
+ prependFailure "parsing PathInfo failed, "
+ (typeMismatch "Object" invalid)