Split common CLI functionality into a module
authorIustin Pop <iustin@google.com>
Sun, 22 Mar 2009 09:52:50 +0000 (10:52 +0100)
committerIustin Pop <iustin@google.com>
Sun, 22 Mar 2009 09:52:50 +0000 (10:52 +0100)
This patch moves the common CLI functionality (as much as currently
possible) into a separate module. This means we only have one parseOpts
and that Utils.hs doesn't keep this kind of functions anymore.

Ganeti/HTools/CLI.hs [new file with mode: 0644]
Ganeti/HTools/Utils.hs
hbal.hs
hn1.hs
hscan.hs

diff --git a/Ganeti/HTools/CLI.hs b/Ganeti/HTools/CLI.hs
new file mode 100644 (file)
index 0000000..7c9c97d
--- /dev/null
@@ -0,0 +1,56 @@
+{-| Implementation of command-line functions.
+
+This module holds the common cli-related functions for the binaries,
+separated into this module since Utils.hs is used in many other places
+and this is more I/O oriented.
+
+-}
+
+module Ganeti.HTools.CLI
+    (
+      parseOpts
+    , showVersion
+    ) where
+
+import System.Console.GetOpt
+import System.IO
+import System.Info
+import System
+import Monad
+import Text.Printf (printf)
+import qualified Data.Version
+
+import qualified Ganeti.HTools.Version as Version(version)
+
+-- | Command line parser, using the 'options' structure.
+parseOpts :: [String]            -- ^ The command line arguments
+          -> String              -- ^ The program name
+          -> [OptDescr (b -> b)] -- ^ The supported command line options
+          -> b                   -- ^ The default options record
+          -> (b -> Bool)         -- ^ The function which given the options
+                                 -- tells us whether we need to show help
+          -> IO (b, [String])    -- ^ The resulting options a leftover
+                                 -- arguments
+parseOpts argv progname options defaultOptions fn =
+    case getOpt Permute options argv of
+      (o, n, []) ->
+          do
+            let resu@(po, _) = (foldl (flip id) defaultOptions o, n)
+            when (fn po) $ do
+              putStr $ usageInfo header options
+              exitWith ExitSuccess
+            return resu
+      (_, _, errs) ->
+          ioError (userError (concat errs ++ usageInfo header options))
+      where header = printf "%s %s\nUsage: %s [OPTION...]"
+                     progname Version.version progname
+
+
+-- | Return a version string for the program
+showVersion :: String -- ^ The program name
+            -> String -- ^ The formatted version and other information data
+showVersion name =
+    printf "%s %s\ncompiled with %s %s\nrunning on %s %s\n"
+           name Version.version
+           compilerName (Data.Version.showVersion compilerVersion)
+           os arch
index 737b94a..81d5173 100644 (file)
@@ -1,16 +1,22 @@
 {-| Utility functions -}
 
-module Ganeti.HTools.Utils where
+module Ganeti.HTools.Utils
+    (
+      debug
+    , isLeft
+    , fromLeft
+    , fromRight
+    , sepSplit
+    , swapPairs
+    , varianceCoeff
+    , readData
+    ) where
 
 import Data.Either
 import Data.List
-import qualified Data.Version
 import Monad
 import System
 import System.IO
-import System.Info
-import Text.Printf
-import qualified Ganeti.HTools.Version as Version
 
 import Debug.Trace
 
@@ -68,7 +74,6 @@ stdDev lst =
         bv = sqrt (av / (fromIntegral $ length lst))
     in bv
 
-
 -- | Coefficient of variation.
 varianceCoeff :: Floating a => [a] -> a
 varianceCoeff lst = (stdDev lst) / (fromIntegral $ length lst)
@@ -82,11 +87,3 @@ readData fn host = do
          putStrLn $ fromLeft nd
          exitWith $ ExitFailure 1
   return $ fromRight nd
-
-showVersion :: String -- ^ The program name
-            -> String -- ^ The formatted version and other information data
-showVersion name =
-    printf "%s %s\ncompiled with %s %s\nrunning on %s %s\n"
-           name Version.version
-           compilerName (Data.Version.showVersion compilerVersion)
-           os arch
diff --git a/hbal.hs b/hbal.hs
index 3eec60b..b34cd52 100644 (file)
--- a/hbal.hs
+++ b/hbal.hs
@@ -16,8 +16,8 @@ import Text.Printf (printf)
 
 import qualified Ganeti.HTools.Container as Container
 import qualified Ganeti.HTools.Cluster as Cluster
-import qualified Ganeti.HTools.Version as Version
 import qualified Ganeti.HTools.Node as Node
