Imported Upstream version 3.6.0

Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
This commit is contained in:
Jo Shields
2014-08-13 10:39:27 +01:00
commit a575963da9
50588 changed files with 8155799 additions and 0 deletions

View File

@@ -0,0 +1,49 @@
//
// AssemblyInfo.cs
//
// Author:
// Marek Habersack <mhabersack@novell.com>
//
// (C) 2007 Marek Habersack
//
// 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.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
[assembly: AssemblyTitle ("Mono.MonoConfig")]
[assembly: AssemblyDescription ("Utility for modifying .NET configuration files")]
[assembly: AssemblyConfiguration ("Development version")]
[assembly: AssemblyProduct ("mconfig")]
[assembly: AssemblyCompany ("MONO development team")]
[assembly: AssemblyCopyright ("Copyright (c) 2007 Novell, Inc")]
[assembly: AssemblyCulture ("")]
[assembly: CLSCompliant (false)]
[assembly: ComVisible (false)]
[assembly: AssemblyVersion ("0.1.0.0")]
#if KEYFILE
[assembly: AssemblyKeyFile("../../mono.snk")]
#endif

View File

@@ -0,0 +1,59 @@
//
// 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.Xml;
using System.Xml.XPath;
namespace Mono.MonoConfig
{
public class ConfigBlockBlock
{
string name;
Section requires;
string contents;
public string Name {
get { return name; }
}
public Section Requires {
get { return requires; }
}
public string Contents {
get { return contents; }
}
public ConfigBlockBlock (string name, Section requires, string contents)
{
this.name = name;
this.requires = requires;
this.contents = contents;
}
}
}

View File

@@ -0,0 +1,97 @@
//
// 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.Text;
using System.Xml;
using System.Xml.XPath;
namespace Mono.MonoConfig
{
public class ConfigBlockNodeHandler : IDocumentNodeHandler, IStorageConsumer, IConfigBlockContainer
{
string name;
Section requirements;
string contents;
Dictionary <string, ConfigBlockBlock> storage;
public void ReadConfiguration (XPathNavigator nav)
{
name = Helpers.GetRequiredNonEmptyAttribute (nav, "name");
requirements = new Section ();
Helpers.BuildSectionTree (nav.Select ("requires/section[string-length(@name) > 0]"), requirements);
XPathNodeIterator iter = nav.Select ("contents/text()");
StringBuilder sb = new StringBuilder ();
while (iter.MoveNext ())
sb.Append (iter.Current.Value);
if (sb.Length > 0)
contents = sb.ToString ();
}
public void StoreConfiguration ()
{
AssertStorage ();
ConfigBlockBlock block = new ConfigBlockBlock (name, requirements, contents);
if (storage.ContainsKey (name))
storage [name] = block; // allow for silent override
else
storage.Add (name, block);
// Prepare to handle more sections
requirements = new Section ();
contents = null;
}
public void SetStorage (object storage)
{
this.storage = storage as Dictionary <string, ConfigBlockBlock>;
if (this.storage == null)
throw new ApplicationException ("Invalid storage type.");
}
public ConfigBlockBlock FindConfigBlock (string name)
{
AssertStorage ();
if (storage.ContainsKey (name))
return storage [name];
return null;
}
void AssertStorage ()
{
if (storage == null)
throw new ApplicationException ("No storage attached");
}
}
}

View File

