Statistics
| Branch: | Tag: | Revision:

root / src / Ganeti / Common.hs @ c92b4671

History | View | Annotate | Download (14.4 kB)

1 51000365 Iustin Pop
{-| Base common functionality.
2 51000365 Iustin Pop
3 51000365 Iustin Pop
This module holds common functionality shared across Ganeti daemons,
4 51000365 Iustin Pop
HTools and any other programs.
5 51000365 Iustin Pop
6 51000365 Iustin Pop
-}
7 51000365 Iustin Pop
8 51000365 Iustin Pop
{-
9 51000365 Iustin Pop
10 9fb621af Yiannis Tsiouris
Copyright (C) 2009, 2010, 2011, 2012, 2013 Google Inc.
11 51000365 Iustin Pop
12 51000365 Iustin Pop
This program is free software; you can redistribute it and/or modify
13 51000365 Iustin Pop
it under the terms of the GNU General Public License as published by
14 51000365 Iustin Pop
the Free Software Foundation; either version 2 of the License, or
15 51000365 Iustin Pop
(at your option) any later version.
16 51000365 Iustin Pop
17 51000365 Iustin Pop
This program is distributed in the hope that it will be useful, but
18 51000365 Iustin Pop
WITHOUT ANY WARRANTY; without even the implied warranty of
19 51000365 Iustin Pop
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20 51000365 Iustin Pop
General Public License for more details.
21 51000365 Iustin Pop
22 51000365 Iustin Pop
You should have received a copy of the GNU General Public License
23 51000365 Iustin Pop
along with this program; if not, write to the Free Software
24 51000365 Iustin Pop
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
25 51000365 Iustin Pop
02110-1301, USA.
26 51000365 Iustin Pop
27 51000365 Iustin Pop
-}
28 51000365 Iustin Pop
29 51000365 Iustin Pop
module Ganeti.Common
30 51000365 Iustin Pop
  ( GenericOptType
31 51000365 Iustin Pop
  , StandardOptions(..)
32 f5af3409 Iustin Pop
  , OptCompletion(..)
33 a6cdfdcc Iustin Pop
  , ArgCompletion(..)
34 2e6ef129 Iustin Pop
  , PersonalityList
35 f5af3409 Iustin Pop
  , optComplYesNo
36 51000365 Iustin Pop
  , oShowHelp
37 51000365 Iustin Pop
  , oShowVer
38 097ad7ee Iustin Pop
  , oShowComp
39 51000365 Iustin Pop
  , usageHelp
40 51000365 Iustin Pop
  , versionInfo
41 814e1e23 Iustin Pop
  , formatCommands
42 51000365 Iustin Pop
  , reqWithConversion
43 51000365 Iustin Pop
  , parseYesNo
44 51000365 Iustin Pop
  , parseOpts
45 51000365 Iustin Pop
  , parseOptsInner
46 630c73e5 Iustin Pop
  , parseOptsCmds
47 630c73e5 Iustin Pop
  , genericMainCmds
48 212b66c3 Helga Velroyen
  , fillUpList
49 212b66c3 Helga Velroyen
  , fillPairFromMaybe
50 212b66c3 Helga Velroyen
  , pickPairUnique
51 51000365 Iustin Pop
  ) where
52 51000365 Iustin Pop
53 51000365 Iustin Pop
import Control.Monad (foldM)
54 097ad7ee Iustin Pop
import Data.Char (toLower)
55 630c73e5 Iustin Pop
import Data.List (intercalate, stripPrefix, sortBy)
56 097ad7ee Iustin Pop
import Data.Maybe (fromMaybe)
57 630c73e5 Iustin Pop
import Data.Ord (comparing)
58 51000365 Iustin Pop
import qualified Data.Version
59 51000365 Iustin Pop
import System.Console.GetOpt
60 630c73e5 Iustin Pop
import System.Environment
61 51000365 Iustin Pop
import System.Exit
62 51000365 Iustin Pop
import System.Info
63 51000365 Iustin Pop
import System.IO
64 51000365 Iustin Pop
import Text.Printf (printf)
65 51000365 Iustin Pop
66 51000365 Iustin Pop
import Ganeti.BasicTypes
67 630c73e5 Iustin Pop
import qualified Ganeti.Constants as C
68 9fb621af Yiannis Tsiouris
import Ganeti.Utils (wrap)
69 51000365 Iustin Pop
import qualified Ganeti.Version as Version (version)
70 51000365 Iustin Pop
71 f5af3409 Iustin Pop
-- | Parameter type.
72 f5af3409 Iustin Pop
data OptCompletion = OptComplNone             -- ^ No parameter to this option
73 f5af3409 Iustin Pop
                   | OptComplFile             -- ^ An existing file
