1 % Copyright (C) 2003 David Roundy 2 % 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. 7 % 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. 12 % 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. 17 18 \begin{code} 19 module Darcs.ArgumentDefaults ( get_default_flags ) where 20 import Data.Maybe ( catMaybes, listToMaybe, mapMaybe ) 21 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} 30 31 \paragraph{defaults}\label{defaults} 32 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. 48 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|. 54 55 \begin{tabular}{ll} 56 {\tt \verb!~/.darcs/defaults!} & provides defaults for this user account, on MS Windows~\ref{ms_win} \\ 57 {\tt \verb!repo/_darcs/prefs/defaults!} & provides defaults for one project,\\ 58 & overrules changes per user \\ 59 \end{tabular} 60 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} 68 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} 77 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} 97 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. 101 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} 111 112 Also, a global preferences file can be created with the name 113 \verb!.darcs/defaults! in your home directory, on MS Windows~\ref{ms_win}. 114 Options present there will be added to the repository-specific preferences. 115 If they conflict with repository-specific options, the repository-specific 116 ones will take precedence. 117 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 127 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 _ = [] 139 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 163 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 170 171 \end{code} 172