@@ -0,0 +1,337 @@
//
// 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.Xml;
using System.Xml.XPath;
namespace Mono.MonoConfig
{
class HandlerDescription
{
Type handlerType;
Type handlerStorageType;
string section;
object handler;
object storage;
public object Handler {
get {
if (handler != null)
return handler;
handler = Activator.CreateInstance (handlerType);
return handler;
}
}
public object Storage {
get {
if (storage != null)
return storage;
storage = Activator.CreateInstance (handlerStorageType);
return storage;
}
}
public string Section {
get { return section; }
}
public bool Implements (string interfaceName)
{
return handlerType.GetInterface (interfaceName) != null;
}
public HandlerDescription (string handlerTypeName, string handlerStorageTypeName, string section)
{
handlerType = Type.GetType (handlerTypeName, true);
if (handlerType.GetInterface ("Mono.MonoConfig.IDocumentNodeHandler") == null)
throw new ApplicationException (
String.Format ("Handler for section '{0}' must implement the '{1}' interface",
section, typeof (Mono.MonoConfig.IDocumentNodeHandler)));
handlerStorageType = Type.GetType (handlerStorageTypeName, true);
this.section = section;
}
}
public class Configuration
{
string[] configs;
Dictionary <string, HandlerDescription> section_handlers;
List <HandlerDescription> section_handlers_ordered;
List <XPathDocument> config_documents;
bool loaded;
public Configuration () : this (null)
{}
public Configuration (string[] configs)
{
this.configs = configs;
section_handlers = new Dictionary <string, HandlerDescription> ();
section_handlers_ordered = new List <HandlerDescription> ();
config_documents = new List <XPathDocument> (configs != null ? configs.Length : 1);
}
public void WriteDefaultConfigFile (string name, string path, FeatureTarget target)
{
AssertLoaded ();
if (String.IsNullOrEmpty (name))
throw new ArgumentException ("name", "Must not be null or empty");
IDefaultConfigFileContainer[] containers = GetHandlersForInterface <IDefaultConfigFileContainer> ();
if (containers == null || containers.Length == 0)
throw new ApplicationException ("Cannot find any handler for writing default config files");
IDefaultContainer[] defaults = GetHandlersForInterface <IDefaultContainer> ();
bool written = false;
foreach (IDefaultConfigFileContainer container in containers) {
if (container.HasDefaultConfigFile (name, target)) {
container.WriteDefaultConfigFile (name, target, path, defaults);
written = true;
break;
}
}
if (!written)
throw new ApplicationException (
String.Format ("Definition of default config file '{0}' for target '{1}' not found.",
name, target));
}
public string[] DefaultConfigFiles {
get {
AssertLoaded ();
IDefaultConfigFileContainer[] containers = GetHandlersForInterface <IDefaultConfigFileContainer> ();
if (containers == null || containers.Length == 0)
return null;
List <string> defaults = new List <string> ();
foreach (IDefaultConfigFileContainer container in containers)
defaults.AddRange (container.DefaultConfigFiles);
defaults.Sort ();
return defaults.ToArray ();
}
}
public void AddFeature (string configFilePath, FeatureTarget target, string featureName)
{
AssertLoaded ();
if (String.IsNullOrEmpty (configFilePath))
throw new ArgumentException ("configFilePath", "Must not be null or empty");
if (String.IsNullOrEmpty (featureName))
throw new ArgumentException ("featureName", "Must not be null or empty");
IFeatureGenerator[] generators = GetHandlersForInterface <IFeatureGenerator> ();
if (generators == null || generators.Length == 0)
throw new ApplicationException ("Cannot find any feature generator");
IDefaultContainer[] defaults = GetHandlersForInterface <IDefaultContainer> ();
IConfigBlockContainer[] configBlocks = GetHandlersForInterface <IConfigBlockContainer> ();
bool added = false;
foreach (IFeatureGenerator generator in generators) {
if (generator.HasFeature (featureName)) {
generator.AddFeature (configFilePath, featureName, target, defaults, configBlocks);
added = true;
break;
}
}
if (!added)
throw new ApplicationException (
String.Format ("Definition of feature '{0}' for target '{1}' not found.",
featureName, target));
}
public string[] Features {
get {
AssertLoaded ();
IFeatureGenerator[] generators = GetHandlersForInterface <IFeatureGenerator> ();
if (generators == null || generators.Length == 0)
return null;
List <string> features = new List <string> ();
foreach (IFeatureGenerator generator in generators)
features.AddRange (generator.Features);
features.Sort ();
return features.ToArray ();
}
}
public void Load (string[] configs)
{
this.configs = configs;
Load ();
}
public void Load ()
{
if (configs == null || configs.Length == 0)
return;
if (loaded) {
section_handlers.Clear ();
section_handlers_ordered.Clear ();
config_documents.Clear ();
loaded = false;
}
XPathDocument doc;
foreach (string config in configs) {
if (String.IsNullOrEmpty (config))
continue;
try {
doc = new XPathDocument (config);
config_documents.Add (doc);
} catch (XmlException ex) {
throw new ApplicationException (
String.Format ("Failed to parse config file '{0}'.", config),
ex);
} catch (Exception) {
continue;
}
}
XPathNavigator nav;
XPathNodeIterator iter;
// First configure section handlers
List <HandlerDescription> handlers_from_file = new List <HandlerDescription> ();
foreach (XPathDocument xpdoc in config_documents) {
handlers_from_file.Clear ();
nav = xpdoc.CreateNavigator ();
iter = nav.Select ("//mconfig/configuration/handlers/handler[string-length (@section) > 0]");
while (iter.MoveNext ())
AddSectionHandler (iter.Current, handlers_from_file);
section_handlers_ordered.InsertRange (0, handlers_from_file);
}
// Process all configs looking for all sections with known handlers
foreach (XPathDocument xpdoc in config_documents) {
nav = xpdoc.CreateNavigator ();
iter = nav.Select ("//mconfig/*");
while (iter.MoveNext ())
HandleTopLevelNode (iter.Current);
}
loaded = true;
}
public T[] GetHandlersForInterface <T> ()
{
AssertLoaded ();
string typeName = typeof (T).ToString ();
object handler;
List <T> handlers = null;
foreach (HandlerDescription hd in section_handlers_ordered) {
if (hd.Implements (typeName)) {
if (handlers == null)
handlers = new List <T> (1);
handler = hd.Handler;
if (handler is IStorageConsumer)
((IStorageConsumer) handler).SetStorage (hd.Storage);
handlers.Add ((T)handler);
}
}
if (handlers == null)
return null;
return handlers.ToArray ();
}
void HandleTopLevelNode (XPathNavigator nav)
{
string section = nav.LocalName;
if (!section_handlers.ContainsKey (section))
return;
HandlerDescription hd = section_handlers [section];
if (hd == null)
return;
IDocumentNodeHandler handler = hd.Handler as IDocumentNodeHandler;
object storage = hd.Storage;
if (handler == null || storage == null)
return;
if (handler is IStorageConsumer)
((IStorageConsumer) handler).SetStorage (storage);
handler.ReadConfiguration (nav);
handler.StoreConfiguration ();
}
void AddSectionHandler (XPathNavigator nav, List <HandlerDescription> handlers)
{
string section = Helpers.GetRequiredNonEmptyAttribute (nav, "section");
HandlerDescription hd = new HandlerDescription (Helpers.GetRequiredNonEmptyAttribute (nav, "type"),
Helpers.GetRequiredNonEmptyAttribute (nav, "storageType"),
section);
if (section_handlers.ContainsKey (section)) {
HandlerDescription old = section_handlers [section];
section_handlers [section] = hd;
handlers.Remove (old);
handlers.Add (hd);
} else {
section_handlers.Add (section, hd);
handlers.Add (hd);
}
}
void AssertLoaded ()
{
if (!loaded)
throw new ApplicationException ("Configuration not loaded yet");
}
}
}