74 f5af3409 Iustin Pop
                   | OptComplDir              -- ^ An existing directory
75 f5af3409 Iustin Pop
                   | OptComplHost             -- ^ Host name
76 f5af3409 Iustin Pop
                   | OptComplInetAddr         -- ^ One ipv4\/ipv6 address
77 f5af3409 Iustin Pop
                   | OptComplOneNode          -- ^ One node
78 f5af3409 Iustin Pop
                   | OptComplManyNodes        -- ^ Many nodes, comma-sep
79 f5af3409 Iustin Pop
                   | OptComplOneInstance      -- ^ One instance
80 f5af3409 Iustin Pop
                   | OptComplManyInstances    -- ^ Many instances, comma-sep
81 f5af3409 Iustin Pop
                   | OptComplOneOs            -- ^ One OS name
82 f5af3409 Iustin Pop
                   | OptComplOneIallocator    -- ^ One iallocator
83 f5af3409 Iustin Pop
                   | OptComplInstAddNodes     -- ^ Either one or two nodes
84 f5af3409 Iustin Pop
                   | OptComplOneGroup         -- ^ One group
85 ecebe9f6 Iustin Pop
                   | OptComplInteger          -- ^ Integer values
86 ecebe9f6 Iustin Pop
                   | OptComplFloat            -- ^ Float values
87 a6cdfdcc Iustin Pop
                   | OptComplJobId            -- ^ Job Id
88 a6cdfdcc Iustin Pop
                   | OptComplCommand          -- ^ Command (executable)
89 f5af3409 Iustin Pop
                   | OptComplString           -- ^ Arbitrary string
90 f5af3409 Iustin Pop
                   | OptComplChoices [String] -- ^ List of string choices
91 a6cdfdcc Iustin Pop
                   | OptComplSuggest [String] -- ^ Suggested choices
92 139c0683 Iustin Pop
                   deriving (Show, Eq)
93 f5af3409 Iustin Pop
94 a6cdfdcc Iustin Pop
-- | Argument type. This differs from (and wraps) an Option by the
95 a6cdfdcc Iustin Pop
-- fact that it can (and usually does) support multiple repetitions of
96 a6cdfdcc Iustin Pop
-- the same argument, via a min and max limit.
97 a6cdfdcc Iustin Pop
data ArgCompletion = ArgCompletion OptCompletion Int (Maybe Int)
98 139c0683 Iustin Pop
                     deriving (Show, Eq)
99 a6cdfdcc Iustin Pop
100 2e6ef129 Iustin Pop
-- | A personality definition.
101 2e6ef129 Iustin Pop
type Personality a = ( a -> [String] -> IO () -- The main function
102 2e6ef129 Iustin Pop
                     , IO [GenericOptType a]  -- The options
103 2e6ef129 Iustin Pop
                     , [ArgCompletion]        -- The description of args
104 559c4a98 Iustin Pop
                     , String                 -- Description
105 2e6ef129 Iustin Pop
                     )