+import qualified Ganeti.HTools.CLI as CLI
 import Ganeti.HTools.Rapi
 import Ganeti.HTools.Utils
 
@@ -31,8 +31,9 @@ data Options = Options
     , optMaxLength :: Int      -- ^ Stop after this many steps
     , optMaster    :: String   -- ^ Collect data from RAPI
     , optVerbose   :: Int      -- ^ Verbosity level
-    , optShowVer   :: Bool     -- ^ Just show the program version
     , optOffline   :: [String] -- ^ Names of offline nodes
+    , optShowVer   :: Bool     -- ^ Just show the program version
+    , optShowHelp  :: Bool     -- ^ Just show the help
     } deriving Show
 
 -- | Default values for the command line options.
@@ -46,8 +47,9 @@ defaultOptions  = Options
  , optMaxLength = -1
  , optMaster    = ""
  , optVerbose   = 0
- , optShowVer   = False
  , optOffline   = []
+ , optShowVer   = False
+ , optShowHelp  = False
  }
 
 -- | Options list and functions
@@ -76,28 +78,19 @@ options =
       "cap the solution at this many moves (useful for very unbalanced \
       \clusters)"
     , Option ['v']     ["verbose"]
-      (NoArg (\ opts -> let nv = (optVerbose opts)
-                        in opts { optVerbose = nv + 1 }))
+      (NoArg (\ opts -> opts { optVerbose = (optVerbose opts) + 1 }))
       "increase the verbosity level"
-    , Option ['V']     ["version"]
-      (NoArg (\ opts -> opts { optShowVer = True}))
-      "show the version of the program"
     , Option ['O']     ["offline"]
       (ReqArg (\ n opts -> opts { optOffline = n:optOffline opts }) "NODE")
        " set node as offline"
+    , Option ['V']     ["version"]
+      (NoArg (\ opts -> opts { optShowVer = True}))
+      "show the version of the program"
+    , Option ['h']     ["help"]
+      (NoArg (\ opts -> opts { optShowHelp = True}))
+      "show help"
     ]
 
--- | Command line parser, using the 'options' structure.
-parseOpts :: [String] -> IO (Options, [String])
-parseOpts argv =
-    case getOpt Permute options argv of
-      (o,n,[]  ) ->
-          return (foldl (flip id) defaultOptions o, n)
-      (_,_,errs) ->
-          ioError (userError (concat errs ++ usageInfo header options))
-      where header = printf "hbal %s\nUsage: hbal [OPTION...]"
-                     Version.version
-
 {- | Start computing the solution at the given depth and recurse until
 we find a valid solution or we exceed the maximum depth.
 
@@ -144,10 +137,10 @@ iterateDepth ini_tbl max_rounds ktn kti nmlen imlen cmd_strs oneline =
 main :: IO ()
 main = do
   cmd_args <- System.getArgs
-  (opts, _) <- parseOpts cmd_args
+  (opts, _) <- CLI.parseOpts cmd_args "hbal" options defaultOptions optShowHelp
 
   when (optShowVer opts) $ do
-         putStr $ showVersion "hbal"
+         putStr $ CLI.showVersion "hbal"
          exitWith ExitSuccess
 
   let oneline = optOneline opts
diff --git a/hn1.hs b/hn1.hs
index 754d926..c452c95 100644 (file)
--- a/hn1.hs
+++ b/hn1.hs
@@ -17,7 +17,7 @@ import Text.Printf (printf)
 import qualified Ganeti.HTools.Container as Container
 import qualified Ganeti.HTools.Instance as Instance
 import qualified Ganeti.HTools.Cluster as Cluster
-import qualified Ganeti.HTools.Version as Version
+import qualified Ganeti.HTools.CLI as CLI
 import Ganeti.HTools.Rapi
 import Ganeti.HTools.Utils
 
@@ -33,6 +33,7 @@ data Options = Options
     , optMaxDelta    :: Int
     , optMaster      :: String
     , optShowVer     :: Bool     -- ^ Just show the program version
+    , optShowHelp    :: Bool     -- ^ Just show the help
     } deriving Show
 
 -- | Default values for the command line options.
@@ -48,6 +49,7 @@ defaultOptions    = Options
  , optMaxDelta    = -1
  , optMaster    = ""
  , optShowVer   = False
+ , optShowHelp  = False
  }
 
 {- | Start computing the solution at the given depth and recurse until
@@ -112,27 +114,19 @@ options =
     , Option ['V']     ["version"]
       (NoArg (\ opts -> opts { optShowVer = True}))
       "show the version of the program"
+    , Option ['h']     ["help"]
+      (NoArg (\ opts -> opts { optShowHelp = True}))
+      "show help"
     ]
 