View File

@@ -0,0 +1,284 @@
//
// 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.IO;
using System.Text;
using System.Xml;
using System.Xml.XPath;
namespace Mono.MonoConfig
{
class DefaultConfigFile
{
string name;
string fileName;
FeatureTarget target;
Section sections;
public string Name {
get { return name; }
}
public string FileName {
get {
if (!String.IsNullOrEmpty (fileName))
return fileName;
return Name;
}
}
public FeatureTarget Target {
get { return target; }
}
public Section Sections {
get { return sections; }
}
public DefaultConfigFile (string name, string fileName, FeatureTarget target, Section sections)
{
this.name = name;
this.fileName = fileName;
this.target = target;
this.sections = sections;
}
}
public delegate void OverwriteFileEventHandler (object sender, OverwriteFileEventArgs e);
public sealed class OverwriteFileEventArgs : System.EventArgs
{
string name;
string path;
FeatureTarget target;
bool overwrite;
public string Name {
get { return name; }
}
public string Path {
get { return path; }
}
public FeatureTarget Target {
get { return target; }
}
public bool Overwrite {
get { return overwrite; }
set { overwrite = value; }
}
public OverwriteFileEventArgs (string name, string path, FeatureTarget target, bool overwrite)
{
this.name = name;
this.path = path;
this.target = target;
this.overwrite = overwrite;
}
}
public class DefaultConfigFileNodeHandler : IDocumentNodeHandler, IDefaultConfigFileContainer, IStorageConsumer
{
string name;
string fileName;
FeatureTarget target;
Section sections;
Dictionary <string, DefaultConfigFile> storage;
public event OverwriteFileEventHandler OverwriteFile;
public void ReadConfiguration (XPathNavigator nav)
{
name = Helpers.GetRequiredNonEmptyAttribute (nav, "name");
target = Helpers.ConvertEnum <FeatureTarget> (Helpers.GetRequiredNonEmptyAttribute (nav, "target"), "target");
fileName = Helpers.GetOptionalAttribute (nav, "fileName");
if (String.IsNullOrEmpty (fileName))
fileName = name;
sections = new Section ();
Helpers.BuildSectionTree (nav.Select ("./section[string-length (@name) > 0]"), sections);
}
public void StoreConfiguration ()
{
AssertStorage ();
DefaultConfigFile dcf = new DefaultConfigFile (name, fileName, target, sections);
if (storage.ContainsKey (name))
storage [name] = dcf;
else
storage.Add (name, dcf);
name = null;
fileName = null;
sections = null;
}
public void SetStorage (object storage)
{
this.storage = storage as Dictionary <string, DefaultConfigFile>;
if (this.storage == null)
throw new ApplicationException ("Invalid storage type");
}
public ICollection <string> DefaultConfigFiles {
get {
AssertStorage ();
if (storage.Count == 0)
return null;
List <string> ret = new List <string>(storage.Count);
DefaultConfigFile dcf;
foreach (KeyValuePair <string, DefaultConfigFile> kvp in storage) {
dcf = kvp.Value;
ret.Add (String.Format ("{0} (Target: {1}; Output file: {2})",
kvp.Key, dcf.Target, dcf.FileName));
}
return ret;
}
}
public bool HasDefaultConfigFile (string name, FeatureTarget target)
{
AssertStorage ();
if (storage.ContainsKey (name)) {
DefaultConfigFile dcf = storage [name];
if (dcf == null)
return false;
if (target != FeatureTarget.Any && dcf.Target != target)
return false;
return true;
}
return false;
}
public void WriteDefaultConfigFile (string name, FeatureTarget target, string path, IDefaultContainer[] defaults)
{
AssertStorage ();
DefaultConfigFile dcf;
if (!storage.ContainsKey (name) || (dcf = storage [name]) == null)
throw new ApplicationException (
String.Format ("Definition of the '{0}' default config file not found.", name));
if (target != FeatureTarget.Any && dcf.Target != target)
throw new ApplicationException (
String.Format ("Config file '{0}' can be generated only for the '{1}' target",
name, target));
string targetFile = Path.Combine (path, dcf.FileName);
if (File.Exists (targetFile)) {
OverwriteFileEventArgs args = new OverwriteFileEventArgs (
dcf.FileName,
path,
target,
true
);
OnOverwriteFile (args);
if (!args.Overwrite)
return;
}
try {
if (!Directory.Exists (path))
Directory.CreateDirectory (path);
} catch (Exception ex) {
throw new ApplicationException (
String.Format ("Could not create directory '{0}'", path),
ex);
}
XmlDocument doc = new XmlDocument ();
PopulateDocument (name, target, doc, dcf, defaults);
Helpers.SaveXml (doc, targetFile);
}
void OnOverwriteFile (OverwriteFileEventArgs args)
{
if (OverwriteFile == null)
return;
OverwriteFile (this, args);
}
void PopulateDocument (string name, FeatureTarget target, XmlDocument doc, DefaultConfigFile dcf,
IDefaultContainer[] defaults)
{
List <Section> children = dcf.Sections != null ? dcf.Sections.Children : null;
if (children == null || children.Count == 0)
return;
PopulateDocument (name, target, doc, doc, defaults, children);
}
void PopulateDocument (string name, FeatureTarget target, XmlDocument doc, XmlNode parent,
IDefaultContainer[] defaults, List <Section> children)
{
if (defaults == null || defaults.Length == 0)
return;
XmlNode node;
XmlDocument tmp;
foreach (Section s in children) {
tmp = Helpers.FindDefault (defaults, s.DefaultBlockName, target);
if (tmp == null)
continue;
node = doc.ImportNode (tmp.DocumentElement.FirstChild, true);
try {
PopulateDocument (name, target, doc, node, defaults, s.Children);
} catch (Exception ex) {
throw new ApplicationException (
String.Format ("Error building default config file '{0}'", name),
ex);
}
parent.AppendChild (node);
}
}
void AssertStorage ()
{
if (storage == null)
throw new ApplicationException ("No storage attached");
}
}
}

