Revision 630c73e5 htools/Ganeti/Common.hs
b/htools/Ganeti/Common.hs | ||
---|---|---|
42 | 42 |
, parseYesNo |
43 | 43 |
, parseOpts |
44 | 44 |
, parseOptsInner |
45 |
, parseOptsCmds |
|
46 |
, genericMainCmds |
|
45 | 47 |
) where |
46 | 48 |
|
47 | 49 |
import Control.Monad (foldM) |
48 | 50 |
import Data.Char (toLower) |
49 |
import Data.List (intercalate, stripPrefix) |
|
51 |
import Data.List (intercalate, stripPrefix, sortBy)
|
|
50 | 52 |
import Data.Maybe (fromMaybe) |
53 |
import Data.Ord (comparing) |
|
51 | 54 |
import qualified Data.Version |
52 | 55 |
import System.Console.GetOpt |
56 |
import System.Environment |
|
53 | 57 |
import System.Exit |
54 | 58 |
import System.Info |
55 | 59 |
import System.IO |
56 | 60 |
import Text.Printf (printf) |
57 | 61 |
|
58 | 62 |
import Ganeti.BasicTypes |
63 |
import qualified Ganeti.Constants as C |
|
59 | 64 |
import qualified Ganeti.Version as Version (version) |
60 | 65 |
|
61 | 66 |
-- | Parameter type. |
... | ... | |
189 | 194 |
parsed_value <- conversion_fn string_opt |
190 | 195 |
updater_fn parsed_value opts) |
191 | 196 |
|
197 |
-- | Max command length when formatting command list output. |
|
198 |
maxCmdLen :: Int |
|
199 |
maxCmdLen = 60 |
|
200 |
|
|
201 |
-- | Formats usage for a multi-personality program. |
|
202 |
formatCmdUsage :: (StandardOptions a) => String -> PersonalityList a -> String |
|
203 |
formatCmdUsage prog personalities = |
|
204 |
let mlen = min maxCmdLen . maximum $ map (length . fst) personalities |
|
205 |
sorted = sortBy (comparing fst) personalities |
|
206 |
header = [ printf "Usage: %s {command} [options...] [argument...]" prog |
|
207 |
, printf "%s <command> --help to see details, or man %s" |
|
208 |
prog prog |
|
209 |
, "" |
|
210 |
, "Commands:" |
|
211 |
] |
|
212 |
rows = map (\(cmd, _) -> |
|
213 |
printf " %-*s" mlen cmd::String) sorted |
|
214 |
in unlines $ header ++ rows |
|
215 |
|
|
216 |
-- | Displays usage for a program and exits. |
|
217 |
showCmdUsage :: (StandardOptions a) => |
|
218 |
String -- ^ Program name |
|
219 |
-> PersonalityList a -- ^ Personality list |
|
220 |
-> Bool -- ^ Whether the exit code is success or not |
|
221 |
-> IO b |
|
222 |
showCmdUsage prog personalities success = do |
|
223 |
let usage = formatCmdUsage prog personalities |
|
224 |
putStr usage |
|
225 |
if success |
|
226 |
then exitSuccess |
|
227 |
else exitWith $ ExitFailure C.exitFailure |
|
228 |
|
|
192 | 229 |
-- | Command line parser, using a generic 'Options' structure. |
193 | 230 |
parseOpts :: (StandardOptions a) => |
194 | 231 |
a -- ^ The default options |
... | ... | |
206 | 243 |
Right result -> |
207 | 244 |
return result |
208 | 245 |
|
246 |
-- | Command line parser, for programs with sub-commands. |
|
247 |
parseOptsCmds :: (StandardOptions a) => |
|
248 |
a -- ^ The default options |
|
249 |
-> [String] -- ^ The command line arguments |
|
250 |
-> String -- ^ The program name |
|
251 |
-> PersonalityList a -- ^ The supported commands |
|
252 |
-> [GenericOptType a] -- ^ Generic options |
|
253 |
-> IO (a, [String], a -> [String] -> IO ()) |
|
254 |
-- ^ The resulting options and leftover arguments |
|
255 |
parseOptsCmds defaults argv progname personalities genopts = do |
|
256 |
let usage = showCmdUsage progname personalities |
|
257 |
check c = case c of |
|
258 |
-- hardcoded option strings here! |
|
259 |
"--version" -> putStrLn (versionInfo progname) >> exitSuccess |
|
260 |
"--help" -> usage True |
|
261 |
_ -> return c |
|
262 |
(cmd, cmd_args) <- case argv of |
|
263 |
cmd:cmd_args -> do |
|
264 |
cmd' <- check cmd |
|
265 |
return (cmd', cmd_args) |
|
266 |
[] -> usage False |
|
267 |
case cmd `lookup` personalities of |
|
268 |
Nothing -> usage False |
|
269 |
Just (mainfn, optdefs, argdefs) -> do |
|
270 |
optdefs' <- optdefs |
|
271 |
(opts, args) <- parseOpts defaults cmd_args progname |
|
272 |
(optdefs' ++ genopts) argdefs |
|
273 |
return (opts, args, mainfn) |
|
274 |
|
|
209 | 275 |
-- | Inner parse options. The arguments are similar to 'parseOpts', |
210 | 276 |
-- but it returns either a 'Left' composed of exit code and message, |
211 | 277 |
-- or a 'Right' for the success case. |
... | ... | |
236 | 302 |
(_, _, errs) -> |
237 | 303 |
Left (ExitFailure 2, "Command line error: " ++ concat errs ++ "\n" ++ |
238 | 304 |
usageHelp progname options) |
305 |
|
|
306 |
-- | Parse command line options and execute the main function of a |
|
307 |
-- multi-personality binary. |
|
308 |
genericMainCmds :: (StandardOptions a) => |
|
309 |
a |
|
310 |
-> PersonalityList a |
|
311 |
-> [GenericOptType a] |
|
312 |
-> IO () |
|
313 |
genericMainCmds defaults personalities genopts = do |
|
314 |
cmd_args <- getArgs |
|
315 |
prog <- getProgName |
|
316 |
(opts, args, fn) <- |
|
317 |
parseOptsCmds defaults cmd_args prog personalities genopts |
|
318 |
fn opts args |
Also available in: Unified diff