PageRenderTime 151ms CodeModel.GetById 116ms app.highlight 21ms RepoModel.GetById 8ms app.codeStats 0ms

/Aurora/Framework/Configuration/ConfigurationLoader.cs

https://bitbucket.org/VirtualReality/software-testing
C# | 538 lines | 413 code | 51 blank | 74 comment | 92 complexity | 563da387c33f4700b41128c550ed8a61 MD5 | raw file
  1/*
  2 * Copyright (c) Contributors, http://aurora-sim.org/, http://opensimulator.org/
  3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
  4 *
  5 * Redistribution and use in source and binary forms, with or without
  6 * modification, are permitted provided that the following conditions are met:
  7 *     * Redistributions of source code must retain the above copyright
  8 *       notice, this list of conditions and the following disclaimer.
  9 *     * Redistributions in binary form must reproduce the above copyright
 10 *       notice, this list of conditions and the following disclaimer in the
 11 *       documentation and/or other materials provided with the distribution.
 12 *     * Neither the name of the Aurora-Sim Project nor the
 13 *       names of its contributors may be used to endorse or promote products
 14 *       derived from this software without specific prior written permission.
 15 *
 16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
 17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
 20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 26 */
 27
 28using System;
 29using System.Collections.Generic;
 30using System.IO;
 31using System.Linq;
 32using Nini.Config;
 33using Nini.Ini;
 34
 35namespace Aurora.Framework
 36{
 37    /// <summary>
 38    ///   Loads the Configuration files into nIni
 39    /// </summary>
 40    public class ConfigurationLoader
 41    {
 42        public string defaultIniFile = "Aurora.ini";
 43
 44        public string iniFilePath = "";
 45
 46        /// <summary>
 47        ///   Should we save all merging of the .ini files to the filesystem?
 48        /// </summary>
 49        protected bool inidbg;
 50
 51        public Dictionary<string, string> m_defines = new Dictionary<string, string>();
 52
 53        /// <summary>
 54        ///   Should we show all the loading of the config files?
 55        /// </summary>
 56        protected bool showIniLoading;
 57
 58        /// <summary>
 59        ///   Loads the region configuration
 60        /// </summary>
 61        /// <param name = "argvSource">Parameters passed into the process when started</param>
 62        /// <returns>A configuration that gets passed to modules</returns>
 63        public IConfigSource LoadConfigSettings(IConfigSource argvSource)
 64        {
 65            iniFilePath = "";
 66            bool iniFileExists = false;
 67            bool oldoptions = false;
 68
 69            string mainIniDirectory = "";
 70            string mainIniFileName = defaultIniFile;
 71            string secondaryIniFileName = "";
 72
 73            List<string> sources = new List<string>();
 74            string basePath = Util.configDir();
 75
 76            if (argvSource != null)
 77            {
 78                IConfig startupConfig = argvSource.Configs["Startup"];
 79
 80
 81                oldoptions =
 82                    startupConfig.GetBoolean("oldoptions", false);
 83
 84                inidbg =
 85                    startupConfig.GetBoolean("inidbg", inidbg);
 86
 87                showIniLoading =
 88                    startupConfig.GetBoolean("inishowfileloading", showIniLoading);
 89
 90                if (oldoptions)
 91                {
 92                    string masterFileName =
 93                        startupConfig.GetString("inimaster", String.Empty);
 94
 95                    string iniGridName =
 96                        startupConfig.GetString("inigrid", String.Empty);
 97
 98                    if (iniGridName == string.Empty) //Read the old name then
 99                        iniGridName =
100                            startupConfig.GetString("inifile", String.Empty);
101
102                    string iniSimName =
103                        startupConfig.GetString("inisim", defaultIniFile);
104
105                    //Be mindful of these when modifying...
106                    //1) When file A includes file B, if the same directive is found in both, that the value in file B wins.
107                    //2) That inifile may be used with or without inimaster being used.
108                    //3) That any values for directives pulled in via inifile (Config Set 2) override directives of the same name found in the directive set (Config Set 1) created by reading in bin/Aurora.ini and its subsequently included files or that created by reading in whatever file inimaster points to and its subsequently included files.
109
110                    if (IsUri(masterFileName))
111                    {
112                        if (!sources.Contains(masterFileName))
113                            sources.Add(masterFileName);
114                    }
115                    else
116                    {
117                        string masterFilePath = Util.BasePathCombine(masterFileName);
118
119                        if (masterFileName != String.Empty &&
120                            File.Exists(masterFilePath) &&
121                            (!sources.Contains(masterFilePath)))
122                            sources.Add(masterFilePath);
123                        if (iniGridName == "") //Then it doesn't exist and we need to set this
124                            iniFilePath = masterFilePath;
125                        if (iniSimName == "") //Then it doesn't exist and we need to set this
126                            iniFilePath = masterFilePath;
127                    }
128
129                    if (iniGridName != "")
130                    {
131                        if (IsUri(iniGridName))
132                        {
133                            if (!sources.Contains(iniGridName))
134                                sources.Add(iniGridName);
135                            iniFilePath = iniGridName;
136                        }
137                        else
138                        {
139                            iniFilePath = Util.BasePathCombine(iniGridName);
140
141                            if (File.Exists(iniFilePath))
142                            {
143                                if (!sources.Contains(iniFilePath))
144                                    sources.Add(iniFilePath);
145                            }
146                        }
147                    }
148
149                    if (iniSimName != "")
150                    {
151                        if (IsUri(iniSimName))
152                        {
153                            if (!sources.Contains(iniSimName))
154                                sources.Add(iniSimName);
155                            iniFilePath = iniSimName;
156                        }
157                        else
158                        {
159                            iniFilePath = Util.BasePathCombine(iniSimName);
160
161                            if (File.Exists(iniFilePath))
162                            {
163                                if (!sources.Contains(iniFilePath))
164                                    sources.Add(iniFilePath);
165                            }
166                        }
167                    }
168
169                    string iniDirName =
170                        startupConfig.GetString("inidirectory", "");
171
172                    if (iniDirName != "" && Directory.Exists(iniDirName))
173                    {
174                        Console.WriteLine(string.Format("Searching folder {0} for config ini files",
175                                         iniDirName));
176
177                        string[] fileEntries = Directory.GetFiles(iniDirName);
178#if (!ISWIN)
179                        foreach (string filePath in fileEntries)
180                        {
181                            string extension = Path.GetExtension(filePath);
182                            if (extension != null && extension.ToLower() == ".ini")
183                            {
184                                if (!sources.Contains(Path.Combine(iniDirName, filePath)))
185                                    sources.Add(Path.Combine(iniDirName, filePath));
186                            }
187                        }
188#else
189                    foreach (string filePath in fileEntries.Where(filePath =>
190                                                                      {
191                                                                          var extension = Path.GetExtension(filePath);
192                                                                          return extension != null && extension.ToLower() == ".ini";
193                                                                      }).Where(filePath => !sources.Contains(Path.Combine(iniDirName, filePath))))
194                    {
195                        sources.Add(Path.Combine(iniDirName, filePath));
196                    }
197#endif
198                    }
199                }
200                else
201                {
202                    mainIniDirectory = startupConfig.GetString("mainIniDirectory", "");
203                    mainIniFileName = startupConfig.GetString("mainIniFileName", defaultIniFile);
204                    secondaryIniFileName = startupConfig.GetString("secondaryIniFileName", "");
205                }
206            }
207
208            if (!oldoptions)
209            {
210                if (mainIniDirectory != "")
211                    basePath = mainIniDirectory;
212                if (mainIniFileName != "")
213                {
214                    if (IsUri(mainIniFileName))
215                    {
216                        if (!sources.Contains(mainIniFileName))
217                            sources.Add(mainIniFileName);
218                    }
219                    else
220                    {
221                        string mainIniFilePath = Path.Combine(mainIniDirectory, mainIniFileName);
222                        if (!sources.Contains(mainIniFilePath))
223                            sources.Add(mainIniFilePath);
224                    }
225                }
226
227                if (secondaryIniFileName != "")
228                {
229                    if (IsUri(secondaryIniFileName))
230                    {
231                        if (!sources.Contains(secondaryIniFileName))
232                            sources.Add(secondaryIniFileName);
233                    }
234                    else
235                    {
236                        string secondaryIniFilePath = Path.Combine(mainIniDirectory, secondaryIniFileName);
237                        if (!sources.Contains(secondaryIniFilePath))
238                            sources.Add(secondaryIniFilePath);
239                    }
240                }
241            }
242
243            IConfigSource m_config = new IniConfigSource();
244            IConfigSource m_fakeconfig = new IniConfigSource();
245
246            //Console.WriteLine(string.Format("[Config]: Reading configuration settings"));
247
248            if (sources.Count == 0)
249            {
250                Console.WriteLine(string.Format("[CONFIG]: Could not load any configuration"));
251                Console.WriteLine(string.Format("[CONFIG]: Did you copy the " + defaultIniFile + ".example file to " + defaultIniFile +
252                                  "?"));
253                throw new NotSupportedException();
254            }
255
256            List<string> triedPaths = new List<string>();
257            for (int i = 0; i < sources.Count; i++)
258            {
259                //Read all non .example files first, then read all the example ones
260
261                if (File.Exists(sources[i]) &&
262                    ReadConfig(sources[i], i, m_fakeconfig))
263                    iniFileExists = true;
264                else if (File.Exists(sources[i] + ".example") &&
265                         ReadConfig(sources[i] + ".example", i, m_fakeconfig))
266                    iniFileExists = true;
267                AddIncludes(sources, basePath, ref i, ref triedPaths, m_fakeconfig);
268            }
269
270            //
271            sources.Reverse();
272            for (int i = 0; i < sources.Count; i++)
273            {
274                //Read all non .example files first, then read all the example ones
275
276                if (File.Exists(sources[i]))
277                    ReadConfig(sources[i], i, m_config);
278                else if (File.Exists(sources[i] + ".example"))
279                    ReadConfig(sources[i] + ".example", i, m_config);
280            }
281
282            FixDefines(ref m_config);
283
284            if (!iniFileExists)
285            {
286                Console.WriteLine(string.Format("[CONFIG]: Could not load any configuration"));
287                Console.WriteLine(string.Format("[CONFIG]: Configuration exists, but there was an error loading it!"));
288                throw new NotSupportedException();
289            }
290            // Make sure command line options take precedence
291            if(argvSource != null)
292                m_config.Merge(argvSource);
293
294            return m_config;
295        }
296
297        private void FixDefines(ref IConfigSource m_config)
298        {
299            if (m_defines.Count == 0)
300                return;
301
302            foreach (IConfig config in m_config.Configs)
303            {
304                int i = 0;
305                foreach (string value in config.GetValues())
306                {
307                    string value1 = value;
308                    foreach (string newValue in from def in m_defines.Keys where value1.Contains(def) select value1.Replace(def, m_defines[def]))
309                    {
310                        config.Set(config.GetKeys()[i], newValue);
311                    }
312                    i++;
313                }
314            }
315        }
316
317        /// <summary>
318        ///   Adds the included files as ini configuration files
319        /// </summary>
320        /// <param name = "sources">List of URL strings or filename strings</param>
321        /// <param name = "cntr">Where should we start inserting sources into the list?</param>
322        private void AddIncludes(List<string> sources, string basePath, ref int cntr, ref List<string> triedPaths,
323                                 IConfigSource configSource)
324        {
325            int cn = cntr;
326            //Where should we insert the sources into the list?
327            //loop over config sources
328            foreach (IConfig config in configSource.Configs)
329            {
330                // Look for Include-* in the key name
331                string[] keys = config.GetKeys();
332                foreach (string k in keys)
333                {
334                    if (k.StartsWith("Define-"))
335                    {
336                        if (!m_defines.ContainsKey(k.Remove(0, 7)))
337                            m_defines.Add(k.Remove(0, 7), config.GetString(k));
338                    }
339                    else if (k.StartsWith("Include-"))
340                    {
341                        // read the config file to be included.
342                        string file = config.GetString(k);
343                        if (triedPaths.Contains(file))
344                            continue;
345                        triedPaths.Add(file);
346                        if (IsUri(file))
347                        {
348                            if (!sources.Contains(file))
349                            {
350                                cn++;
351                                sources.Insert(cn, file);
352                            }
353                        }
354                        else
355                        {
356                            // Resolve relative paths with wildcards
357                            string chunkWithoutWildcards = file;
358                            string chunkWithWildcards = string.Empty;
359                            int wildcardIndex = file.IndexOfAny(new[] {'*', '?'});
360                            if (wildcardIndex != -1)
361                            {
362                                chunkWithoutWildcards = file.Substring(0, wildcardIndex);
363                                chunkWithWildcards = file.Substring(wildcardIndex);
364                            }
365                            string path = Path.Combine(basePath, chunkWithoutWildcards + chunkWithWildcards);
366                            List<string> paths = new List<string>(new string[1] {path});
367                            if (path.Contains("*"))
368                                if (path.Contains("*.ini"))
369                                {
370                                    paths.AddRange(Util.GetSubFiles(path));
371                                    List<string> examplefiles =
372                                        new List<string>(Util.GetSubFiles(path.Replace(".ini", ".ini.example")));
373#if (!ISWIN)
374                                    examplefiles.RemoveAll(delegate(string s)
375                                    {
376                                        return paths.Contains(s.Replace(".example", ""));
377                                    });
378#else
379                                    examplefiles.RemoveAll(
380                                        s => paths.Contains(s.Replace(".example", "")));
381#endif
382                                    paths.AddRange(examplefiles);
383                                }
384                                else
385                                    paths.AddRange(Util.GetSubFiles(path));
386#if (!ISWIN)
387                            foreach (string p in paths)
388                            {
389                                if (!sources.Contains(p))
390                                {
391                                    cn++;
392                                    sources.Insert(cn, p);
393                                }
394                            }
395#else
396                            foreach (string p in paths.Where(p => !sources.Contains(p)))
397                            {
398                                cn++;
399                                sources.Insert(cn, p);
400                            }
401#endif
402                        }
403                    }
404                    else if (k.StartsWith("RemoveInclude-"))
405                    {
406                        // read the config file to be included.
407                        string file = config.GetString(k);
408                        if (triedPaths.Contains(file))
409                            continue;
410                        triedPaths.Add(file);
411                        if (IsUri(file))
412                        {
413                            if (!sources.Contains(file))
414                            {
415                                cn--;
416                                sources.Remove(file);
417                            }
418                        }
419                        else
420                        {
421                            // Resolve relative paths with wildcards
422                            string chunkWithoutWildcards = file;
423                            string chunkWithWildcards = string.Empty;
424                            int wildcardIndex = file.IndexOfAny(new[] {'*', '?'});
425                            if (wildcardIndex != -1)
426                            {
427                                chunkWithoutWildcards = file.Substring(0, wildcardIndex);
428                                chunkWithWildcards = file.Substring(wildcardIndex);
429                            }
430                            string path = Path.Combine(basePath, chunkWithoutWildcards + chunkWithWildcards);
431                            string[] paths = new string[1] {path};
432                            if (path.Contains("*"))
433                                paths = Util.GetSubFiles(path);
434#if (!ISWIN)
435                            foreach (string p in paths)
436                            {
437                                if (!sources.Contains(p))
438                                {
439                                    cn--;
440                                    sources.Remove(p);
441                                }
442                            }
443#else
444                            foreach (string p in paths.Where(p => !sources.Contains(p)))
445                            {
446                                cn--;
447                                sources.Remove(p);
448                            }
449#endif
450                        }
451                    }
452                }
453            }
454        }
455
456        /// <summary>
457        ///   Check if we can convert the string to a URI
458        /// </summary>
459        /// <param name = "file">String uri to the remote resource</param>
460        /// <returns>true if we can convert the string to a Uri object</returns>
461        private bool IsUri(string file)
462        {
463            Uri configUri;
464
465            return Uri.TryCreate(file, UriKind.Absolute,
466                                 out configUri) && configUri.Scheme == Uri.UriSchemeHttp;
467        }
468
469        /// <summary>
470        ///   Provide same ini loader functionality for standard ini and master ini - file system or XML over http
471        /// </summary>
472        /// <param name = "iniPath">Full path to the ini</param>
473        /// <returns></returns>
474        private bool ReadConfig(string iniPath, int i, IConfigSource source)
475        {
476            bool success = false;
477
478            if (!IsUri(iniPath))
479            {
480                if (showIniLoading)
481                    Console.WriteLine(string.Format("[CONFIG]: Reading configuration file {0}", Util.BasePathCombine(iniPath)));
482
483                source.Merge(new IniConfigSource(iniPath, IniFileType.AuroraStyle));
484                if (inidbg)
485                {
486                    WriteConfigFile(i, source);
487                }
488                success = true;
489            }
490            else
491            {
492                // The ini file path is a http URI
493                // Try to read it
494                try
495                {
496                    string file = Utilities.ReadExternalWebsite(iniPath);
497                    string filename = Path.GetTempFileName();
498                    File.WriteAllText(filename, file);
499
500                    if (showIniLoading)
501                        Console.WriteLine(string.Format("[CONFIG]: Reading configuration file {0}", Util.BasePathCombine(iniPath)));
502
503                    source.Merge(new IniConfigSource(filename, IniFileType.AuroraStyle));
504                    if (inidbg)
505                    {
506                        WriteConfigFile(i, source);
507                    }
508                    File.Delete(filename);
509                    success = true;
510                }
511                catch (Exception e)
512                {
513                    Console.WriteLine(string.Format("[CONFIG]: Exception reading config from URI {0}\n" + e, iniPath));
514                    Environment.Exit(1);
515                }
516            }
517            return success;
518        }
519
520        private void WriteConfigFile(int i, IConfigSource m_config)
521        {
522            string m_fileName = "ConfigFileDump" + i + ".ini";
523            Console.WriteLine(string.Format("Writing config dump file to " + m_fileName));
524            try
525            {
526                //Add the user
527                FileStream stream = new FileStream(m_fileName, FileMode.Create);
528                StreamWriter m_streamWriter = new StreamWriter(stream);
529                m_streamWriter.BaseStream.Position += m_streamWriter.BaseStream.Length;
530                m_streamWriter.WriteLine(m_config.ToString());
531                m_streamWriter.Close();
532            }
533            catch
534            {
535            }
536        }
537    }
538}