View File

@@ -0,0 +1,121 @@
//
// 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.Text;
using System.Xml;
using System.Xml.XPath;
namespace Mono.MonoConfig
{
class DefaultNode
{
string contents;
FeatureTarget target;
public string Contents {
get { return contents; }
}
public FeatureTarget Target {
get { return target; }
}
public DefaultNode (string contents, FeatureTarget target)
{
this.contents = contents;
this.target = target;
}
}
public class DefaultNodeHandler : IDocumentNodeHandler, IDefaultContainer, IStorageConsumer
{
string section;
string contents;
FeatureTarget target;
Dictionary <string, DefaultNode> storage;
public void ReadConfiguration (XPathNavigator nav)
{
section = Helpers.GetRequiredNonEmptyAttribute (nav, "section");
target = Helpers.ConvertEnum <FeatureTarget> (Helpers.GetRequiredNonEmptyAttribute (nav, "target"), "target");
XPathNodeIterator iter = nav.Select ("./text()");
StringBuilder sb = new StringBuilder ();
while (iter.MoveNext ())
sb.Append (iter.Current.Value);
if (sb.Length > 0)
contents = sb.ToString ();
}
public void StoreConfiguration ()
{
AssertStorage ();
DefaultNode dn = new DefaultNode (contents, target);
if (storage.ContainsKey (section))
storage [section] = dn;
else
storage.Add (section, dn);
section = null;
contents = null;
storage = null;
}
public string FindDefault (string sectionName, FeatureTarget target)
{
AssertStorage ();
if (storage.ContainsKey (sectionName)) {
DefaultNode dn = storage [sectionName];
if (target == FeatureTarget.Any || dn.Target == FeatureTarget.Any || dn.Target == target)
return dn.Contents;
}
return null;
}
public void SetStorage (object storage)
{
this.storage = storage as Dictionary <string, DefaultNode>;
if (this.storage == null)
throw new ApplicationException ("Invalid storage type");
}
void AssertStorage ()
{
if (storage == null)
throw new ApplicationException ("No storage attached");
}
}
}

