1 {-| Base common functionality.
3 This module holds common functionality shared across Ganeti daemons,
4 HTools and any other programs.
10 Copyright (C) 2009, 2010, 2011, 2012 Google Inc.
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; either version 2 of the License, or
15 (at your option) any later version.
17 This program is distributed in the hope that it will be useful, but
18 WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 General Public License for more details.
22 You should have received a copy of the GNU General Public License
23 along with this program; if not, write to the Free Software
24 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
44 import Control.Monad (foldM)
45 import qualified Data.Version
46 import System.Console.GetOpt
50 import Text.Printf (printf)
52 import Ganeti.BasicTypes
53 import qualified Ganeti.Version as Version (version)
56 data OptCompletion = OptComplNone -- ^ No parameter to this option
57 | OptComplFile -- ^ An existing file
58 | OptComplDir -- ^ An existing directory
59 | OptComplHost -- ^ Host name
60 | OptComplInetAddr -- ^ One ipv4\/ipv6 address
61 | OptComplOneNode -- ^ One node
62 | OptComplManyNodes -- ^ Many nodes, comma-sep
63 | OptComplOneInstance -- ^ One instance
64 | OptComplManyInstances -- ^ Many instances, comma-sep
65 | OptComplOneOs -- ^ One OS name
66 | OptComplOneIallocator -- ^ One iallocator
67 | OptComplInstAddNodes -- ^ Either one or two nodes
68 | OptComplOneGroup -- ^ One group
69 | OptComplNumeric -- ^ Float values
70 | OptComplString -- ^ Arbitrary string
71 | OptComplChoices [String] -- ^ List of string choices
72 deriving (Show, Read, Eq)
74 -- | Yes\/no choices completion.
75 optComplYesNo :: OptCompletion
76 optComplYesNo = OptComplChoices ["yes", "no"]
78 -- | Abrreviation for the option type.
79 type GenericOptType a = (OptDescr (a -> Result a), OptCompletion)
81 -- | Type class for options which support help and version.
82 class StandardOptions a where
83 helpRequested :: a -> Bool
84 verRequested :: a -> Bool
88 -- | Options to request help output.
89 oShowHelp :: (StandardOptions a) => GenericOptType a
90 oShowHelp = (Option "h" ["help"] (NoArg (Ok . requestHelp)) "show help",
93 -- | Option to request version information.
94 oShowVer :: (StandardOptions a) => GenericOptType a
95 oShowVer = (Option "V" ["version"] (NoArg (Ok . requestVer))
96 "show the version of the program",
100 usageHelp :: String -> [GenericOptType a] -> String
102 usageInfo (printf "%s %s\nUsage: %s [OPTION...]"
103 progname Version.version progname) . map fst
105 -- | Show the program version info.
106 versionInfo :: String -> String
107 versionInfo progname =
108 printf "%s %s\ncompiled with %s %s\nrunning on %s %s\n"
109 progname Version.version compilerName
110 (Data.Version.showVersion compilerVersion)
113 -- | Helper for parsing a yes\/no command line flag.
114 parseYesNo :: Bool -- ^ Default value (when we get a @Nothing@)
115 -> Maybe String -- ^ Parameter value
116 -> Result Bool -- ^ Resulting boolean value
117 parseYesNo v Nothing = return v
118 parseYesNo _ (Just "yes") = return True
119 parseYesNo _ (Just "no") = return False
120 parseYesNo _ (Just s) = fail ("Invalid choice '" ++ s ++
121 "', pass one of 'yes' or 'no'")
123 -- | Helper function for required arguments which need to be converted
124 -- as opposed to stored just as string.
125 reqWithConversion :: (String -> Result a)
126 -> (a -> b -> Result b)
128 -> ArgDescr (b -> Result b)
129 reqWithConversion conversion_fn updater_fn =
130 ReqArg (\string_opt opts -> do
131 parsed_value <- conversion_fn string_opt
132 updater_fn parsed_value opts)
134 -- | Command line parser, using a generic 'Options' structure.
135 parseOpts :: (StandardOptions a) =>
136 a -- ^ The default options
137 -> [String] -- ^ The command line arguments
138 -> String -- ^ The program name
139 -> [GenericOptType a] -- ^ The supported command line options
140 -> IO (a, [String]) -- ^ The resulting options and
141 -- leftover arguments
142 parseOpts defaults argv progname options =
143 case parseOptsInner defaults argv progname options of
144 Left (code, msg) -> do
145 hPutStr (if code == ExitSuccess then stdout else stderr) msg
150 -- | Inner parse options. The arguments are similar to 'parseOpts',
151 -- but it returns either a 'Left' composed of exit code and message,
152 -- or a 'Right' for the success case.
153 parseOptsInner :: (StandardOptions a) =>
157 -> [GenericOptType a]
158 -> Either (ExitCode, String) (a, [String])
159 parseOptsInner defaults argv progname options =
160 case getOpt Permute (map fst options) argv of
162 case foldM (flip id) defaults opts of
163 Bad msg -> Left (ExitFailure 1,
164 "Error while parsing command line arguments:\n"
167 select (Right (parsed, args))
168 [ (helpRequested parsed,
169 Left (ExitSuccess, usageHelp progname options))
170 , (verRequested parsed,
171 Left (ExitSuccess, versionInfo progname))
174 Left (ExitFailure 2, "Command line error: " ++ concat errs ++ "\n" ++
175 usageHelp progname options)