]> gitweb.michael.orlitzky.com - dead/halcyon.git/blob - src/CommandLine.hs
15120439d40dd1ece0a933bc730b4cafa2e906ff
[dead/halcyon.git] / src / CommandLine.hs
1 -- |The CommandLine module handles parsing of the command-line options.
2 -- It should more or less be a black box, providing Main with only the
3 -- information it requires.
4 module CommandLine
5 ( heartbeat,
6 help_set,
7 help_text,
8 from_email_address,
9 to_email_address,
10 parse_errors,
11 parse_usernames
12 ) where
13
14 import Data.Maybe (isJust, isNothing)
15 import System.Console.GetOpt
16 import System.Environment (getArgs)
17
18
19
20 -- |A record containing values for all available options.
21 data Options = Options { opt_heartbeat :: Maybe Int,
22 opt_help :: Bool,
23 opt_ignore_retweets :: Bool,
24 opt_ignore_replies :: Bool,
25 opt_from :: Maybe String,
26 opt_to :: Maybe String }
27
28
29 -- |Constructs an instance of Options, with each of its members set to
30 -- default values.
31 default_options :: Options
32 default_options = Options { opt_heartbeat = Just 600,
33 opt_help = False,
34 opt_ignore_retweets = False,
35 opt_ignore_replies = False,
36 opt_from = Nothing,
37 opt_to = Nothing }
38
39
40 -- |The options list that we construct associates a function with each
41 -- option. This function is responsible for updating an Options record
42 -- with the appropriate value.
43 --
44 -- For more information and an example of this idiom, see,
45 --
46 -- <http://www.haskell.org/haskellwiki/High-level_option_handling_with_GetOpt>
47 --
48 options :: [OptDescr (Options -> IO Options)]
49 options =
50 [ Option
51 ['h']["help"]
52 (NoArg set_help)
53 "Prints this help message.",
54
55 Option
56 ['n']["heartbeat"]
57 (ReqArg set_heartbeat "heartbeat")
58 "How many seconds to wait between polling.",
59
60 Option
61 ['t']["to"]
62 (ReqArg set_to "email_address")
63 "Send tweets TO email_address.",
64
65 Option
66 ['f']["from"]
67 (ReqArg set_from "email_address")
68 "Send tweets FROM email_address.",
69
70 Option
71 ['i']["ignore-retweets"]
72 (NoArg set_ignore_retweets)
73 "Ignore retweets.",
74
75 Option
76 ['I']["ignore-replies"]
77 (NoArg set_ignore_replies)
78 "Ignore retweets."
79 ]
80
81
82 -- | Attempt to parse an 'Int' from a 'String'. This is just a 'Maybe'
83 -- wrapper around 'reads'.
84 parse_int :: String -> Maybe Int
85 parse_int s =
86 case (reads s) of
87 [(n,_)] -> Just n
88 _ -> Nothing
89
90 set_heartbeat :: String -> Options -> IO Options
91 set_heartbeat arg opts = do
92 let new_heartbeat = parse_int arg
93 return opts { opt_heartbeat = new_heartbeat }
94
95 set_help :: Options -> IO Options
96 set_help opts = do
97 return opts { opt_help = True }
98
99 set_ignore_retweets :: Options -> IO Options
100 set_ignore_retweets opts =
101 return opts { opt_ignore_retweets = True }
102
103 set_ignore_replies :: Options -> IO Options
104 set_ignore_replies opts =
105 return opts { opt_ignore_replies = True }
106
107 set_to :: String -> Options -> IO Options
108 set_to arg opts = do
109 return opts { opt_to = Just arg }
110
111 set_from :: String -> Options -> IO Options
112 set_from arg opts = do
113 return opts { opt_from = Just arg }
114
115
116 -- The usage header.
117 usage :: String
118 usage = "Usage: twat [-n heartbeat] [-t to_address] [-f from_address] <username1> [username2, [username3]...]"
119
120
121 -- The usage header, and all available flags (as generated by GetOpt)
122 help_text :: String
123 help_text = usageInfo usage options
124
125
126 -- Return a list of options.
127 parse_options :: IO Options
128 parse_options = do
129 argv <- getArgs
130 let (actions, _, _) = getOpt Permute options argv
131
132 -- This will execute each of the functions contained in our options
133 -- list, one after another, on a default_options record. The end
134 -- result should be an Options instance with all of its members set
135 -- correctly.
136 opts <- foldl (>>=) (return default_options) actions
137
138 return opts
139
140
141 -- | A list of parse errors relating to the heartbeat.
142 heartbeat_errors :: IO [String]
143 heartbeat_errors = do
144 hb <- heartbeat
145 if (isNothing hb)
146 then return ["\"heartbeat\" does not appear to be an integer."]
147 else return []
148
149 -- |Parse errors relating to the list of usernames.
150 username_errors :: IO [String]
151 username_errors = do
152 argv <- getArgs
153 let (_, usernames, _) = getOpt Permute options argv
154
155 if (null usernames)
156 then return ["no usernames provided."]
157 else return []
158
159
160 -- |Parse errors relating to the "To" address.
161 to_errors :: IO [String]
162 to_errors = do
163 toaddr <- to_email_address
164 fromaddr <- from_email_address
165 if (isNothing toaddr) && (isJust fromaddr)
166 then return ["\"from\" address specified without \"to\" address."]
167 else return []
168
169
170 -- |Parse errors relating to the "From" address.
171 from_errors :: IO [String]
172 from_errors = do
173 toaddr <- to_email_address
174 fromaddr <- from_email_address
175 if (isJust toaddr) && (isNothing fromaddr)
176 then return ["\"to\" address specified without \"from\" address."]
177 else return []
178
179
180 -- |Format an error message for printing.
181 format_error :: String -> String
182 format_error err = "ERROR: " ++ err ++ "\n"
183
184
185 -- |Return a list of all parse errors.
186 parse_errors :: IO [String]
187 parse_errors = do
188 argv <- getArgs
189 let (_, _, errors) = getOpt Permute options argv
190 errs_heartbeat <- heartbeat_errors
191 errs_username <- username_errors
192 errs_to <- to_errors
193 errs_from <- from_errors
194 return $ map format_error (errors ++
195 errs_heartbeat ++
196 errs_username ++
197 errs_to ++
198 errs_from)
199
200 -- |Was the "help" option passed on the command line?
201 help_set :: IO Bool
202 help_set = do
203 opts <- parse_options
204 return (opt_help opts)
205
206 -- |What's the heartbeat?
207 heartbeat :: IO (Maybe Int)
208 heartbeat = do
209 opts <- parse_options
210 return (opt_heartbeat opts)
211
212 -- |What "To" address was given on the command line?
213 to_email_address :: IO (Maybe String)
214 to_email_address = do
215 opts <- parse_options
216 return (opt_to opts)
217
218 -- |What "From" address was given on the command line?
219 from_email_address :: IO (Maybe String)
220 from_email_address = do
221 opts <- parse_options
222 return (opt_from opts)
223
224
225 -- |What usernames were passed on the command line?
226 parse_usernames :: IO [String]
227 parse_usernames = do
228 argv <- getArgs
229 let (_, usernames, _) = getOpt Permute options argv
230 return usernames