View File

@@ -0,0 +1,219 @@
//
// 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);
s.Flush ();
s.Close ();
RunCommand ("/bin/sh", script_temp);
} catch (Exception ex) {
throw new ApplicationException ("Error executing feature 'shell script' action.", ex);
} finally {
if (s != null)
s.Close ();
try {
File.Delete (script_temp);
} catch (Exception) {
// ignore
}
}
}
void ExecuteExec ()
{
if (String.IsNullOrEmpty (command))
return;
try {
RunCommand (command, commandArguments);
} catch (Exception ex) {
throw new ApplicationException ("Error executing feature 'exec' action.", ex);
}
}
void RunCommand (string commandPath, string format, params object[] arguments)
{
if (String.IsNullOrEmpty (commandPath))
return;
string args;
if (!String.IsNullOrEmpty (format))
args = String.Format (format, arguments);
else
args = String.Empty;
Process p = null;
try {
p = new Process ();
ProcessStartInfo pinfo = p.StartInfo;
pinfo.UseShellExecute = false;
pinfo.RedirectStandardOutput = true;
pinfo.RedirectStandardError = true;
pinfo.FileName = commandPath;
pinfo.Arguments = args;
p.Start ();
string stdout = p.StandardOutput.ReadToEnd ();
string stderr = p.StandardError.ReadToEnd ();
p.WaitForExit ();
if (!String.IsNullOrEmpty (stdout))
Console.WriteLine (stdout);
if (!String.IsNullOrEmpty (stderr))
Console.Error.WriteLine (stderr);
int exitCode = p.ExitCode;
if (exitCode != 0)
throw new ApplicationException (
String.Format ("Process signalled failure code: {0}", exitCode));
} finally {
if (p != null)
p.Close ();
}
}
}
}

View File

@@ -0,0 +1,53 @@
//
// 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.Xml;
using System.Xml.XPath;
namespace Mono.MonoConfig
{
public class FeatureBlock
{
string name;
FeatureTarget target;
public string Name {
get { return name; }
}
public FeatureTarget Target {
get { return target; }
}
public FeatureBlock (XPathNavigator node, FeatureTarget target)
{
this.name = Helpers.GetRequiredNonEmptyAttribute (node, "name");
this.target = target;
}
}
}

View File

@@ -0,0 +1,75 @@
//
// 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;
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 blocks;
return new List <FeatureBlock> ();
}
}
public string Description {
get {
if (description != null)
return description;
return String.Empty;
}
}
public List <FeatureAction> ActionsBefore {
get { return actionsBefore; }
}
public List <FeatureAction> ActionsAfter {
get { return actionsAfter; }
}
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;
}
}
}

View File

