2009-09-24 Zoltan Varga <vargaz@gmail.com>
[mcs.git] / tools / mconfig / mconfig.cs
blob5887f739dbbfb43b1102445f635a313867e17be3
1 //
2 // Authors:
3 // Marek Habersack (mhabersack@novell.com)
4 //
5 // (C) 2007 Novell, Inc
6 //
8 //
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:
16 //
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 //
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.
28 using System;
29 using System.Collections.Generic;
30 using System.IO;
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)
43 this.Names = names;
44 this.Handler = handler;
48 class MConfigOptions
50 string[] usage = {
51 "Usage: mconfig [options] command [command_parameters]",
52 "Options:",
53 "",
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 "",
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",
69 "",
70 " {defconfig,dc} [template_name] [target_directory]",
71 " Write a config file based on the named template.",
73 };
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 {
82 get {
83 if (unknown_arguments == null || unknown_arguments.Count == 0)
84 return null;
86 return unknown_arguments;
90 public string[] PlainArguments {
91 get {
92 if (plain_arguments == null || plain_arguments.Count == 0)
93 return null;
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)
108 return;
110 int len = args.Length;
111 string arg;
113 for (int i = 0; i < len; i++) {
114 arg = args [i];
116 switch (arg [0]) {
117 case '-':
118 case '/':
119 i += ProcessArgument (i, arg, args, len);
120 break;
122 default:
123 plain_arguments.Add (arg);
124 break;
129 static char[] paramStartChars = {':', '='};
131 int ProcessArgument (int idx, string argument, string[] args, int argsLen)
133 int argnameIdx = 1;
134 bool haveMoreDashes = false, badArg = false;
135 int argumentLen = argument.Length;
137 if (argumentLen < 2)
138 badArg = true;
140 haveMoreDashes = !badArg && (argument [1] == '-');
142 if (argumentLen == 2 && haveMoreDashes)
143 badArg = true;
145 if (badArg) {
146 Console.Error.WriteLine ("Invalid argument: {0}", argument);
147 Environment.Exit (1);
150 if (haveMoreDashes)
151 argnameIdx++;
153 int paramPos = argument.IndexOfAny (paramStartChars, argnameIdx);
154 bool haveParam = true;
156 if (paramPos == -1) {
157 haveParam = false;
158 paramPos = argumentLen;
161 string argName = argument.Substring (argnameIdx, paramPos - argnameIdx);
162 string argParam = haveParam ? argument.Substring (paramPos + 1) : null;
164 int ret = 0;
166 if (!haveParam && haveMoreDashes) {
167 idx++;
168 if (idx < argsLen) {
169 argParam = args [idx];
170 ret++;
171 haveParam = true;
175 switch (argName) {
176 case "?":
177 case "h":
178 case "help":
179 Usage ();
180 break;
182 case "v":
183 case "version":
184 ShowVersion ();
185 break;
187 case "t":
188 case "target":
189 if (!haveParam)
190 RequiredParameterMissing (argName);
192 try {
193 Target = Helpers.ConvertEnum <FeatureTarget> (argParam, "target");
194 } catch (Exception ex) {
195 OptionParameterError (argName, ex.Message);
197 break;
199 default:
200 unknown_arguments.Add (argName, argParam);
201 break;
204 return ret;
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}'.",
216 argName);
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);
225 if (exit)
226 Environment.Exit (1);
229 public void Usage ()
231 ShowUsage (usage, true);
234 public void UsageCommands ()
236 ShowUsage (usageCommands, false);
239 void ShowVersion ()
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 = "";
245 if (asm != null) {
246 Version v = asm.GetName ().Version;
247 if (v != null)
248 version = v.ToString ();
251 if (attrs != null) {
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;
260 } else
261 Console.WriteLine ("Missing version information");
263 Console.WriteLine ("{0} - {1} {2}", product, description, version);
264 Console.WriteLine (copyright);
266 Environment.Exit (1);
270 class MConfig
272 static string[] configPaths = {
273 Constants.GlobalConfigPath,
274 Path.Combine (ConfigPath, "config.xml"),
275 Path.Combine (".", "mconfig.xml"),
276 null
279 static CommandHandler[] commands = {
280 new CommandHandler (new string[] {"addfeature", "af"}, HandleAddFeature),
281 new CommandHandler (new string[] {"defconfig", "dc"}, HandleDefaultConfig)
284 static string ConfigPath {
285 get {
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)
297 if (name == command)
298 return ch.Handler;
301 return null;
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");
309 return;
312 foreach (string item in list)
313 Console.WriteLine (" {0}", item);
316 static void PrintException (Exception ex, string format, params object[] parms)
318 if (ex == null)
319 return;
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 ();
335 try {
336 config.Load (configPaths);
337 } catch (Exception ex) {
338 PrintException (ex, "Failed to load configuration files:");
339 return 1;
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);
348 return 1;
351 HandleCommand commandHandler = FindCommandHandler (commandArguments [0]);
352 if (commandHandler == null) {
353 Console.Error.WriteLine ("Unknown command '{0}'", commandArguments [0]);
354 return 1;
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);
370 switch (cki.Key) {
371 case ConsoleKey.N:
372 e.Overwrite = false;
373 break;
375 case ConsoleKey.Y:
376 e.Overwrite = true;
377 break;
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.");
387 return 1;
390 FeatureTarget target = options.Target;
391 string featureName = commandArguments [1], configPath;
392 if (commandArguments.Length > 2)
393 configPath = commandArguments [2];
394 else {
395 switch (target) {
396 case FeatureTarget.Any:
397 Console.Error.WriteLine ("No default config file for target 'Any'");
398 return 1;
400 case FeatureTarget.Web:
401 configPath = "Web.config";
402 break;
404 case FeatureTarget.Application:
405 configPath = "application.exe.config";
406 break;
408 default:
409 Console.Error.WriteLine ("Unknown target '{0}'", target);
410 return 1;
414 try {
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);
419 return 1;
422 return 0;
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) {
432 switch (target) {
433 case FeatureTarget.Any:
434 Console.Error.WriteLine ("No default config file for target 'Any'");
435 return 1;
437 case FeatureTarget.Web:
438 configName = "Web.config";
439 break;
441 case FeatureTarget.Application:
442 configName = "application.exe.config";
443 break;
445 default:
446 Console.Error.WriteLine ("Unknown target '{0}'", target);
447 return 1;
449 } else
450 configName = commandArguments [1];
452 if (commandArguments.Length < 3)
453 targetPath = ".";
454 else
455 targetPath = commandArguments [2];
457 try {
458 config.WriteDefaultConfigFile (configName, targetPath, target);
459 } catch (Exception ex) {
460 PrintException (ex, "Failed to write default config file '{0}':",
461 configName);
462 return 1;
465 return 0;