+2007-11-10 Marek Habersack <mhabersack@novell.com>
+
+ * Mono.MonoConfig/Helpers.cs: added a method for breaking long
+ text lines to fit them within the console window.
+
+ * Mono.MonoConfig/FeatureNode.cs: added support for feature
+ actions.
+
+ * Mono.MonoConfig/FeatureNodeHandler.cs: added support for feature
+ actions.
+
+ * Mono.MonoConfig/FeatureAction.cs: added
+
+ * mconfig.exe.sources: added Mono.MonoConfig/FeatureAction.cs
+
2007-11-09 Marek Habersack <mhabersack@novell.com>
* Mono.MonoConfig/FeatureNodeHandler.cs: added support for feature
public void ReadConfiguration (XPathNavigator nav)
{
name = Helpers.GetRequiredNonEmptyAttribute (nav, "name");
- target = Helpers.ConvertTarget (Helpers.GetRequiredNonEmptyAttribute (nav, "target"));
+ target = Helpers.ConvertEnum <FeatureTarget> (Helpers.GetRequiredNonEmptyAttribute (nav, "target"), "target");
fileName = Helpers.GetOptionalAttribute (nav, "fileName");
if (String.IsNullOrEmpty (fileName))
public void ReadConfiguration (XPathNavigator nav)
{
section = Helpers.GetRequiredNonEmptyAttribute (nav, "section");
- target = Helpers.ConvertTarget (Helpers.GetRequiredNonEmptyAttribute (nav, "target"));
+ target = Helpers.ConvertEnum <FeatureTarget> (Helpers.GetRequiredNonEmptyAttribute (nav, "target"), "target");
XPathNodeIterator iter = nav.Select ("./text()");
StringBuilder sb = new StringBuilder ();
--- /dev/null
+//
+// Authors:
+// Marek Habersack (mhabersack@novell.com)
+//
+// (C) 2007 Novell, Inc
+//
+
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Diagnostics;
+using System.IO;
+using System.Text;
+using System.Xml;
+using System.Xml.XPath;
+
+namespace Mono.MonoConfig
+{
+ public enum ActionType
+ {
+ Message,
+ ShellScript,
+ Exec
+ }
+
+ public enum ActionWhen
+ {
+ Before,
+ After
+ }
+
+ public class FeatureAction
+ {
+ ActionType type;
+ ActionWhen when;
+ string command;
+ string commandArguments;
+ string message;
+ string script;
+
+ public ActionWhen When {
+ get { return when; }
+ }
+
+ public FeatureAction (XPathNavigator nav)
+ {
+ string val = Helpers.GetRequiredNonEmptyAttribute (nav, "type");
+ type = Helpers.ConvertEnum <ActionType> (val, "type");
+
+ val = Helpers.GetRequiredNonEmptyAttribute (nav, "when");
+ when = Helpers.ConvertEnum <ActionWhen> (val, "when");
+
+ XPathNodeIterator iter;
+ StringBuilder sb = new StringBuilder ();
+
+ switch (type) {
+ case ActionType.Message:
+ case ActionType.ShellScript:
+ iter = nav.Select ("./text()");
+ while (iter.MoveNext ())
+ sb.Append (iter.Current.Value);
+ if (type == ActionType.Message)
+ message = sb.ToString ();
+ else
+ script = sb.ToString ();
+ break;
+
+ case ActionType.Exec:
+ command = Helpers.GetRequiredNonEmptyAttribute (nav, "command");
+ commandArguments = Helpers.GetOptionalAttribute (nav, "commndArguments");
+ break;
+ }
+ }
+
+ public void Execute ()
+ {
+ switch (type) {
+ case ActionType.Message:
+ ExecuteMessage ();
+ break;
+
+ case ActionType.ShellScript:
+ ExecuteShellScript ();
+ break;
+
+ case ActionType.Exec:
+ ExecuteExec ();
+ break;
+ }
+ }
+
+ void ExecuteMessage ()
+ {
+ if (String.IsNullOrEmpty (message))
+ return;
+
+ string[] lines = message.Split ('\n');
+ string line;
+ int maxLineWidth = Console.WindowWidth;
+ StringBuilder sb = new StringBuilder ();
+
+ foreach (string l in lines) {
+ if (l.Length == 0) {
+ sb.Append ("\n");
+ continue;
+ }
+
+ line = l.Trim ();
+ if (line.Length > maxLineWidth)
+ sb.AppendFormat ("{0}\n", Helpers.BreakLongLine (line, String.Empty, maxLineWidth));
+ else
+ sb.AppendFormat ("{0}{1}\n", String.Empty, line);
+ }
+ Console.WriteLine (sb.ToString ());
+ }
+
+ void ExecuteShellScript ()
+ {
+ if (String.IsNullOrEmpty (script))
+ return;
+
+ string script_temp = Path.GetTempFileName ();
+ StreamWriter s = null;
+ try {
+ s = new StreamWriter (script_temp);
+ s.Write (script);
+
+ Process p = new Process ();
+ ProcessStartInfo pinfo = p.StartInfo;
+
+ pinfo.UseShellExecute = false;
+ pinfo.RedirectStandardOutput = true;
+ pinfo.RedirectStandardError = true;
+ pinfo.FileName = "/bin/bash";
+ pinfo.Arguments = script_temp;
+ p.Start ();
+
+ string stdout = p.StandardOutput.ReadToEnd ();
+ string stderr = p.StandardError.ReadToEnd ();
+ p.WaitForExit ();
+
+ if (p.ExitCode != 0) {
+ Console.Error.Write (stderr);
+ throw new ApplicationException (
+ String.Format ("Script signalled failure code: {0}", p.ExitCode));
+ }
+
+ Console.Write (stdout);
+ p.Close ();
+ } catch (Exception ex) {
+ Console.WriteLine (ex);
+ throw new ApplicationException ("Error executing feature shell action.", ex);
+ } finally {
+ if (s != null)
+ s.Close ();
+ try {
+ File.Delete (script_temp);
+ } catch (Exception) {
+ // ignore
+ }
+ }
+ }
+
+ void ExecuteExec ()
+ {
+ }
+ }
+}
//
using System;
using System.Collections.Generic;
-using System.IO;
namespace Mono.MonoConfig
{
public class FeatureNode
{
List <FeatureBlock> blocks;
+ List <FeatureAction> actionsBefore;
+ List <FeatureAction> actionsAfter;
string description;
-
+
public List <FeatureBlock> Blocks {
get {
if (blocks != null)
return String.Empty;
}
}
+
+ public List <FeatureAction> ActionsBefore {
+ get { return actionsBefore; }
+ }
+
+ public List <FeatureAction> ActionsAfter {
+ get { return actionsAfter; }
+ }
- public FeatureNode (List <FeatureBlock> blocks, string description)
+ public FeatureNode (List <FeatureBlock> blocks, string description,
+ List <FeatureAction> actionsBefore, List <FeatureAction> actionsAfter)
{
this.blocks = blocks;
this.description = description;
+ this.actionsBefore = actionsBefore;
+ this.actionsAfter = actionsAfter;
}
}
}
string name;
FeatureTarget target;
List <FeatureBlock> blocks;
+ List <FeatureAction> actionsBefore;
+ List <FeatureAction> actionsAfter;
Dictionary <string, FeatureNode> storage;
StringBuilder description;
public FeatureNodeHandler ()
{
blocks = new List <FeatureBlock> ();
+ actionsBefore = new List <FeatureAction> ();
+ actionsAfter = new List <FeatureAction> ();
description = new StringBuilder ();
}
public void ReadConfiguration (XPathNavigator nav)
{
name = Helpers.GetRequiredNonEmptyAttribute (nav, "name");
- target = Helpers.ConvertTarget (Helpers.GetRequiredNonEmptyAttribute (nav, "target"));
+ target = Helpers.ConvertEnum <FeatureTarget> (Helpers.GetRequiredNonEmptyAttribute (nav, "target"), "target");
XPathNodeIterator iter = nav.Select ("blocks/block[string-length (@name) > 0]");
while (iter.MoveNext ())
continue;
description.Append (val);
}
+
+ FeatureAction action;
+ iter = nav.Select ("actions/action[string-length (@type) > 0 and string-length (@when) > 0]");
+ while (iter.MoveNext ()) {
+ action = new FeatureAction (iter.Current);
+ switch (action.When) {
+ case ActionWhen.Before:
+ actionsBefore.Add (action);
+ break;
+
+ case ActionWhen.After:
+ actionsAfter.Add (action);
+ break;
+
+ default:
+ throw new ApplicationException (
+ String.Format ("Unknown 'when' attribute: {0}", action.When));
+ }
+ }
}
public void StoreConfiguration ()
AssertStorage ();
List <FeatureBlock> blocksClone = new List <FeatureBlock> (blocks.Count);
+ List <FeatureAction> abc = new List <FeatureAction> (actionsBefore.Count);
+ List <FeatureAction> aac = new List <FeatureAction> (actionsAfter.Count);
+
blocksClone.AddRange (blocks);
- FeatureNode fn = new FeatureNode (blocksClone, description.ToString ());
+ abc.AddRange (actionsBefore);
+ aac.AddRange (actionsAfter);
+ FeatureNode fn = new FeatureNode (blocksClone, description.ToString (), abc, aac);
if (storage.ContainsKey (name))
storage [name] = fn; // allow for silent override
storage.Add (name, fn);
blocks.Clear ();
+ actionsBefore.Clear ();
+ actionsAfter.Clear ();
description.Length = 0;
}
StringBuilder ret = new StringBuilder ();
ret.AppendFormat ("{0} (Target: {1})", name, lfb [0].Target);
+ List <FeatureAction> al = fn.ActionsBefore;
+ if (al != null && al.Count > 0)
+ ret.AppendFormat ("; {0} actions before", al.Count);
+
+ al = fn.ActionsAfter;
+ if (al != null && al.Count > 0)
+ ret.AppendFormat ("; {0} actions after", al.Count);
+
+ ret.Append ("\n");
+
string desc = fn.Description;
if (String.IsNullOrEmpty (desc))
return ret.ToString ();
line = l.Trim ();
if (line.Length > maxLineWidth)
- ret.AppendFormat ("{0}\n", BreakLongLine (line, indent, maxLineWidth));
+ ret.AppendFormat ("{0}\n", Helpers.BreakLongLine (line, indent, maxLineWidth));
else
ret.AppendFormat ("{0}{1}\n", indent, line);
}
return ret.ToString ();
}
-
- string BreakLongLine (string line, string indent, int maxLineWidth)
- {
- StringBuilder sb = new StringBuilder ();
-
- int lineLen = line.Length;
- int segments = lineLen / maxLineWidth;
- int segmentStart = 0;
- int segmentLen = maxLineWidth - 1;
- int idx;
-
- while (segments-- >= 0) {
- idx = line.LastIndexOf (' ', segmentStart + segmentLen);
- if (idx > 0)
- segmentLen = idx - segmentStart;
- else
- idx = segmentLen - 1;
-
- sb.AppendFormat ("{0}{1}\n", indent, line.Substring (segmentStart, segmentLen));
- segmentStart = idx + 1;
- if (lineLen - segmentStart > maxLineWidth)
- segmentLen = maxLineWidth;
- else
- segmentLen = lineLen - segmentStart - 1;
- }
-
- return sb.ToString ();
- }
public bool HasFeature (string featureName)
{
List <FeatureBlock> blocks = fn.Blocks;
if (blocks == null || blocks.Count == 0)
throw new ApplicationException (String.Format ("Definition of feature '{0}' is empty", featureName));
-
+
+ RunActions (fn.ActionsBefore);
XmlDocument doc = new XmlDocument ();
if (File.Exists (configFilePath))
AddFeatureBlock (doc, block, target, defaults, configBlocks);
Helpers.SaveXml (doc, configFilePath);
+ RunActions (fn.ActionsAfter);
}
+ void RunActions (List <FeatureAction> actions)
+ {
+ if (actions == null || actions.Count == 0)
+ return;
+
+ foreach (FeatureAction action in actions) {
+ if (action == null)
+ continue;
+ action.Execute ();
+ }
+ }
+
void AddFeatureBlock (XmlDocument doc, FeatureBlock block, FeatureTarget target, IDefaultContainer[] defaults,
IConfigBlockContainer[] configBlocks)
{
{
public const string FakeRootName = "F_a_K_e_R_o_O_t_M_o_N_o_C_o_N_f_I_g_N_o_D_e";
- public static FeatureTarget ConvertTarget (string value)
+ public static EnumType ConvertEnum <EnumType> (string value, string attrName)
{
try {
- EnumConverter cvt = new EnumConverter (typeof (FeatureTarget));
- return (FeatureTarget) cvt.ConvertFromInvariantString (value);
+ EnumConverter cvt = new EnumConverter (typeof (EnumType));
+ return (EnumType) cvt.ConvertFromInvariantString (value);
} catch (Exception) {
throw new ApplicationException (
- String.Format ("Failed to parse the 'target' attribute '{0}'", value));
+ String.Format ("Failed to parse the '{0}' attribute '{1}'", attrName, value));
}
}
+
+ public static string BreakLongLine (string line, string indent, int maxLineWidth)
+ {
+ StringBuilder sb = new StringBuilder ();
+
+ int lineLen = line.Length;
+ int segments = lineLen / maxLineWidth;
+ int segmentStart = 0;
+ int segmentLen = maxLineWidth - 1;
+ int idx;
+
+ while (segments-- >= 0) {
+ idx = line.LastIndexOf (' ', segmentStart + segmentLen);
+ if (idx > 0)
+ segmentLen = idx - segmentStart;
+ else
+ idx = segmentLen - 1;
+
+ sb.AppendFormat ("{0}{1}\n", indent, line.Substring (segmentStart, segmentLen));
+ segmentStart = idx + 1;
+ if (lineLen - segmentStart > maxLineWidth)
+ segmentLen = maxLineWidth;
+ else
+ segmentLen = lineLen - segmentStart - 1;
+ }
+
+ return sb.ToString ();
+ }
public static string GetRequiredNonEmptyAttribute (XPathNavigator node, string name)
{
RequiredParameterMissing (argName);
try {
- Target = Helpers.ConvertTarget (argParam);
+ Target = Helpers.ConvertEnum <FeatureTarget> (argParam, "target");
} catch (Exception ex) {
OptionParameterError (argName, ex.Message);
}
Mono.MonoConfig/Configuration.cs
Mono.MonoConfig/DefaultConfigFileNodeHandler.cs
Mono.MonoConfig/DefaultNodeHandler.cs
+Mono.MonoConfig/FeatureAction.cs
Mono.MonoConfig/FeatureBlock.cs
Mono.MonoConfig/FeatureNode.cs
Mono.MonoConfig/FeatureNodeHandler.cs