@@ -0,0 +1,439 @@
//
// 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.IO;
using System.Text;
using System.Xml;
using System.Xml.XPath;
namespace Mono.MonoConfig
{
public class FeatureNodeHandler : IDocumentNodeHandler, IStorageConsumer, IFeatureGenerator
{
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.ConvertEnum <FeatureTarget> (Helpers.GetRequiredNonEmptyAttribute (nav, "target"), "target");
XPathNodeIterator iter = nav.Select ("blocks/block[string-length (@name) > 0]");
while (iter.MoveNext ())
blocks.Add (new FeatureBlock (iter.Current, target));
iter = nav.Select ("description/text()");
string val;
while (iter.MoveNext ()) {
val = iter.Current.Value;
if (String.IsNullOrEmpty (val))
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);
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
else
storage.Add (name, fn);
blocks.Clear ();
actionsBefore.Clear ();
actionsAfter.Clear ();
description.Length = 0;
}
public void SetStorage (object storage)
{
this.storage = storage as Dictionary <string, FeatureNode>;
if (this.storage == null)
throw new ApplicationException ("Invalid storage type");
}
public ICollection <string> Features {
get {
AssertStorage ();
if (storage.Count == 0)
return null;
List <string> ret = new List <string> (storage.Count);
string desc;
foreach (KeyValuePair <string, FeatureNode> kvp in storage) {
desc = FormatFeatureDescription (kvp.Key, kvp.Value);
if (String.IsNullOrEmpty (desc))
continue;
ret.Add (desc);
}
return ret;
}
}
string FormatFeatureDescription (string name, FeatureNode fn)
{
if (fn == null)
return null;
List <FeatureBlock> lfb = fn.Blocks;
if (lfb == null || lfb.Count == 0)
return null;
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 ();
string indent = " ";
int maxLineWidth = Console.WindowWidth - indent.Length;
string[] dlines = desc.Trim ().Split ('\n');
string line;
foreach (string l in dlines) {
if (l.Length == 0) {
ret.Append ("\n");
continue;
}
line = l.Trim ();
if (line.Length > maxLineWidth)
ret.AppendFormat ("{0}\n", Helpers.BreakLongLine (line, indent, maxLineWidth));
else
ret.AppendFormat ("{0}{1}\n", indent, line);
}
ret.Append ("\n");
return ret.ToString ();
}
public bool HasFeature (string featureName)
{
AssertStorage ();
if (!storage.ContainsKey (featureName))
return false;
FeatureNode fn = storage [featureName];
if (fn == null)
return false;
List <FeatureBlock> blocks = fn.Blocks;
if (blocks == null || blocks.Count == 0)
return false;
return true;
}
public void AddFeature (string configFilePath, string featureName, FeatureTarget target,
IDefaultContainer[] defaults, IConfigBlockContainer[] configBlocks)
{
AssertStorage ();
FeatureNode fn;
if (!storage.ContainsKey (featureName) || (fn = storage [featureName]) == null)
throw new ApplicationException (String.Format ("Missing definition of feature '{0}'", 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))
doc.Load (configFilePath);
foreach (FeatureBlock block in blocks)
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)
{
if (target != FeatureTarget.Any && block.Target != target)
return;
ConfigBlockBlock configBlock = Helpers.FindConfigBlock (configBlocks, block.Name);
if (configBlock == null)
throw new ApplicationException (String.Format ("Config block '{0}' cannot be found", block.Name));
XmlNode attachPoint = null;
ProcessSections (doc, doc, "/", configBlock.Requires, defaults, configBlock.Name, ref attachPoint);
if (attachPoint == null)
attachPoint = FindDefaultAttachPoint (doc, configBlock.Requires);
if (attachPoint == null)
throw new ApplicationException (
String.Format ("Missing attachment point for block '{0}'", configBlock.Name));
XmlDocument contents = new XmlDocument ();
contents.LoadXml (String.Format ("<{0}>{1}</{0}>", Helpers.FakeRootName, configBlock.Contents));
AddFeatureRecursively (doc, attachPoint, contents.DocumentElement);
}
// TODO: handle comment and text nodes to avoid their duplication
void AddFeatureRecursively (XmlDocument doc, XmlNode attachPoint, XmlNode top)
{
bool topIsFake = top.Name == Helpers.FakeRootName;
XmlNode parent = null;
string xpath;
if (top.NodeType == XmlNodeType.Element) {
xpath = BuildFeaturePath (attachPoint, topIsFake ? null : top);
parent = DocumentHasFeatureFragment (doc, top, xpath);
}
if (!topIsFake && parent == null) {
parent = doc.ImportNode (top, false);
attachPoint.AppendChild (parent);
if (parent.NodeType == XmlNodeType.Comment)
return;
}
if (top.HasChildNodes)
foreach (XmlNode node in top.ChildNodes)
AddFeatureRecursively (doc, topIsFake ? attachPoint : parent, node);
}
XmlNode FindDefaultAttachPoint (XmlDocument doc, Section req)
{
List <Section> children = req.Children;
if (children == null || children.Count == 0)
return null;
StringBuilder sb = new StringBuilder ("/");
BuildPathToLastRequirement (sb, children);
return doc.SelectSingleNode (sb.ToString ());
}
void BuildPathToLastRequirement (StringBuilder sb, List <Section> sections)
{
Section last = sections [sections.Count - 1];
sb.AppendFormat ("/{0}", last.Name);
List <Section> children = last.Children;
if (children == null || children.Count == 0)
return;
BuildPathToLastRequirement (sb, children);
}
XmlNode DocumentHasFeatureFragment (XmlDocument doc, XmlNode top, string xpath)
{
if (top.NodeType == XmlNodeType.Comment)
return null;
return doc.SelectSingleNode (xpath);
}
string BuildFeaturePath (XmlNode parent, XmlNode child)
{
if (parent == null)
return "/";
List <string> path = new List <string> ();
XmlNode cur = parent, last = null;
while (cur != null && cur.NodeType != XmlNodeType.Document) {
if (cur.NodeType == XmlNodeType.Element && cur.Name != Helpers.FakeRootName)
path.Insert (0, cur.Name);
last = cur;
cur = cur.ParentNode;
}
string attributes = null;
if (child != null && last.Name != child.Name) {
if (child.NodeType == XmlNodeType.Element)
path.Add (child.Name);
attributes = BuildXPathFromAttributes (child);
} else if (last != null)
attributes = BuildXPathFromAttributes (last);
path [path.Count - 1] += attributes;
path.Insert (0, "/");
return String.Join ("/", path.ToArray ());
}
string BuildXPathFromAttributes (XmlNode node)
{
XmlAttributeCollection attrs = node.Attributes;
StringBuilder sb = new StringBuilder ();
string and = String.Empty;
bool first = true;
foreach (XmlAttribute attr in attrs) {
sb.AppendFormat ("{0}@{1}=\"{2}\"",
and,
attr.Name,
attr.Value);
if (first) {
first = false;
and = " and ";
}
}
if (sb.Length == 0)
return String.Empty;
sb.Insert (0, "[");
sb.Append ("]");
return sb.ToString ();
}
void ProcessSections (XmlDocument doc, XmlNode parent, string topPath, Section top, IDefaultContainer[] defaults,
string blockName, ref XmlNode attachPoint)
{
List <Section> topChildren, children;
if (top == null || (topChildren = top.Children) == null)
return;
XmlNode node;
string curPath;
foreach (Section s in topChildren) {
curPath = String.Format ("{0}/{1}", topPath, s.Name);
node = FindNodeOrAddDefault (doc, s.DefaultBlockName, curPath, defaults);
if (node != null && s.AttachPoint) {
if (attachPoint != null)
throw new ApplicationException (
String.Format ("Config block '{0}' has more than one attachment point",
blockName));
attachPoint = node;
}
parent.AppendChild (node);
if ((children = s.Children) != null && children.Count > 0)
ProcessSections (doc, node, curPath, s, defaults, blockName, ref attachPoint);
}
return;
}
XmlNode FindNodeOrAddDefault (XmlDocument doc, string nodeName, string nodePath, IDefaultContainer[] defaults)
{
XmlNode ret = doc.SelectSingleNode (nodePath);
if (ret != null)
return ret;
XmlDocument defDoc = Helpers.FindDefault (defaults, nodeName, FeatureTarget.Any);
if (defDoc == null)
throw new ApplicationException (
String.Format ("Document doesn't contain node '{0}' and no default can be found",
nodePath));
return doc.ImportNode (defDoc.DocumentElement.FirstChild, true);
}
void AssertStorage ()
{
if (storage == null)
throw new ApplicationException ("No storage attached");
}
}
}

