On Thu, Feb 23, 2012 at 04:29:36PM +0100, Guido Trotter wrote: > On Tue, Feb 21, 2012 at 1:21 PM, Iustin Pop <[email protected]> wrote: > > +oPort :: Int -> OptType > > +oPort def = Option "p" ["--port"] > > + (ReqArg (\ p o -> tryRead "reading port" p >>= \p' -> > > + return (o { optPort = Just p' })) "PORT") > > + ("Network port (default: " ++ show def ++ ")") > > + > > Maybe we can extract something out of the reqArg? Anyway we may have > other command line options in the future that have to parse integer > arguments, so we can avoid embedding this here.
Sure, absolutely. Although you'd need to pass in the "reading port", optPort, and similar, so we might not gain too much. But if we can, by all means. > > +-- | Command line parser, using the 'Options' structure. > > +parseOpts :: [String] -- ^ The command line arguments > > + -> String -- ^ The program name > > + -> [OptType] -- ^ The supported command line options > > + -> IO (DaemonOptions, [String]) -- ^ The resulting options > > + -- and leftover arguments > > +parseOpts argv progname options = > > + case getOpt Permute options argv of > > + (o, n, []) -> > > + do > > + let (pr, args) = (foldM (flip id) defaultOptions o, n) > > + po <- (case pr of > > + Bad msg -> do > > + hPutStrLn stderr "Error while parsing command\ > > + \line arguments:" > > + hPutStrLn stderr msg > > + exitWith $ ExitFailure 1 > > + Ok val -> return val) > > + when (optShowHelp po) $ do > > + putStr $ usageHelp progname options > > + exitWith ExitSuccess > > + when (optShowVer po) $ do > > + printf "%s %s\ncompiled with %s %s\nrunning on %s %s\n" > > + progname Version.version > > + compilerName (Data.Version.showVersion compilerVersion) > > + os arch :: IO () > > + exitWith ExitSuccess > > These two are not "parsing" arguments but are executing variations of > the program depending on them. > Not sure they belong to a "parseOpts" function. Also, is there really > no easier way to parse them? :) I have no idea :) This is code copied from Ganeti/HTools/CLI.hs, which was written before March 2009 :) We can split the various 'modes', but the basic parsing is the standard way to parse (see http://hackage.haskell.org/packages/archive/base/latest/doc/html/System-Console-GetOpt.html). A better option is switching to the more modern cmdargs module, but I haven't looked at that yet. > > +-- | Writes a PID file and locks it. > > +_writePidFile :: FilePath -> IO Fd > > +_writePidFile path = do > > + fd <- createFile path pidFileMode > > + setLock fd (WriteLock, AbsoluteSeek, 0, 0) > > + my_pid <- getProcessID > > + _ <- fdWrite fd (show my_pid ++ "\n") > > + return fd > > + > > +-- | Nice wrapper over '_writePidFile'. > > "Nice?" ? Also, this is the public function, so its docstring > shouldn't mention a private one but explain what it does. Sure then :) But I'd still mention the wrapper… Actually I wonder if this is not a generic function. It basically makes either an Ok or Bad if we got any IO exception. Hmm… > > +-- | Generic daemon startup. > > +genericMain :: GanetiDaemon -> [OptType] -> (DaemonOptions -> IO ()) -> IO > > () > > +genericMain daemon options main = do > > + (opts, args) <- parseArgs (daemonName daemon) options > > + > > + unless (null args) $ do > > + hPutStrLn stderr "This program doesn't take any arguments" > > + exitWith $ ExitFailure C.exitFailure > > + > > I believe evaluation of "help" and "version" goes here, and not during > the parsing. Agreed. But then we'll need to define a new type, oh noes! thanks, iustin