--- | Command line parser, using the 'options' structure.
-parseOpts :: [String] -> IO (Options, [String])
-parseOpts argv =
-    case getOpt Permute options argv of
-      (o,n,[]  ) ->
-          return (foldl (flip id) defaultOptions o, n)
-      (_,_,errs) ->
-          ioError (userError (concat errs ++ usageInfo header options))
-      where header = printf "hn1 %s\nUsage: hn1 [OPTION...]"
-                     Version.version
-
 -- | Main function.
 main :: IO ()
 main = do
   cmd_args <- System.getArgs
-  (opts, _) <- parseOpts cmd_args
+  (opts, _) <- CLI.parseOpts cmd_args "hn1" options defaultOptions optShowHelp
 
   when (optShowVer opts) $ do
-         printf $ showVersion "hn1"
+         printf $ CLI.showVersion "hn1"
          exitWith ExitSuccess
 
   let min_depth = optMinDepth opts
index 3922718..8a3a64e 100644 (file)
--- a/hscan.hs
+++ b/hscan.hs
@@ -18,9 +18,9 @@ import Text.Printf (printf)
 
 import qualified Ganeti.HTools.Container as Container
 import qualified Ganeti.HTools.Cluster as Cluster
-import qualified Ganeti.HTools.Version as Version
 import qualified Ganeti.HTools.Node as Node
 import qualified Ganeti.HTools.Instance as Instance
+import qualified Ganeti.HTools.CLI as CLI
 import Ganeti.HTools.Rapi
 import Ganeti.HTools.Utils
 
@@ -29,8 +29,9 @@ data Options = Options
     { optShowNodes :: Bool     -- ^ Whether to show node status
     , optOutPath   :: FilePath -- ^ Path to the output directory
     , optVerbose   :: Int      -- ^ Verbosity level
-    , optShowVer   :: Bool     -- ^ Just show the program version
     , optNoHeader  :: Bool     -- ^ Do not show a header line
+    , optShowVer   :: Bool     -- ^ Just show the program version
+    , optShowHelp  :: Bool     -- ^ Just show the help
     } deriving Show
 
 -- | Default values for the command line options.
@@ -39,8 +40,9 @@ defaultOptions  = Options
  { optShowNodes = False
  , optOutPath   = "."
  , optVerbose   = 0
- , optShowVer   = False
  , optNoHeader  = False
+ , optShowVer   = False
+ , optShowHelp  = False
  }
 
 -- | Options list and functions
@@ -55,25 +57,17 @@ options =
     , Option ['v']     ["verbose"]
       (NoArg (\ opts -> opts { optVerbose = (optVerbose opts) + 1 }))
       "increase the verbosity level"
-    , Option ['V']     ["version"]
-      (NoArg (\ opts -> opts { optShowVer = True}))
-      "show the version of the program"
     , Option []        ["no-headers"]
       (NoArg (\ opts -> opts { optNoHeader = True }))
       "do not show a header line"
+    , Option ['V']     ["version"]
+      (NoArg (\ opts -> opts { optShowVer = True}))
+      "show the version of the program"
+    , Option ['h']     ["help"]
+      (NoArg (\ opts -> opts { optShowHelp = True}))
+      "show help"
     ]
 
--- | Command line parser, using the 'options' structure.
-parseOpts :: [String] -> IO (Options, [String])
-parseOpts argv =
-    case getOpt Permute options argv of
-      (o, n, []) ->
-          return (foldl (flip id) defaultOptions o, n)
-      (_, _, errs) ->
-          ioError (userError (concat errs ++ usageInfo header options))
-      where header = printf "hscan %s\nUsage: hscan [OPTION...] cluster..."
-                     Version.version
-
 -- | Generate node file data from node objects
 serializeNodes :: Cluster.NodeList -> String -> Cluster.NameList -> String
 serializeNodes nl csf ktn =
@@ -137,10 +131,11 @@ printCluster nl il ktn kti =
 main :: IO ()
 main = do
   cmd_args <- System.getArgs
-  (opts, clusters) <- parseOpts cmd_args
+  (opts, clusters) <- CLI.parseOpts cmd_args "hscan" options
+                      defaultOptions optShowHelp
 
   when (optShowVer opts) $ do
-         putStr $ showVersion "hscan"
+         putStr $ CLI.showVersion "hscan"
          exitWith ExitSuccess
 
   let odir = optOutPath opts