From db00f634979c751a8fcead56882bca67c5db29a1 Mon Sep 17 00:00:00 2001 From: Tim Emiola Date: Tue, 6 Feb 2024 14:15:15 +0900 Subject: [PATCH 1/3] The title indicates the inclusion of pid or process count --- src/System/MemInfo/Print.hs | 33 +++++++---- test/MemInfo/PrintSpec.hs | 113 ++++++++++++++++++++++++++++++------ 2 files changed, 117 insertions(+), 29 deletions(-) diff --git a/src/System/MemInfo/Print.hs b/src/System/MemInfo/Print.hs index d48e284..a396d83 100644 --- a/src/System/MemInfo/Print.hs +++ b/src/System/MemInfo/Print.hs @@ -1,6 +1,8 @@ {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE TypeApplications #-} {- | Module : System.MemInfo.Print @@ -18,6 +20,7 @@ module System.MemInfo.Print ( styleOutput, ) where +import Data.Proxy (Proxy (..)) import qualified Data.Text as Text import Fmt ( build, @@ -110,17 +113,19 @@ fmtMem' = in go -hdrPrivate, hdrShared, hdrRamUsed, hdrSwapUsed, hdrProgram :: Text +hdrPrivate, hdrShared, hdrRamUsed, hdrSwapUsed, hdrProgram, hdrCount, hdrPid :: Text hdrPrivate = "Private" hdrShared = "Shared" hdrRamUsed = "RAM Used" hdrSwapUsed = "Swap Used" hdrProgram = "Program" +hdrCount = "(# processes)" +hdrPid = "[pid]" -- | Generates the text of the printed header of the memory report -fmtAsHeader :: Bool -> Text -fmtAsHeader showSwap = +fmtAsHeader :: Bool -> Bool -> Text +fmtAsHeader hasPid showSwap = let padb = padBothF columnWidth ' ' padr = padRightF columnWidth ' ' @@ -128,7 +133,8 @@ fmtAsHeader showSwap = private = padb hdrPrivate shared = padb hdrShared all' = padl hdrRamUsed - name' = padr hdrProgram + nameExt = if hasPid then hdrPid else hdrCount + name' = padr $ hdrProgram <> " " <> nameExt swap' = padl hdrSwapUsed ram = private |+ " + " +| shared |+ " = " +| all' numbers = if showSwap then ram +| swap' else ram @@ -137,13 +143,14 @@ fmtAsHeader showSwap = -- | Generates the text of the printed header of the memory report -fmtAsHeaderCsv :: Bool -> Text -fmtAsHeaderCsv showSwap = +fmtAsHeaderCsv :: Bool -> Bool -> Text +fmtAsHeaderCsv hasPid showSwap = let private = build hdrPrivate shared = build hdrShared all' = build hdrRamUsed - name' = build hdrProgram + nameExt = if hasPid then hdrPid else hdrCount + name' = build $ hdrProgram <> " " <> nameExt swap' = build hdrSwapUsed ram = private |+ "," +| shared |+ "," +| all' |+ "," numbers = if showSwap then ram +| swap' |+ "," else ram @@ -165,14 +172,20 @@ class AsCmdName a where cmdWithCount :: a -> Int -> Text + -- Indicate if pid or process count should shown in the hdr + hdrHasPid :: Proxy a -> Bool + + instance AsCmdName Text where asCmdName = id cmdWithCount cmd count = "" +| asCmdName cmd |+ " (" +| count |+ ")" + hdrHasPid _ = False instance AsCmdName (ProcessID, Text) where asCmdName (pid, name) = "" +| name |+ " [" +| toInteger pid |+ "]" cmdWithCount cmd _count = "" +| asCmdName cmd |+ "" + hdrHasPid _ = True overallTotals :: [MemUsage] -> (Int, Int) @@ -188,12 +201,12 @@ data Printers a = Printers } -printStyle :: (AsCmdName a) => Style -> Bool -> Printers a +printStyle :: forall a. (AsCmdName a) => Style -> Bool -> Printers a printStyle style showSwap = let usageFmt Normal = fmtMemUsage usageFmt Csv = fmtMemUsageCsv - headerFmt Normal = fmtAsHeader - headerFmt Csv = fmtAsHeaderCsv + headerFmt Normal = fmtAsHeader (hdrHasPid @a Proxy) + headerFmt Csv = fmtAsHeaderCsv (hdrHasPid @a Proxy) overallFmt Normal x = Just $ fmtOverall showSwap x overallFmt Csv _ = Nothing in Printers diff --git a/test/MemInfo/PrintSpec.hs b/test/MemInfo/PrintSpec.hs index 8248f9b..f687cbc 100644 --- a/test/MemInfo/PrintSpec.hs +++ b/test/MemInfo/PrintSpec.hs @@ -11,7 +11,8 @@ module MemInfo.PrintSpec (spec) where import Data.Text (Text) import qualified Data.Text as Text -import System.MemInfo.Print (fmtAsHeader, fmtMemUsage, fmtOverall) +import System.MemInfo.Choices (Style (Csv, Normal)) +import System.MemInfo.Print (fmtAsHeader, fmtMemUsage, fmtOverall, styleOutput) import System.MemInfo.Proc (MemUsage (..)) import System.Posix.Types (ProcessID) import Test.Hspec @@ -22,35 +23,106 @@ spec = describe "module System.MemInfo.Print" $ do fmtAsHeaderSpec fmtOverallSpec fmtMemUsageSpec + styleOutputSpec + + +styleOutputSpec :: Spec +styleOutputSpec = describe "styleOutput" $ do + describe "when accurate and swap shown" $ do + let count = 6 + usage = sampleUsage' count + styleOutput' s = styleOutput True s True + describe "when style is csv" $ do + let style = Csv + describe "when discriminating by pid" $ do + let want = + [ "Private,Shared,RAM Used,Swap Used,Program [pid]" + , "1,1,2,4,by-id-and-name-cmd [100]" + ] + it "should generate the expected output" $ do + styleOutput' style [(biName, usage)] `shouldBe` want + + describe "not discriminating by pid" $ do + let want = + [ "Private,Shared,RAM Used,Swap Used,Program (# processes)" + , "1,1,2,4,by-name-cmd (6)" + ] + it "should generate the expected output" $ do + styleOutput' style [(monoName, usage)] `shouldBe` want + + describe "when accurate and no swap shown" $ do + let count = 6 + usage = sampleUsage' count + styleOutput' s = styleOutput False s True + describe "when style is normal" $ do + let style = Normal + wantedSummary = + Text.unlines + [ "------------------------------------" + , " 2.0 KiB" + , "====================================" + ] + describe "when discriminating by pid" $ do + let want = + [ " Private + Shared = RAM Used\tProgram [pid]" + , " 1.0 KiB + 1.0 KiB = 2.0 KiB\tby-id-and-name-cmd [100]" + , wantedSummary + ] + it "should generate the expected output" $ do + styleOutput' style [(biName, usage)] `shouldBe` want + + describe "not discriminating by pid" $ do + let want = + [ " Private + Shared = RAM Used\tProgram (# processes)" + , " 1.0 KiB + 1.0 KiB = 2.0 KiB\tby-name-cmd (6)" + , wantedSummary + ] + it "should generate the expected output" $ do + styleOutput' style [(monoName, usage)] `shouldBe` want fmtAsHeaderSpec :: Spec fmtAsHeaderSpec = describe "fmtAsHeader" $ do - describe "when swap is not required" $ do - it "does not show it" $ - fmtAsHeader False `shouldBe` headerNoSwap + describe "when discriminating by pid" $ do + let byPid = True + describe "when swap is not required" $ do + it "does not show it" $ do + fmtAsHeader byPid False `shouldBe` headerNoSwap - describe "when swap is required" $ do - it "does show it" $ - fmtAsHeader True `shouldBe` headerSwap + describe "when swap is required" $ do + it "does show it" $ do + fmtAsHeader byPid True `shouldBe` headerSwap + + describe "when not discriminating by pid" $ do + let byPid = False + withProcCount = Text.replace "[pid]" "(# processes)" + describe "when swap is not required" $ do + it "does not show it" $ do + fmtAsHeader byPid False `shouldBe` withProcCount headerNoSwap + + describe "when swap is required" $ do + it "does show it" $ do + fmtAsHeader byPid True `shouldBe` withProcCount headerSwap headerNoSwap :: Text -headerNoSwap = " Private + Shared = RAM Used\tProgram " +headerNoSwap = " Private + Shared = RAM Used\tProgram [pid]" headerSwap :: Text -headerSwap = " Private + Shared = RAM Used Swap Used\tProgram " +headerSwap = " Private + Shared = RAM Used Swap Used\tProgram [pid]" fmtOverallSpec :: Spec fmtOverallSpec = describe "fmtOverall" $ do describe "when swap is not required" $ do - it "does not show it" $ - fmtOverall False (1, 1) `shouldBe` sampleNoSwapOverall + it "does not show it" + $ fmtOverall False (1, 1) + `shouldBe` sampleNoSwapOverall describe "when swap is required" $ do - it "does show it" $ - fmtOverall True (1, 1) `shouldBe` sampleSwapOverall + it "does show it" + $ fmtOverall True (1, 1) + `shouldBe` sampleSwapOverall sampleNoSwapOverall :: Text @@ -76,18 +148,21 @@ fmtMemUsageSpec = describe "fmtMemUsage" $ do describe "when displaying by-pid" $ do let usage = sampleUsage' 1 describe "and swap is not required" $ do - it "does not show it" $ - fmtMemUsage False biName usage `shouldBe` sampleTotalNoSwap + it "does not show it" + $ fmtMemUsage False biName usage + `shouldBe` sampleTotalNoSwap describe "when swap is required" $ do - it "shows it" $ - fmtMemUsage True biName usage `shouldBe` sampleTotalSwap + it "shows it" + $ fmtMemUsage True biName usage + `shouldBe` sampleTotalSwap describe "when displaying by-name" $ do let usage = sampleUsage' 3 describe "and swap is not required" $ do - it "does not show it" $ - fmtMemUsage False monoName usage `shouldBe` sampleTotalNoSwapMono + it "does not show it" + $ fmtMemUsage False monoName usage + `shouldBe` sampleTotalNoSwapMono monoName :: Text From 7a45e3b68315ffd8c1603ee4288a338ebaba3776 Mon Sep 17 00:00:00 2001 From: Tim Emiola Date: Tue, 6 Feb 2024 14:27:23 +0900 Subject: [PATCH 2/3] Update the help text and the flags --- ChangeLog.md | 5 ++++- src/System/MemInfo/Choices.hs | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index d3a3077..cc9007c 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -2,13 +2,16 @@ `mem-info` uses [PVP Versioning][1]. -## Unreleased -- 2024-01-31 +## Unreleased -- 2024-02-06 - Remove the check for __root__ when no pids are specified - previously, an error occurred if no pids were specified without sudo - after this, all processes of the current user are shown +- Add an option -y (--output-style) that allows the output to be formatted as + CSV with all values in KiB + ## 0.2.0.0 -- 2024-01-28 - Simplify the output when the -d (--discriminate-by-pid) flag is used diff --git a/src/System/MemInfo/Choices.hs b/src/System/MemInfo/Choices.hs index 4f11290..53cc8a3 100644 --- a/src/System/MemInfo/Choices.hs +++ b/src/System/MemInfo/Choices.hs @@ -183,7 +183,7 @@ styleHelp = Text.unlines [ "Determines how the output report is presented;" , "'normal' is the default and is the same as if this option was omitted;" - , "'csv' outputs the usage and header rows in csv format, with all values in KiB and 'overall' row." + , "'csv' outputs the usage and header rows in csv format, with all values in KiB and no 'total' row." , "With 'csv', the --total (-t) flag is ignored" ] From ca64e203897e66334ef584fbab9797d298b49ea9 Mon Sep 17 00:00:00 2001 From: Tim Emiola Date: Tue, 6 Feb 2024 14:30:58 +0900 Subject: [PATCH 3/3] Redo formatting --- test/MemInfo/PrintSpec.hs | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/test/MemInfo/PrintSpec.hs b/test/MemInfo/PrintSpec.hs index f687cbc..8dc41a0 100644 --- a/test/MemInfo/PrintSpec.hs +++ b/test/MemInfo/PrintSpec.hs @@ -116,13 +116,11 @@ headerSwap = " Private + Shared = RAM Used Swap Used\tProgram [pid]" fmtOverallSpec :: Spec fmtOverallSpec = describe "fmtOverall" $ do describe "when swap is not required" $ do - it "does not show it" - $ fmtOverall False (1, 1) - `shouldBe` sampleNoSwapOverall + it "does not show it" $ do + fmtOverall False (1, 1) `shouldBe` sampleNoSwapOverall describe "when swap is required" $ do - it "does show it" - $ fmtOverall True (1, 1) - `shouldBe` sampleSwapOverall + it "does show it" $ do + fmtOverall True (1, 1) `shouldBe` sampleSwapOverall sampleNoSwapOverall :: Text @@ -148,21 +146,18 @@ fmtMemUsageSpec = describe "fmtMemUsage" $ do describe "when displaying by-pid" $ do let usage = sampleUsage' 1 describe "and swap is not required" $ do - it "does not show it" - $ fmtMemUsage False biName usage - `shouldBe` sampleTotalNoSwap + it "does not show it" $ do + fmtMemUsage False biName usage `shouldBe` sampleTotalNoSwap describe "when swap is required" $ do - it "shows it" - $ fmtMemUsage True biName usage - `shouldBe` sampleTotalSwap + it "shows it" $ do + fmtMemUsage True biName usage `shouldBe` sampleTotalSwap describe "when displaying by-name" $ do let usage = sampleUsage' 3 describe "and swap is not required" $ do - it "does not show it" - $ fmtMemUsage False monoName usage - `shouldBe` sampleTotalNoSwapMono + it "does not show it" $ do + fmtMemUsage False monoName usage `shouldBe` sampleTotalNoSwapMono monoName :: Text