106 2e6ef129 Iustin Pop
107 2e6ef129 Iustin Pop
-- | Personality lists type, common across all binaries that expose
108 2e6ef129 Iustin Pop
-- multiple personalities.
109 2e6ef129 Iustin Pop
type PersonalityList  a = [(String, Personality a)]
110 2e6ef129 Iustin Pop
111 f5af3409 Iustin Pop
-- | Yes\/no choices completion.
112 f5af3409 Iustin Pop
optComplYesNo :: OptCompletion
113 f5af3409 Iustin Pop
optComplYesNo = OptComplChoices ["yes", "no"]
114 f5af3409 Iustin Pop
115 097ad7ee Iustin Pop
-- | Text serialisation for 'OptCompletion', used on the Python side.
116 097ad7ee Iustin Pop
complToText :: OptCompletion -> String
117 fad06963 Iustin Pop
complToText (OptComplChoices choices) = "choices=" ++ intercalate "," choices
118 fad06963 Iustin Pop
complToText (OptComplSuggest choices) = "suggest=" ++ intercalate "," choices
119 097ad7ee Iustin Pop
complToText compl =
120 097ad7ee Iustin Pop
  let show_compl = show compl
121 097ad7ee Iustin Pop
      stripped = stripPrefix "OptCompl" show_compl
122 097ad7ee Iustin Pop
  in map toLower $ fromMaybe show_compl stripped
123 097ad7ee Iustin Pop
124 7ce2f8ee Michele Tartara
-- | Text serialisation for 'ArgCompletion'.
125 a6cdfdcc Iustin Pop
argComplToText :: ArgCompletion -> String
126 a6cdfdcc Iustin Pop
argComplToText (ArgCompletion optc min_cnt max_cnt) =
127 a6cdfdcc Iustin Pop
  complToText optc ++ " " ++ show min_cnt ++ " " ++ maybe "none" show max_cnt
128 a6cdfdcc Iustin Pop
129 f5606cda Dato Simรณ
-- | Abbreviation for the option type.
130 ce207617 Iustin Pop
type GenericOptType a = (OptDescr (a -> Result a), OptCompletion)
131 51000365 Iustin Pop
132 51000365 Iustin Pop
-- | Type class for options which support help and version.
133 51000365 Iustin Pop
class StandardOptions a where
134 51000365 Iustin Pop
  helpRequested :: a -> Bool
135 51000365 Iustin Pop
  verRequested  :: a -> Bool
136 097ad7ee Iustin Pop
  compRequested :: a -> Bool
137 51000365 Iustin Pop
  requestHelp   :: a -> a
138 51000365 Iustin Pop
  requestVer    :: a -> a
139 097ad7ee Iustin Pop
  requestComp   :: a -> a
140 51000365 Iustin Pop
141 097ad7ee Iustin Pop
-- | Option to request help output.
142 51000365 Iustin Pop
oShowHelp :: (StandardOptions a) => GenericOptType a
143 ce207617 Iustin Pop
oShowHelp = (Option "h" ["help"] (NoArg (Ok . requestHelp)) "show help",
144 ce207617 Iustin Pop
             OptComplNone)
145 51000365 Iustin Pop
146 ce207617 Iustin Pop
-- | Option to request version information.
147 51000365 Iustin Pop
oShowVer :: (StandardOptions a) => GenericOptType a
148 ce207617 Iustin Pop
oShowVer = (Option "V" ["version"] (NoArg (Ok . requestVer))
149 ce207617 Iustin Pop
            "show the version of the program",
150 ce207617 Iustin Pop
            OptComplNone)
151 51000365 Iustin Pop
152 097ad7ee Iustin Pop
-- | Option to request completion information
153 097ad7ee Iustin Pop
oShowComp :: (StandardOptions a) => GenericOptType a
154 097ad7ee Iustin Pop
oShowComp =
155 097ad7ee Iustin Pop
  (Option "" ["help-completion"] (NoArg (Ok . requestComp) )
156 097ad7ee Iustin Pop
   "show completion info", OptComplNone)
157 097ad7ee Iustin Pop
158 51000365 Iustin Pop
-- | Usage info.
159 51000365 Iustin Pop
usageHelp :: String -> [GenericOptType a] -> String
160 51000365 Iustin Pop
usageHelp progname =
161 51000365 Iustin Pop
  usageInfo (printf "%s %s\nUsage: %s [OPTION...]"
162 ce207617 Iustin Pop
             progname Version.version progname) . map fst
163 51000365 Iustin Pop
164 51000365 Iustin Pop
-- | Show the program version info.
165 51000365 Iustin Pop
versionInfo :: String -> String
166 51000365 Iustin Pop
versionInfo progname =
167 51000365 Iustin Pop
  printf "%s %s\ncompiled with %s %s\nrunning on %s %s\n"