View File

@@ -0,0 +1,38 @@
//
// 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;
namespace Mono.MonoConfig
{
public enum FeatureTarget
{
Any,
Web,
Application
};
}

View File

@@ -0,0 +1,192 @@
//
// 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.Text;
using System.Xml;
using System.Xml.XPath;
namespace Mono.MonoConfig
{
public static class Helpers
{
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 EnumType ConvertEnum <EnumType> (string value, string attrName)
{
try {
EnumConverter cvt = new EnumConverter (typeof (EnumType));
return (EnumType) cvt.ConvertFromInvariantString (value);
} catch (Exception) {
throw new ApplicationException (
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)
{
string val = GetOptionalAttribute (node, name);
if (String.IsNullOrEmpty (val))
ThrowMissingRequiredAttribute (node, name);
return val;
}
public static string GetOptionalAttribute (XPathNavigator node, string name)
{
return node.GetAttribute (name, String.Empty);
}
static void ThrowMissingRequiredAttribute (XPathNavigator node, string name)
{
throw new ApplicationException (String.Format ("Element '{0}' is missing required attribute '{1}'",
node.LocalName, name));
}
public static void BuildSectionTree (XPathNodeIterator iter, Section section)
{
XPathNavigator nav, tmp;
XPathNodeIterator children;
List <Section> sectionChildren = section.Children;
Section newSection, curSection;
while (iter.MoveNext ()) {
nav = iter.Current;
children = nav.Select ("section[string-length(@name) > 0]");
curSection = new Section (nav);
while (children.MoveNext ()) {
tmp = children.Current;
newSection = new Section (tmp);
BuildSectionTree (tmp.Select ("section[string-length(@name) > 0]"), newSection);
curSection.Children.Add (newSection);
}
sectionChildren.Add (curSection);
}
}
public static XmlDocument FindDefault (IDefaultContainer[] defaults, string name, FeatureTarget target)
{
int len;
if (defaults == null || (len = defaults.Length) == 0)
return null;
IDefaultContainer cur;
string text = null;
for (int i = 0; i < len; i++) {
cur = defaults [i];
text = cur.FindDefault (name, target);
if (text != null)
break;
}
if (text == null)
return null;
XmlDocument ret = new XmlDocument ();
ret.LoadXml (String.Format ("<{0}>{1}</{0}>", FakeRootName, text));
return ret;
}
public static ConfigBlockBlock FindConfigBlock (IConfigBlockContainer[] configBlocks, string name)
{
int len;
if (configBlocks == null || (len = configBlocks.Length) == 0)
return null;
IConfigBlockContainer cur;
ConfigBlockBlock ret = null;
for (int i = 0; i < len; i++) {
cur = configBlocks [i];
ret = cur.FindConfigBlock (name);
if (ret != null)
break;
}
return ret;
}
public static void SaveXml (XmlDocument doc, string targetFile)
{
XmlWriterSettings settings = new XmlWriterSettings ();
settings.CloseOutput = true;
settings.CheckCharacters = true;
settings.Indent = true;
settings.Encoding = Encoding.UTF8;
settings.IndentChars = "\t";
settings.NewLineHandling = NewLineHandling.Replace;
XmlWriter writer = null;
try {
writer = XmlWriter.Create (targetFile, settings);
doc.Save (writer);
writer.Flush ();
} catch (Exception ex) {
throw new ApplicationException (
String.Format ("Failed to write XML file {1}", targetFile), ex);
} finally {
if (writer != null)
writer.Close ();
}
}
}
}

View File

@@ -0,0 +1,36 @@
//
// 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;
namespace Mono.MonoConfig
{
public interface IConfigBlockContainer
{
ConfigBlockBlock FindConfigBlock (string name);
}
}

View File

@@ -0,0 +1,43 @@
//
// 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;
namespace Mono.MonoConfig
{
public interface IDefaultConfigFileContainer
{
event OverwriteFileEventHandler OverwriteFile;
bool HasDefaultConfigFile (string name, FeatureTarget target);
void WriteDefaultConfigFile (string name, FeatureTarget target, string path, IDefaultContainer[] defaults);
ICollection <string> DefaultConfigFiles {
get;
}
}
}

View File

@@ -0,0 +1,36 @@
//
// 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;
namespace Mono.MonoConfig
{
public interface IDefaultContainer
{
string FindDefault (string sectionName, FeatureTarget target);
}
}

View File

@@ -0,0 +1,41 @@
//
// 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.ComponentModel;
using System.Collections.Generic;
using System.Xml;
using System.Xml.XPath;
namespace Mono.MonoConfig
{
public interface IDocumentNodeHandler
{
void ReadConfiguration (XPathNavigator nav);
void StoreConfiguration ();
}
}

View File

@@ -0,0 +1,42 @@
//
// 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;
namespace Mono.MonoConfig
{
public interface IFeatureGenerator
{
bool HasFeature (string featureName);
void AddFeature (string configFilePath, string featureName, FeatureTarget target,
IDefaultContainer[] defaults, IConfigBlockContainer[] configBlocks);
ICollection <string> Features {
get;
}
}
}

View File

@@ -0,0 +1,36 @@
//
// 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;
namespace Mono.MonoConfig
{
public interface IStorageConsumer
{
void SetStorage (object storage);
}
}

View File

@@ -0,0 +1,86 @@
//
// 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.Text;
using System.Xml;
using System.Xml.XPath;
namespace Mono.MonoConfig
{
public class Section
{
List <Section> children;
string name;
string defaultBlockName;
bool attachPoint;
public string Name {
get { return name; }
}
public string DefaultBlockName {
get {
if (String.IsNullOrEmpty (defaultBlockName))
return Name;
return defaultBlockName;
}
}
public List <Section> Children {
get {
if (children == null)
children = new List <Section> ();
return children;
}
}
public bool AttachPoint {
get { return attachPoint; }
}
public Section () : this (null)
{
}
public Section (XPathNavigator nav)
{
if (nav != null) {
name = Helpers.GetRequiredNonEmptyAttribute (nav, "name");
string val = Helpers.GetOptionalAttribute (nav, "attachPoint");
if (!String.IsNullOrEmpty (val))
attachPoint = true;
val = Helpers.GetOptionalAttribute (nav, "defaultBlockName");
if (!String.IsNullOrEmpty (val))
defaultBlockName = val;
}
}
}
}

View File

@@ -0,0 +1,43 @@
//
// 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.IO;
namespace Mono.MonoConfig
{
public class Constants
{
public static readonly string GlobalConfigPath;
static Constants ()
{
GlobalConfigPath = String.Format ("@MONO_SYSCONFDIR@{0}mono{0}mconfig{0}config.xml",
Path.DirectorySeparatorChar);
}
}
}