示例#1
0
 public DefaultConfigFile(string name, string fileName, FeatureTarget target, Section sections)
 {
     this.name     = name;
     this.fileName = fileName;
     this.target   = target;
     this.sections = sections;
 }
        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);
        }
		public DefaultConfigFile (string name, string fileName, FeatureTarget target, Section sections)
		{
			this.name = name;
			this.fileName = fileName;
			this.target = target;
			this.sections = sections;
		}
示例#4
0
 public OverwriteFileEventArgs(string name, string path, FeatureTarget target, bool overwrite)
 {
     this.name      = name;
     this.path      = path;
     this.target    = target;
     this.overwrite = overwrite;
 }
        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);
        }
示例#6
0
        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);
            }
        }
        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);
        }
        static int HandleDefaultConfig(MConfigOptions options, Configuration config)
        {
            FeatureTarget target = options.Target;

            string[] commandArguments = options.PlainArguments;
            string   configName, targetPath;

            if (commandArguments.Length < 2)
            {
                switch (target)
                {
                case FeatureTarget.Any:
                    Console.Error.WriteLine("No default config file for target 'Any'");
                    return(1);

                case FeatureTarget.Web:
                    configName = "Web.config";
                    break;

                case FeatureTarget.Application:
                    configName = "application.exe.config";
                    break;

                default:
                    Console.Error.WriteLine("Unknown target '{0}'", target);
                    return(1);
                }
            }
            else
            {
                configName = commandArguments [1];
            }

            if (commandArguments.Length < 3)
            {
                targetPath = ".";
            }
            else
            {
                targetPath = commandArguments [2];
            }

            try
            {
                config.WriteDefaultConfigFile(configName, targetPath, target);
            }
            catch (Exception ex)
            {
                PrintException(ex, "Failed to write default config file '{0}':",
                               configName);
                return(1);
            }

            return(0);
        }
示例#9
0
        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);
        }
示例#10
0
		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 ();
		}
        static int HandleAddFeature(MConfigOptions options, Configuration config)
        {
            string[] commandArguments = options.PlainArguments;
            if (commandArguments.Length < 2)
            {
                Console.Error.WriteLine("Command requires at least one argument.");
                return(1);
            }

            FeatureTarget target = options.Target;
            string        featureName = commandArguments [1], configPath;

            if (commandArguments.Length > 2)
            {
                configPath = commandArguments [2];
            }
            else
            {
                switch (target)
                {
                case FeatureTarget.Any:
                    Console.Error.WriteLine("No default config file for target 'Any'");
                    return(1);

                case FeatureTarget.Web:
                    configPath = "Web.config";
                    break;

                case FeatureTarget.Application:
                    configPath = "application.exe.config";
                    break;

                default:
                    Console.Error.WriteLine("Unknown target '{0}'", target);
                    return(1);
                }
            }

            try
            {
                config.AddFeature(configPath, target, featureName);
            }
            catch (Exception ex)
            {
                PrintException(ex, "Failed to add feature '{0}' to config file '{1}'.",
                               featureName, configPath);
                return(1);
            }

            return(0);
        }
示例#12
0
        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);
        }
示例#13
0
        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 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));
                }
            }
        }
示例#15
0
        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();
            }
        }
示例#16
0
        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));
            }
        }
示例#17
0
        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);
        }
示例#18
0
		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));
				}
			}
		}
示例#19
0
        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));
            }
        }
示例#20
0
		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;
		}
示例#21
0
		public FeatureBlock (XPathNavigator node, FeatureTarget target)
		{
			this.name = Helpers.GetRequiredNonEmptyAttribute (node, "name");
			this.target = target;
		}
示例#22
0
 public DefaultNode(string contents, FeatureTarget target)
 {
     this.contents = contents;
     this.target   = target;
 }
 public FeatureBlock (XPathNavigator node, FeatureTarget target)
 {
     this.name = Helpers.GetRequiredNonEmptyAttribute (node, "name");
     this.target = target;
 }
示例#24
0
		public DefaultNode (string contents, FeatureTarget target)
		{
			this.contents = contents;
			this.target = target;
		}