168 51000365 Iustin Pop
         progname Version.version compilerName
169 51000365 Iustin Pop
         (Data.Version.showVersion compilerVersion)
170 51000365 Iustin Pop
         os arch
171 51000365 Iustin Pop
172 097ad7ee Iustin Pop
-- | Show completion info.
173 a6cdfdcc Iustin Pop
completionInfo :: String -> [GenericOptType a] -> [ArgCompletion] -> String
174 a6cdfdcc Iustin Pop
completionInfo _ opts args =
175 a6cdfdcc Iustin Pop
  unlines $
176 097ad7ee Iustin Pop
  map (\(Option shorts longs _ _, compinfo) ->
177 097ad7ee Iustin Pop
         let all_opts = map (\c -> ['-', c]) shorts ++ map ("--" ++) longs
178 097ad7ee Iustin Pop
         in intercalate "," all_opts ++ " " ++ complToText compinfo
179 a6cdfdcc Iustin Pop
      ) opts ++
180 a6cdfdcc Iustin Pop
  map argComplToText args
181 097ad7ee Iustin Pop
182 51000365 Iustin Pop
-- | Helper for parsing a yes\/no command line flag.
183 51000365 Iustin Pop
parseYesNo :: Bool         -- ^ Default value (when we get a @Nothing@)
184 51000365 Iustin Pop
           -> Maybe String -- ^ Parameter value
185 51000365 Iustin Pop
           -> Result Bool  -- ^ Resulting boolean value
186 51000365 Iustin Pop
parseYesNo v Nothing      = return v
187 51000365 Iustin Pop
parseYesNo _ (Just "yes") = return True
188 51000365 Iustin Pop
parseYesNo _ (Just "no")  = return False
189 51000365 Iustin Pop
parseYesNo _ (Just s)     = fail ("Invalid choice '" ++ s ++
190 51000365 Iustin Pop
                                  "', pass one of 'yes' or 'no'")
191 51000365 Iustin Pop
192 51000365 Iustin Pop
-- | Helper function for required arguments which need to be converted
193 51000365 Iustin Pop
-- as opposed to stored just as string.
194 51000365 Iustin Pop
reqWithConversion :: (String -> Result a)
195 51000365 Iustin Pop
                  -> (a -> b -> Result b)
196 51000365 Iustin Pop
                  -> String
197 51000365 Iustin Pop
                  -> ArgDescr (b -> Result b)
198 5b11f8db Iustin Pop
reqWithConversion conversion_fn updater_fn =
199 51000365 Iustin Pop
  ReqArg (\string_opt opts -> do
200 51000365 Iustin Pop
            parsed_value <- conversion_fn string_opt
201 5b11f8db Iustin Pop
            updater_fn parsed_value opts)
202 51000365 Iustin Pop
203 630c73e5 Iustin Pop
-- | Max command length when formatting command list output.
204 630c73e5 Iustin Pop
maxCmdLen :: Int
205 630c73e5 Iustin Pop
maxCmdLen = 60
206 630c73e5 Iustin Pop
207 814e1e23 Iustin Pop
-- | Formats the description of various commands.
208 814e1e23 Iustin Pop
formatCommands :: (StandardOptions a) => PersonalityList a -> [String]
209 814e1e23 Iustin Pop
formatCommands personalities =
210 9fb621af Yiannis Tsiouris
  concatMap (\(cmd, (_, _, _, desc)) ->
211 9fb621af Yiannis Tsiouris
              fmtDesc cmd (wrap maxWidth desc) "-" []) $
212 814e1e23 Iustin Pop
  sortBy (comparing fst) personalities
213 814e1e23 Iustin Pop
    where mlen = min maxCmdLen . maximum $ map (length . fst) personalities
214 9fb621af Yiannis Tsiouris
          maxWidth = 79 - 3 - mlen
215 9fb621af Yiannis Tsiouris
          fmtDesc _ [] _ acc = reverse acc
216 9fb621af Yiannis Tsiouris
          fmtDesc cmd (d : ds) sep acc =
