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'",
60 " -C,--list-configs List all the default config file names defined in the",
61 " configuration files.",
62 " -F,--list-features List all the features defined in the configuration files.",
65 " {addfeature,af} <feature_name> [config_file_path]",
66 " {defconfig,dc} [config_name] [target_directory]"
69 public delegate void ListDefaultConfigsHandler ();
70 public delegate void ListFeaturesHandler ();
72 public event ListDefaultConfigsHandler OnListDefaultConfigs;
73 public event ListFeaturesHandler OnListFeatures;
75 List <string> plain_arguments;
76 Dictionary <string, string> unknown_arguments;
78 public string ConfigFile;
79 public FeatureTarget Target = FeatureTarget.Any;
80 public bool ListDefaultConfigs;
81 public bool ListFeatures;
83 public Dictionary <string, string> UnknownArguments {
85 if (unknown_arguments == null || unknown_arguments.Count == 0)
88 return unknown_arguments;
92 public string[] PlainArguments {
94 if (plain_arguments == null || plain_arguments.Count == 0)
97 return plain_arguments.ToArray ();
101 public MConfigOptions ()
103 unknown_arguments = new Dictionary <string, string> ();
104 plain_arguments = new List <string> ();
107 public void Parse (string[] args)
109 if (args == null || args.Length == 0)
112 int len = args.Length;
115 for (int i = 0; i < len; i++) {
121 i += ProcessArgument (i, arg, args, len);
125 plain_arguments.Add (arg);
131 static char[] paramStartChars = {':', '='};
133 int ProcessArgument (int idx, string argument, string[] args, int argsLen)
136 bool haveMoreDashes = false, badArg = false;
137 int argumentLen = argument.Length;
142 haveMoreDashes = !badArg && (argument [1] == '-');
144 if (argumentLen == 2 && haveMoreDashes)
148 Console.Error.WriteLine ("Invalid argument: {0}", argument);
149 Environment.Exit (1);
155 int paramPos = argument.IndexOfAny (paramStartChars, argnameIdx);
156 bool haveParam = true;
158 if (paramPos == -1) {
160 paramPos = argumentLen;
163 string argName = argument.Substring (argnameIdx, paramPos - argnameIdx);
164 string argParam = haveParam ? argument.Substring (paramPos + 1) : null;
168 if (!haveParam && haveMoreDashes) {
171 argParam = args [idx];
192 RequiredParameterMissing (argName);
195 Target = Helpers.ConvertEnum <FeatureTarget> (argParam, "target");
196 } catch (Exception ex) {
197 OptionParameterError (argName, ex.Message);
203 ListDefaultConfigs = true;
207 case "list-features":
212 unknown_arguments.Add (argName, argParam);
219 void RequiredParameterMissing (string argName)
221 Console.Error.WriteLine ("Argument '{0}' requires a parameter", argName);
222 Environment.Exit (1);
225 void OptionParameterError (string argName, string message)
227 Console.Error.WriteLine ("Parameter value is invalid for argument '{0}'.",
229 Console.Error.WriteLine (message);
230 Environment.Exit (1);
235 foreach (string line in usage)
236 Console.WriteLine (line);
237 Environment.Exit (1);
242 Assembly asm = Assembly.GetExecutingAssembly () ?? Assembly.GetCallingAssembly ();
243 object[] attrs = asm != null ? asm.GetCustomAttributes (false) : null;
244 string product = "mconfig", version = "0.0.0.0", copyright = "", description = "";
247 Version v = asm.GetName ().Version;
249 version = v.ToString ();
253 foreach (object o in attrs) {
254 if (o is AssemblyProductAttribute)
255 product = ((AssemblyProductAttribute)o).Product;
256 else if (o is AssemblyCopyrightAttribute)
257 copyright = ((AssemblyCopyrightAttribute)o).Copyright;
258 else if (o is AssemblyDescriptionAttribute)
259 description = ((AssemblyDescriptionAttribute)o).Description;
262 Console.WriteLine ("Missing version information");
264 Console.WriteLine ("{0} - {1} {2}", product, description, version);
265 Console.WriteLine (copyright);
267 Environment.Exit (1);
273 static string[] configPaths = {
274 Constants.GlobalConfigPath,
275 Path.Combine (ConfigPath, "config.xml"),
276 Path.Combine (".", "mconfig.xml"),
280 static CommandHandler[] commands = {
281 new CommandHandler (new string[] {"addfeature", "af"}, HandleAddFeature),
282 new CommandHandler (new string[] {"defconfig", "dc"}, HandleDefaultConfig)
285 static string ConfigPath {
287 string configPath = Environment.GetEnvironmentVariable ("XDG_CONFIG_HOME");
288 if (String.IsNullOrEmpty (configPath))
289 configPath = Path.Combine (Environment.GetEnvironmentVariable ("HOME"), ".config");
290 return Path.Combine (configPath, "mconfig");
294 static HandleCommand FindCommandHandler (string command)
296 foreach (CommandHandler ch in commands) {
297 foreach (string name in ch.Names)
305 static void DisplayList (string banner, string[] list)
307 Console.WriteLine (banner);
308 if (list == null || list.Length == 0) {
309 Console.WriteLine ("No data found");
313 foreach (string item in list)
314 Console.WriteLine (" {0}", item);
317 static int Main (string[] args)
319 MConfigOptions options = new MConfigOptions ();
320 options.Parse (args);
322 if (!String.IsNullOrEmpty (options.ConfigFile))
323 configPaths [3] = options.ConfigFile;
325 Configuration config = new Configuration ();
326 config.Load (configPaths);
329 if (options.ListDefaultConfigs) {
330 DisplayList ("Default config files", config.DefaultConfigFiles);
334 if (options.ListFeatures) {
335 DisplayList ("Available features", config.Features);
342 string[] commandArguments = options.PlainArguments;
343 if (commandArguments == null || commandArguments.Length == 0) {
348 HandleCommand commandHandler = FindCommandHandler (commandArguments [0]);
349 if (commandHandler == null) {
350 Console.Error.WriteLine ("Unknown command '{0}'", commandArguments [0]);
354 IDefaultConfigFileContainer[] containers = config.GetHandlersForInterface <IDefaultConfigFileContainer> ();
355 if (containers != null && containers.Length > 0)
356 foreach (IDefaultConfigFileContainer c in containers)
357 c.OverwriteFile += new OverwriteFileEventHandler (OnOverwriteFile);
359 return commandHandler (options, config);
362 static void OnOverwriteFile (object sender, OverwriteFileEventArgs e)
364 Console.Write ("Do you want to overwrite existing file '{0}'? [{1}] ",
365 e.Name, e.Overwrite ? "Y/n" : "y/N");
366 ConsoleKeyInfo cki = Console.ReadKey (false);
376 Console.WriteLine ();
379 static int HandleAddFeature (MConfigOptions options, Configuration config)
381 string[] commandArguments = options.PlainArguments;
382 if (commandArguments.Length < 2) {
383 Console.Error.WriteLine ("Command requires at least one argument.");
387 FeatureTarget target = options.Target;
388 string featureName = commandArguments [1], configPath;
389 if (commandArguments.Length > 2)
390 configPath = commandArguments [2];
393 case FeatureTarget.Any:
394 Console.Error.WriteLine ("No default config file for target 'Any'");
397 case FeatureTarget.Web:
398 configPath = "Web.config";
401 case FeatureTarget.Application:
402 configPath = "application.exe.config";
406 Console.Error.WriteLine ("Unknown target '{0}'", target);
412 config.AddFeature (configPath, target, featureName);
413 } catch (Exception ex) {
414 Console.Error.WriteLine ("Failed to add feature '{0}' to config file '{1}'.\n{2}",
415 featureName, configPath, ex.Message);
422 static int HandleDefaultConfig (MConfigOptions options, Configuration config)
424 FeatureTarget target = options.Target;
425 string[] commandArguments = options.PlainArguments;
426 string configName, targetPath;
428 if (commandArguments.Length < 2) {
430 case FeatureTarget.Any:
431 Console.Error.WriteLine ("No default config file for target 'Any'");
434 case FeatureTarget.Web:
435 configName = "Web.config";
438 case FeatureTarget.Application:
439 configName = "application.exe.config";
443 Console.Error.WriteLine ("Unknown target '{0}'", target);
447 configName = commandArguments [1];
449 if (commandArguments.Length < 3)
452 targetPath = commandArguments [2];
455 config.WriteDefaultConfigFile (configName, targetPath, target);
456 } catch (Exception ex) {
457 Console.Error.WriteLine ("Failed to write default config file '{0}':\n{1}",
458 configName, ex.Message);