示例#25
0
		public OverwriteFileEventArgs (string name, string path, FeatureTarget target, bool overwrite)
		{
			this.name = name;
			this.path = path;
			this.target = target;
			this.overwrite = overwrite;
		}
示例#26
0
		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;
		}
示例#27
0
		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);
			}
		}
示例#28
0
		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);
		}
示例#29
0
		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);
		}
示例#30
0
		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);
		}
示例#31
0
        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);
        }
示例#32
0
        int ProcessArgument(int idx, string argument, string[] args, int argsLen)
        {
            int  argnameIdx = 1;
            bool haveMoreDashes = false, badArg = false;
            int  argumentLen = argument.Length;

            if (argumentLen < 2)
            {
                badArg = true;
            }

            haveMoreDashes = !badArg && (argument [1] == '-');

            if (argumentLen == 2 && haveMoreDashes)
            {
                badArg = true;
            }

            if (badArg)
            {
                Console.Error.WriteLine("Invalid argument: {0}", argument);
                Environment.Exit(1);
            }

            if (haveMoreDashes)
            {
                argnameIdx++;
            }

            int  paramPos  = argument.IndexOfAny(paramStartChars, argnameIdx);
            bool haveParam = true;

            if (paramPos == -1)
            {
                haveParam = false;
                paramPos  = argumentLen;
            }

            string argName  = argument.Substring(argnameIdx, paramPos - argnameIdx);
            string argParam = haveParam ? argument.Substring(paramPos + 1) : null;

            int ret = 0;

            if (!haveParam && haveMoreDashes)
            {
                idx++;
                if (idx < argsLen)
                {
                    argParam = args [idx];
                    ret++;
                    haveParam = true;
                }
            }

            switch (argName)
            {
            case "?":
            case "h":
            case "help":
                Usage();
                break;

            case "v":
            case "version":
                ShowVersion();
                break;

            case "t":
            case "target":
                if (!haveParam)
                {
                    RequiredParameterMissing(argName);
                }

                try {
                    Target = Helpers.ConvertEnum <FeatureTarget> (argParam, "target");
                } catch (Exception ex) {
                    OptionParameterError(argName, ex.Message);
                }
                break;

            default:
                unknown_arguments.Add(argName, argParam);
                break;
            }

            return(ret);
        }
示例#33
0
		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);
		}
示例#34
0
		int ProcessArgument (int idx, string argument, string[] args, int argsLen)
		{
			int argnameIdx = 1;
			bool haveMoreDashes = false, badArg = false;
			int argumentLen = argument.Length;

			if (argumentLen < 2)
				badArg = true;
			
			haveMoreDashes = !badArg && (argument [1] == '-');
			
			if (argumentLen == 2 && haveMoreDashes)
				badArg = true;
			
			if (badArg) {
				Console.Error.WriteLine ("Invalid argument: {0}", argument);
				Environment.Exit (1);
			}

			if (haveMoreDashes)
				argnameIdx++;

			int paramPos = argument.IndexOfAny (paramStartChars, argnameIdx);
			bool haveParam = true;
			
			if (paramPos == -1) {
				haveParam = false;
				paramPos = argumentLen;
			}
			
			string argName = argument.Substring (argnameIdx, paramPos - argnameIdx);
			string argParam = haveParam ? argument.Substring (paramPos + 1) : null;

			int ret = 0;
			
			if (!haveParam && haveMoreDashes) {
				idx++;
				if (idx < argsLen) {
					argParam = args [idx];
					ret++;
					haveParam = true;
				}
			}
			
			switch (argName) {
				case "?":
				case "h":
				case "help":
					Usage ();
					break;

				case "v":
				case "version":
					ShowVersion ();
					break;

				case "t":
				case "target":
					if (!haveParam)
						RequiredParameterMissing (argName);
					
					try {
						Target = Helpers.ConvertEnum <FeatureTarget> (argParam, "target");
					} catch (Exception ex) {
						OptionParameterError (argName, ex.Message);
					}
					break;

				default:
					unknown_arguments.Add (argName, argParam);
					break;
			}
			
			return ret;
		}
示例#35
0
		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);
		}