217 9fb621af Yiannis Tsiouris
            fmtDesc "" ds " " (printf " %-*s %s %s" mlen cmd sep d : acc)
218 814e1e23 Iustin Pop
219 630c73e5 Iustin Pop
-- | Formats usage for a multi-personality program.
220 630c73e5 Iustin Pop
formatCmdUsage :: (StandardOptions a) => String -> PersonalityList a -> String
221 630c73e5 Iustin Pop
formatCmdUsage prog personalities =
222 814e1e23 Iustin Pop
  let header = [ printf "Usage: %s {command} [options...] [argument...]" prog
223 630c73e5 Iustin Pop
               , printf "%s <command> --help to see details, or man %s"
224 630c73e5 Iustin Pop
                   prog prog
225 630c73e5 Iustin Pop
               , ""
226 630c73e5 Iustin Pop
               , "Commands:"
227 630c73e5 Iustin Pop
               ]
228 814e1e23 Iustin Pop
      rows = formatCommands personalities
229 630c73e5 Iustin Pop
  in unlines $ header ++ rows
230 630c73e5 Iustin Pop
231 630c73e5 Iustin Pop
-- | Displays usage for a program and exits.
232 630c73e5 Iustin Pop
showCmdUsage :: (StandardOptions a) =>
233 630c73e5 Iustin Pop
                String            -- ^ Program name
234 630c73e5 Iustin Pop
             -> PersonalityList a -- ^ Personality list
235 630c73e5 Iustin Pop
             -> Bool              -- ^ Whether the exit code is success or not
236 630c73e5 Iustin Pop
             -> IO b
237 630c73e5 Iustin Pop
showCmdUsage prog personalities success = do
238 630c73e5 Iustin Pop
  let usage = formatCmdUsage prog personalities
239 630c73e5 Iustin Pop
  putStr usage
240 630c73e5 Iustin Pop
  if success
241 630c73e5 Iustin Pop
    then exitSuccess
242 630c73e5 Iustin Pop
    else exitWith $ ExitFailure C.exitFailure
243 630c73e5 Iustin Pop
244 daf0de68 Iustin Pop
-- | Generates completion information for a multi-command binary.
245 daf0de68 Iustin Pop
multiCmdCompletion :: (StandardOptions a) => PersonalityList a -> String
246 daf0de68 Iustin Pop
multiCmdCompletion personalities =
247 7ce2f8ee Michele Tartara
  argComplToText $
248 7ce2f8ee Michele Tartara
    ArgCompletion (OptComplChoices (map fst personalities))
249 7ce2f8ee Michele Tartara
      1 (Just 1)
250 daf0de68 Iustin Pop
251 daf0de68 Iustin Pop
-- | Displays completion information for a multi-command binary and exits.
252 daf0de68 Iustin Pop
showCmdCompletion :: (StandardOptions a) => PersonalityList a -> IO b
253 daf0de68 Iustin Pop
showCmdCompletion personalities =
254 7ce2f8ee Michele Tartara
  putStrLn (multiCmdCompletion personalities) >> exitSuccess
255 daf0de68 Iustin Pop
256 51000365 Iustin Pop
-- | Command line parser, using a generic 'Options' structure.
257 51000365 Iustin Pop
parseOpts :: (StandardOptions a) =>
258 51000365 Iustin Pop
             a                      -- ^ The default options
259 51000365 Iustin Pop
          -> [String]               -- ^ The command line arguments
260 51000365 Iustin Pop
          -> String                 -- ^ The program name
261 51000365 Iustin Pop
          -> [GenericOptType a]     -- ^ The supported command line options
262 22278fa7 Iustin Pop
          -> [ArgCompletion]        -- ^ The supported command line arguments
263 51000365 Iustin Pop
          -> IO (a, [String])       -- ^ The resulting options and
264 51000365 Iustin Pop
                                    -- leftover arguments
265 22278fa7 Iustin Pop
parseOpts defaults argv progname options arguments =
266 22278fa7 Iustin Pop
  case parseOptsInner defaults argv progname options arguments of
267 51000365 Iustin Pop
    Left (code, msg) -> do
268 51000365 Iustin Pop
      hPutStr (if code == ExitSuccess then stdout else stderr) msg
