3 // Marek Habersack (mhabersack@novell.com)
5 // (C) 2007 Novell, Inc
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 using System
.Collections
.Generic
;
31 using System
.Reflection
;
33 namespace Mono
.MonoConfig
35 delegate int HandleCommand (MConfigOptions options
, Configuration config
);
37 struct CommandHandler
{
38 public readonly HandleCommand Handler
;
39 public readonly string[] Names
;
41 public CommandHandler (string[] names
, HandleCommand handler
)
44 this.Handler
= handler
;
51 "Usage: mconfig [options] command [command_parameters]",
54 " -?,-h,--help Display this usage information",
55 " -v,--version Display version information",
56 " -c,--config=<filepath> Read the specified config file in addition to",
57 " the standard ones. Settings in this file override ones",
58 " in the other files.",
59 " -t,--target={any,web,application} Use this target when executing 'command'",
61 "To see the list of commands, features and default config file templates, run mconfig",
62 "without any parameters"
65 string[] usageCommands
= {
66 "Available commands (see 'man mconfig' for details):",
67 " {addfeature,af} <feature_name> [config_file_path]",
68 " Add the named feature to the specified config file",
70 " {defconfig,dc} [template_name] [target_directory]",
71 " Write a config file based on the named template.",
75 List
<string> plain_arguments
;
76 Dictionary
<string, string> unknown_arguments
;
78 public string ConfigFile
;
79 public FeatureTarget Target
= FeatureTarget
.Any
;
81 public Dictionary
<string, string> UnknownArguments
{
83 if (unknown_arguments
== null || unknown_arguments
.Count
== 0)
86 return unknown_arguments
;
90 public string[] PlainArguments
{
92 if (plain_arguments
== null || plain_arguments
.Count
== 0)
95 return plain_arguments
.ToArray ();
99 public MConfigOptions ()
101 unknown_arguments
= new Dictionary
<string, string> ();
102 plain_arguments
= new List
<string> ();
105 public void Parse (string[] args
)
107 if (args
== null || args
.Length
== 0)
110 int len
= args
.Length
;
113 for (int i
= 0; i
< len
; i
++) {
119 i
+= ProcessArgument (i
, arg
, args
, len
);
123 plain_arguments
.Add (arg
);
129 static char[] paramStartChars
= {':', '='}
;
131 int ProcessArgument (int idx
, string argument
, string[] args
, int argsLen
)
134 bool haveMoreDashes
= false, badArg
= false;
135 int argumentLen
= argument
.Length
;
140 haveMoreDashes
= !badArg
&& (argument
[1] == '-');
142 if (argumentLen
== 2 && haveMoreDashes
)
146 Console
.Error
.WriteLine ("Invalid argument: {0}", argument
);
147 Environment
.Exit (1);
153 int paramPos
= argument
.IndexOfAny (paramStartChars
, argnameIdx
);
154 bool haveParam
= true;
156 if (paramPos
== -1) {
158 paramPos
= argumentLen
;
161 string argName
= argument
.Substring (argnameIdx
, paramPos
- argnameIdx
);
162 string argParam
= haveParam
? argument
.Substring (paramPos
+ 1) : null;
166 if (!haveParam
&& haveMoreDashes
) {
169 argParam
= args
[idx
];
190 RequiredParameterMissing (argName
);
193 Target
= Helpers
.ConvertEnum
<FeatureTarget
> (argParam
, "target");
194 } catch (Exception ex
) {
195 OptionParameterError (argName
, ex
.Message
);
200 unknown_arguments
.Add (argName
, argParam
);
207 void RequiredParameterMissing (string argName
)
209 Console
.Error
.WriteLine ("Argument '{0}' requires a parameter", argName
);
210 Environment
.Exit (1);
213 void OptionParameterError (string argName
, string message
)
215 Console
.Error
.WriteLine ("Parameter value is invalid for argument '{0}'.",
217 Console
.Error
.WriteLine (message
);
218 Environment
.Exit (1);
221 void ShowUsage (string[] msg
, bool exit
)
223 foreach (string line
in msg
)
224 Console
.WriteLine (line
);
226 Environment
.Exit (1);
231 ShowUsage (usage
, true);
234 public void UsageCommands ()
236 ShowUsage (usageCommands
, false);
241 Assembly asm
= Assembly
.GetExecutingAssembly () ?? Assembly
.GetCallingAssembly ();
242 object[] attrs
= asm
!= null ? asm
.GetCustomAttributes (false) : null;
243 string product
= "mconfig", version
= "0.0.0.0", copyright
= "", description
= "";
246 Version v
= asm
.GetName ().Version
;
248 version
= v
.ToString ();
252 foreach (object o
in attrs
) {
253 if (o
is AssemblyProductAttribute
)
254 product
= ((AssemblyProductAttribute
)o
).Product
;
255 else if (o
is AssemblyCopyrightAttribute
)
256 copyright
= ((AssemblyCopyrightAttribute
)o
).Copyright
;
257 else if (o
is AssemblyDescriptionAttribute
)
258 description
= ((AssemblyDescriptionAttribute
)o
).Description
;
261 Console
.WriteLine ("Missing version information");
263 Console
.WriteLine ("{0} - {1} {2}", product
, description
, version
);
264 Console
.WriteLine (copyright
);
266 Environment
.Exit (1);
272 static string[] configPaths
= {
273 Constants
.GlobalConfigPath
,
274 Path
.Combine (ConfigPath
, "config.xml"),
275 Path
.Combine (".", "mconfig.xml"),
279 static CommandHandler
[] commands
= {
280 new CommandHandler (new string[] {"addfeature", "af"}
, HandleAddFeature
),
281 new CommandHandler (new string[] {"defconfig", "dc"}
, HandleDefaultConfig
)
284 static string ConfigPath
{
286 string configPath
= Environment
.GetEnvironmentVariable ("XDG_CONFIG_HOME");
287 if (String
.IsNullOrEmpty (configPath
))
288 configPath
= Path
.Combine (Environment
.GetEnvironmentVariable ("HOME"), ".config");
289 return Path
.Combine (configPath
, "mconfig");
293 static HandleCommand
FindCommandHandler (string command
)
295 foreach (CommandHandler ch
in commands
) {
296 foreach (string name
in ch
.Names
)
304 static void DisplayList (string banner
, string[] list
)
306 Console
.WriteLine (banner
);
307 if (list
== null || list
.Length
== 0) {
308 Console
.WriteLine ("No data found");
312 foreach (string item
in list
)
313 Console
.WriteLine (" {0}", item
);
316 static void PrintException (Exception ex
, string format
, params object[] parms
)
320 Console
.Error
.WriteLine (format
, parms
);
321 Console
.Error
.WriteLine (" {0}", ex
.Message
);
322 if (ex
.InnerException
!= null)
323 Console
.Error
.WriteLine (" {0}", ex
.InnerException
.Message
);
326 static int Main (string[] args
)
328 MConfigOptions options
= new MConfigOptions ();
329 options
.Parse (args
);
331 if (!String
.IsNullOrEmpty (options
.ConfigFile
))
332 configPaths
[3] = options
.ConfigFile
;
334 Configuration config
= new Configuration ();
336 config
.Load (configPaths
);
337 } catch (Exception ex
) {
338 PrintException (ex
, "Failed to load configuration files:");
342 string[] commandArguments
= options
.PlainArguments
;
343 if (commandArguments
== null || commandArguments
.Length
== 0) {
344 options
.UsageCommands ();
345 DisplayList ("Default config files:", config
.DefaultConfigFiles
);
346 Console
.WriteLine ();
347 DisplayList ("Available features:", config
.Features
);
351 HandleCommand commandHandler
= FindCommandHandler (commandArguments
[0]);
352 if (commandHandler
== null) {
353 Console
.Error
.WriteLine ("Unknown command '{0}'", commandArguments
[0]);
357 IDefaultConfigFileContainer
[] containers
= config
.GetHandlersForInterface
<IDefaultConfigFileContainer
> ();
358 if (containers
!= null && containers
.Length
> 0)
359 foreach (IDefaultConfigFileContainer c
in containers
)
360 c
.OverwriteFile
+= new OverwriteFileEventHandler (OnOverwriteFile
);
362 return commandHandler (options
, config
);
365 static void OnOverwriteFile (object sender
, OverwriteFileEventArgs e
)
367 Console
.Write ("Do you want to overwrite existing file '{0}'? [{1}] ",
368 e
.Name
, e
.Overwrite
? "Y/n" : "y/N");
369 ConsoleKeyInfo cki
= Console
.ReadKey (false);
379 Console
.WriteLine ();
382 static int HandleAddFeature (MConfigOptions options
, Configuration config
)
384 string[] commandArguments
= options
.PlainArguments
;
385 if (commandArguments
.Length
< 2) {
386 Console
.Error
.WriteLine ("Command requires at least one argument.");
390 FeatureTarget target
= options
.Target
;
391 string featureName
= commandArguments
[1], configPath
;
392 if (commandArguments
.Length
> 2)
393 configPath
= commandArguments
[2];
396 case FeatureTarget
.Any
:
397 Console
.Error
.WriteLine ("No default config file for target 'Any'");
400 case FeatureTarget
.Web
:
401 configPath
= "Web.config";
404 case FeatureTarget
.Application
:
405 configPath
= "application.exe.config";
409 Console
.Error
.WriteLine ("Unknown target '{0}'", target
);
415 config
.AddFeature (configPath
, target
, featureName
);
416 } catch (Exception ex
) {
417 PrintException (ex
, "Failed to add feature '{0}' to config file '{1}'.",
418 featureName
, configPath
);
425 static int HandleDefaultConfig (MConfigOptions options
, Configuration config
)
427 FeatureTarget target
= options
.Target
;
428 string[] commandArguments
= options
.PlainArguments
;
429 string configName
, targetPath
;
431 if (commandArguments
.Length
< 2) {
433 case FeatureTarget
.Any
:
434 Console
.Error
.WriteLine ("No default config file for target 'Any'");
437 case FeatureTarget
.Web
:
438 configName
= "Web.config";
441 case FeatureTarget
.Application
:
442 configName
= "application.exe.config";
446 Console
.Error
.WriteLine ("Unknown target '{0}'", target
);
450 configName
= commandArguments
[1];
452 if (commandArguments
.Length
< 3)
455 targetPath
= commandArguments
[2];
458 config
.WriteDefaultConfigFile (configName
, targetPath
, target
);
459 } catch (Exception ex
) {
460 PrintException (ex
, "Failed to write default config file '{0}':",