Merge branch 'darcs' into master
[git-darcs-import.git] / src / Darcs / ArgumentDefaults.lhs
blob31ca42ad9e3439d86f6f5bed9be92f58ead69517
1 % Copyright (C) 2003 David Roundy
3 % This program is free software; you can redistribute it and/or modify
4 % it under the terms of the GNU General Public License as published by
5 % the Free Software Foundation; either version 2, or (at your option)
6 % any later version.
8 % This program is distributed in the hope that it will be useful,
9 % but WITHOUT ANY WARRANTY; without even the implied warranty of
10 % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 % GNU General Public License for more details.
13 % You should have received a copy of the GNU General Public License
14 % along with this program; see the file COPYING. If not, write to
15 % the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
16 % Boston, MA 02110-1301, USA.
18 \begin{code}
19 module Darcs.ArgumentDefaults ( get_default_flags ) where
20 import Data.Maybe ( catMaybes, listToMaybe, mapMaybe )
22 import Darcs.Arguments ( DarcsFlag,
23 DarcsOption( DarcsArgOption, DarcsNoArgOption, DarcsMultipleChoiceOption ),
24 arein, isin )
25 import Darcs.Commands ( CommandControl( Command_data ),
26 command_alloptions )
27 import Darcs.Commands.Help ( command_control_list )
28 import Darcs.Repository.Prefs ( get_global, get_preflist )
29 \end{code}
31 \paragraph{defaults}\label{defaults}
33 Default values for darcs commands can be configured on a per-repository
34 basis by editing (and possibly creating) the \verb!_darcs/prefs/defaults!
35 file. Each line of this file has the following form:
36 \begin{verbatim}
37 COMMAND FLAG VALUE
38 \end{verbatim}
39 where \verb!COMMAND! is either the name of the command to which the default
40 applies, or \verb!ALL! to indicate that the default applies to all commands
41 accepting that flag. The \verb!FLAG! term is the name of the long argument
42 option without the ``\verb!--!'', i.e.\ \verb!verbose! rather than
43 \verb!--verbose!. Finally, the \verb!VALUE! option can be omitted if the
44 flag is one such as \verb!verbose! that doesn't involve a value.
45 If the value has spaces in it, use single quotes, not double quotes, to surround it.
46 Each line only takes one flag. To set multiple defaults for the same
47 command (or for \verb!ALL! commands), use multiple lines.
49 Note that the use of \verb|ALL| easily can have unpredicted consequences,
50 especially if commands in newer versions of darcs accepts flags that they
51 didn't in previous versions. A command like \verb|obliterate| could be
52 devastating with the ``wrong'' flags (for example --all). Only use safe
53 flags with \verb|ALL|.
55 \begin{tabular}{ll}
56 {\tt \verb!~/.darcs/defaults!} & provides defaults for this user account \\
57 {\tt \verb!repo/_darcs/prefs/defaults!} & provides defaults for one project,\\
58 & overrules changes per user \\
59 \end{tabular}
61 For example, if your system clock is bizarre, you could instruct darcs to
62 always ignore the file modification times by adding the following line to
63 your \verb!_darcs/prefs/defaults! file. (Note that this would have to be
64 done for each repository!)
65 \begin{verbatim}
66 ALL ignore-times
67 \end{verbatim}
69 If you never want to run a test when recording to a particular repository
70 (but still want to do so when running
71 \verb'check' on that repository), and like to name
72 all your patches ``Stupid patch'', you could use the following:
73 \begin{verbatim}
74 record no-test
75 record patch-name Stupid patch
76 \end{verbatim}
78 If you would like a command to be run every time patches are recorded
79 in a particular repository (for example if you have one central
80 repository, that all developers contribute to), then you can set apply
81 to always run a command when apply is successful. For example, if you
82 need to make sure that the files in the repository have the correct
83 access rights you might use the following. There are two things
84 to note about using darcs this way:
85 \begin{itemize}
86 \item Without the second line you will get errors, because the sub
87 process that runs apply cannot prompt interactively.
88 \item Whatever script is run by the post apply command should not be
89 added to the repository with \verb!darcs add!; doing so would
90 allow people to modify that file and then run arbitrary scripts on
91 your main repository, possibly damaging or violating security.
92 \end{itemize}
93 \begin{verbatim}
94 apply posthook chmod -R a+r *
95 apply run-posthook
96 \end{verbatim}
98 Similarly, if you need a command to run automatically before darcs
99 performs an action you can use a prehook. Using prehooks it could be
100 possible to canonicalize line endings before recording patches.
102 There are some options which are meant specifically for use in
103 \verb!_darcs/prefs/defaults!. One of them is \verb!--disable!. As the name
104 suggests, this option will disable every command that got it as argument. So,
105 if you are afraid that you could damage your repositories by inadvertent use of
106 a command like amend-record, add the following line to
107 \verb!_darcs/prefs/defaults!:
108 \begin{verbatim}
109 amend-record disable
110 \end{verbatim}
112 Also, a global preferences file can be created with the name
113 \verb!.darcs/defaults! in your home directory. Options present there will
114 be added to the repository-specific preferences.
115 If they conflict with repository-specific options, the repository-specific
116 ones will take precedence.
118 \begin{code}
119 get_default_flags :: String -> [DarcsOption] -> [DarcsFlag] -> IO [DarcsFlag]
120 get_default_flags com com_opts already = do
121 repo_defs <- default_content $ get_preflist "defaults"
122 global_defs <- default_content $ get_global "defaults"
123 let repo_flags = get_flags_from com com_opts already repo_defs
124 global_flags = get_flags_from com com_opts
125 (already++repo_flags) global_defs
126 return $ repo_flags ++ global_flags
128 get_flags_from :: String -> [DarcsOption] -> [DarcsFlag] -> [(String,String,String)] -> [DarcsFlag]
129 get_flags_from com com_opts already defs =
130 options_for com_defs com_opts com_opts ++
131 options_for all_defs com_opts all_opts
132 where com_defs = filter (\ (c,_,_) -> c == com) defs
133 all_defs = filter (\ (c,_,_) -> c == "ALL") defs
134 options_for d o ao = concatMap (find_option o ao already) d
135 all_opts = concatMap get_opts command_control_list
136 get_opts (Command_data c) = let (o1, o2) = command_alloptions c
137 in o1 ++ o2
138 get_opts _ = []
140 find_option :: [DarcsOption] -> [DarcsOption] -> [DarcsFlag] -> (String,String,String) -> [DarcsFlag]
141 find_option opts all_opts already (c, f, d) =
142 if null $ mapMaybe choose_option all_opts
143 then error $ "Bad default option: command '"++c++"' has no option '"++f++"'."
144 else concat $ mapMaybe choose_option opts
145 where choose_option (DarcsNoArgOption _ fls o _)
146 | o `elem` already = Just []
147 | f `elem` fls = if null d
148 then Just [o]
149 else error $ "Bad default option: '"++f
150 ++"' takes no argument, but '"++d
151 ++"' argument given."
152 choose_option (DarcsArgOption _ fls o _ _)
153 | o `isin` already = Just []
154 | f `elem` fls = if null d
155 then error $ "Bad default option: '"++f
156 ++"' requires an argument, but no "
157 ++"argument given."
158 else Just [o d]
159 choose_option (DarcsMultipleChoiceOption os)
160 | os `arein` already = Just []
161 | otherwise = listToMaybe $ mapMaybe choose_option os
162 choose_option _ = Nothing
164 default_content :: IO [String] -> IO [(String,String,String)]
165 default_content = fmap (catMaybes . map (doline.words))
166 where doline (c:a:r) = Just (c, drop_dashdash a, unwords r)
167 doline _ = Nothing
168 drop_dashdash ('-':'-':a) = a
169 drop_dashdash a = a
171 \end{code}