269 51000365 Iustin Pop
      exitWith code
270 51000365 Iustin Pop
    Right result ->
271 51000365 Iustin Pop
      return result
272 51000365 Iustin Pop
273 630c73e5 Iustin Pop
-- | Command line parser, for programs with sub-commands.
274 630c73e5 Iustin Pop
parseOptsCmds :: (StandardOptions a) =>
275 630c73e5 Iustin Pop
                 a                      -- ^ The default options
276 630c73e5 Iustin Pop
              -> [String]               -- ^ The command line arguments
277 630c73e5 Iustin Pop
              -> String                 -- ^ The program name
278 630c73e5 Iustin Pop
              -> PersonalityList a      -- ^ The supported commands
279 630c73e5 Iustin Pop
              -> [GenericOptType a]     -- ^ Generic options
280 630c73e5 Iustin Pop
              -> IO (a, [String], a -> [String] -> IO ())
281 630c73e5 Iustin Pop
                     -- ^ The resulting options and leftover arguments
282 630c73e5 Iustin Pop
parseOptsCmds defaults argv progname personalities genopts = do
283 630c73e5 Iustin Pop
  let usage = showCmdUsage progname personalities
284 630c73e5 Iustin Pop
      check c = case c of
285 630c73e5 Iustin Pop
                  -- hardcoded option strings here!
286 630c73e5 Iustin Pop
                  "--version" -> putStrLn (versionInfo progname) >> exitSuccess
287 630c73e5 Iustin Pop
                  "--help"    -> usage True
288 daf0de68 Iustin Pop
                  "--help-completion" -> showCmdCompletion personalities
289 630c73e5 Iustin Pop
                  _           -> return c
290 630c73e5 Iustin Pop
  (cmd, cmd_args) <- case argv of
291 630c73e5 Iustin Pop
                       cmd:cmd_args -> do
292 630c73e5 Iustin Pop
                         cmd' <- check cmd
293 630c73e5 Iustin Pop
                         return (cmd', cmd_args)
294 630c73e5 Iustin Pop
                       [] -> usage False
295 630c73e5 Iustin Pop
  case cmd `lookup` personalities of
296 630c73e5 Iustin Pop
    Nothing -> usage False
297 559c4a98 Iustin Pop
    Just (mainfn, optdefs, argdefs, _) -> do
298 630c73e5 Iustin Pop
      optdefs' <- optdefs
299 630c73e5 Iustin Pop
      (opts, args) <- parseOpts defaults cmd_args progname
300 630c73e5 Iustin Pop
                      (optdefs' ++ genopts) argdefs
301 630c73e5 Iustin Pop
      return (opts, args, mainfn)
302 630c73e5 Iustin Pop
303 51000365 Iustin Pop
-- | Inner parse options. The arguments are similar to 'parseOpts',
304 51000365 Iustin Pop
-- but it returns either a 'Left' composed of exit code and message,
305 51000365 Iustin Pop
-- or a 'Right' for the success case.
306 51000365 Iustin Pop
parseOptsInner :: (StandardOptions a) =>
307 51000365 Iustin Pop
                  a
308 51000365 Iustin Pop
               -> [String]
309 51000365 Iustin Pop
               -> String
310 51000365 Iustin Pop
               -> [GenericOptType a]
311 22278fa7 Iustin Pop
               -> [ArgCompletion]
312 51000365 Iustin Pop
               -> Either (ExitCode, String) (a, [String])
313 22278fa7 Iustin Pop
parseOptsInner defaults argv progname options arguments  =
314 ce207617 Iustin Pop
  case getOpt Permute (map fst options) argv of
315 51000365 Iustin Pop
    (opts, args, []) ->
316 51000365 Iustin Pop
      case foldM (flip id) defaults opts of
317 51000365 Iustin Pop
           Bad msg -> Left (ExitFailure 1,
318 51000365 Iustin Pop
                            "Error while parsing command line arguments:\n"
319 51000365 Iustin Pop
                            ++ msg ++ "\n")
320 51000365 Iustin Pop
           Ok parsed ->
321 51000365 Iustin Pop
             select (Right (parsed, args))
322 51000365 Iustin Pop
                 [ (helpRequested parsed,
323 51000365 Iustin Pop
                    Left (ExitSuccess, usageHelp progname options))
324 51000365 Iustin Pop
                 , (verRequested parsed,
325 51000365 Iustin Pop
                    Left (ExitSuccess, versionInfo progname))
326 097ad7ee Iustin Pop
                 , (compRequested parsed,
327 22278fa7 Iustin Pop
                    Left (ExitSuccess, completionInfo progname options
328 22278fa7 Iustin Pop
                                         arguments))
329 51000365 Iustin Pop
                 ]
330 51000365 Iustin Pop
    (_, _, errs) ->
331 51000365 Iustin Pop
      Left (ExitFailure 2, "Command line error: "  ++ concat errs ++ "\n" ++
332 51000365 Iustin Pop
            usageHelp progname options)
333 630c73e5 Iustin Pop
334 630c73e5 Iustin Pop
-- | Parse command line options and execute the main function of a
335 630c73e5 Iustin Pop
-- multi-personality binary.
336 630c73e5 Iustin Pop
genericMainCmds :: (StandardOptions a) =>
337 630c73e5 Iustin Pop
                   a
338 630c73e5 Iustin Pop
                -> PersonalityList a
339 630c73e5 Iustin Pop
                -> [GenericOptType a]
340 630c73e5 Iustin Pop
                -> IO ()
341 630c73e5 Iustin Pop
genericMainCmds defaults personalities genopts = do
342 630c73e5 Iustin Pop
  cmd_args <- getArgs
343 630c73e5 Iustin Pop
  prog <- getProgName
344 630c73e5 Iustin Pop
  (opts, args, fn) <-
345 630c73e5 Iustin Pop
    parseOptsCmds defaults cmd_args prog personalities genopts
346 630c73e5 Iustin Pop
  fn opts args
347 212b66c3 Helga Velroyen
348 212b66c3 Helga Velroyen
-- | Order a list of pairs in the order of the given list and fill up
349 212b66c3 Helga Velroyen
-- the list for elements that don't have a matching pair
350 212b66c3 Helga Velroyen
fillUpList :: ([(a, b)] -> a -> (a, b)) -> [a] -> [(a, b)] -> [(a, b)]
351 212b66c3 Helga Velroyen
fillUpList fill_fn inputs pairs =
352 212b66c3 Helga Velroyen
  map (fill_fn pairs) inputs
353 212b66c3 Helga Velroyen
354 212b66c3 Helga Velroyen
-- | Fill up a pair with fillup element if no matching pair is present
355 212b66c3 Helga Velroyen
fillPairFromMaybe :: (a -> (a, b)) -> (a -> [(a, b)] -> Maybe (a, b))
356 212b66c3 Helga Velroyen
                  -> [(a, b)] -> a -> (a, b)
357 212b66c3 Helga Velroyen
fillPairFromMaybe fill_fn pick_fn pairs element = fromMaybe (fill_fn element)
358 212b66c3 Helga Velroyen
    (pick_fn element pairs)
359 212b66c3 Helga Velroyen
360 212b66c3 Helga Velroyen
-- | Check if the given element matches the given pair
361 212b66c3 Helga Velroyen
isMatchingPair :: (Eq a) => a -> (a, b) -> Bool
362 212b66c3 Helga Velroyen
isMatchingPair element (pair_element, _) = element == pair_element
363 212b66c3 Helga Velroyen
364 212b66c3 Helga Velroyen
-- | Pick a specific element's pair from the list
365 212b66c3 Helga Velroyen
pickPairUnique :: (Eq a) => a -> [(a, b)] -> Maybe (a, b)
366 212b66c3 Helga Velroyen
pickPairUnique element pairs =
367 212b66c3 Helga Velroyen
  let res = filter (isMatchingPair element) pairs
368 212b66c3 Helga Velroyen
  in case res of
369 212b66c3 Helga Velroyen
    [x] -> Just x
370 212b66c3 Helga Velroyen
    -- if we have more than one result, we should get suspcious
371 212b66c3 Helga Velroyen
    _ -> Nothing