/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. using System;
  28. using System.Collections.Generic;
  29. using System.IO;
  30. using System.Linq;
  31. using Nini.Config;
  32. using Nini.Ini;
  33. namespace Aurora.Framework
  34. {
  35. /// <summary>
  36. /// Loads the Configuration files into nIni
  37. /// </summary>
  38. public class ConfigurationLoader
  39. {
  40. public string defaultIniFile = "Aurora.ini";
  41. public string iniFilePath = "";
  42. /// <summary>
  43. /// Should we save all merging of the .ini files to the filesystem?
  44. /// </summary>
  45. protected bool inidbg;
  46. public Dictionary<string, string> m_defines = new Dictionary<string, string>();
  47. /// <summary>
  48. /// Should we show all the loading of the config files?
  49. /// </summary>
  50. protected bool showIniLoading;
  51. /// <summary>
  52. /// Loads the region configuration
  53. /// </summary>
  54. /// <param name = "argvSource">Parameters passed into the process when started</param>
  55. /// <returns>A configuration that gets passed to modules</returns>
  56. public IConfigSource LoadConfigSettings(IConfigSource argvSource)
  57. {
  58. iniFilePath = "";
  59. bool iniFileExists = false;
  60. bool oldoptions = false;
  61. string mainIniDirectory = "";
  62. string mainIniFileName = defaultIniFile;
  63. string secondaryIniFileName = "";
  64. List<string> sources = new List<string>();
  65. string basePath = Util.configDir();
  66. if (argvSource != null)
  67. {
  68. IConfig startupConfig = argvSource.Configs["Startup"];
  69. oldoptions =
  70. startupConfig.GetBoolean("oldoptions", false);
  71. inidbg =
  72. startupConfig.GetBoolean("inidbg", inidbg);
  73. showIniLoading =
  74. startupConfig.GetBoolean("inishowfileloading", showIniLoading);
  75. if (oldoptions)
  76. {
  77. string masterFileName =
  78. startupConfig.GetString("inimaster", String.Empty);
  79. string iniGridName =
  80. startupConfig.GetString("inigrid", String.Empty);
  81. if (iniGridName == string.Empty) //Read the old name then
  82. iniGridName =
  83. startupConfig.GetString("inifile", String.Empty);
  84. string iniSimName =
  85. startupConfig.GetString("inisim", defaultIniFile);
  86. //Be mindful of these when modifying...
  87. //1) When file A includes file B, if the same directive is found in both, that the value in file B wins.
  88. //2) That inifile may be used with or without inimaster being used.
  89. //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.
  90. if (IsUri(masterFileName))
  91. {
  92. if (!sources.Contains(masterFileName))
  93. sources.Add(masterFileName);
  94. }
  95. else
  96. {
  97. string masterFilePath = Util.BasePathCombine(masterFileName);
  98. if (masterFileName != String.Empty &&
  99. File.Exists(masterFilePath) &&
  100. (!sources.Contains(masterFilePath)))
  101. sources.Add(masterFilePath);
  102. if (iniGridName == "") //Then it doesn't exist and we need to set this
  103. iniFilePath = masterFilePath;
  104. if (iniSimName == "") //Then it doesn't exist and we need to set this
  105. iniFilePath = masterFilePath;
  106. }
  107. if (iniGridName != "")
  108. {
  109. if (IsUri(iniGridName))
  110. {
  111. if (!sources.Contains(iniGridName))
  112. sources.Add(iniGridName);
  113. iniFilePath = iniGridName;
  114. }
  115. else
  116. {
  117. iniFilePath = Util.BasePathCombine(iniGridName);
  118. if (File.Exists(iniFilePath))
  119. {
  120. if (!sources.Contains(iniFilePath))
  121. sources.Add(iniFilePath);
  122. }
  123. }
  124. }
  125. if (iniSimName != "")
  126. {
  127. if (IsUri(iniSimName))
  128. {
  129. if (!sources.Contains(iniSimName))
  130. sources.Add(iniSimName);
  131. iniFilePath = iniSimName;
  132. }
  133. else
  134. {
  135. iniFilePath = Util.BasePathCombine(iniSimName);
  136. if (File.Exists(iniFilePath))
  137. {
  138. if (!sources.Contains(iniFilePath))
  139. sources.Add(iniFilePath);
  140. }
  141. }
  142. }
  143. string iniDirName =
  144. startupConfig.GetString("inidirectory", "");
  145. if (iniDirName != "" && Directory.Exists(iniDirName))
  146. {
  147. Console.WriteLine(string.Format("Searching folder {0} for config ini files",
  148. iniDirName));
  149. string[] fileEntries = Directory.GetFiles(iniDirName);
  150. #if (!ISWIN)
  151. foreach (string filePath in fileEntries)
  152. {
  153. string extension = Path.GetExtension(filePath);
  154. if (extension != null && extension.ToLower() == ".ini")
  155. {
  156. if (!sources.Contains(Path.Combine(iniDirName, filePath)))
  157. sources.Add(Path.Combine(iniDirName, filePath));
  158. }
  159. }
  160. #else
  161. foreach (string filePath in fileEntries.Where(filePath =>
  162. {
  163. var extension = Path.GetExtension(filePath);
  164. return extension != null && extension.ToLower() == ".ini";
  165. }).Where(filePath => !sources.Contains(Path.Combine(iniDirName, filePath))))
  166. {
  167. sources.Add(Path.Combine(iniDirName, filePath));
  168. }
  169. #endif
  170. }
  171. }
  172. else
  173. {
  174. mainIniDirectory = startupConfig.GetString("mainIniDirectory", "");
  175. mainIniFileName = startupConfig.GetString("mainIniFileName", defaultIniFile);
  176. secondaryIniFileName = startupConfig.GetString("secondaryIniFileName", "");
  177. }
  178. }
  179. if (!oldoptions)
  180. {
  181. if (mainIniDirectory != "")
  182. basePath = mainIniDirectory;
  183. if (mainIniFileName != "")
  184. {
  185. if (IsUri(mainIniFileName))
  186. {
  187. if (!sources.Contains(mainIniFileName))
  188. sources.Add(mainIniFileName);
  189. }
  190. else
  191. {
  192. string mainIniFilePath = Path.Combine(mainIniDirectory, mainIniFileName);
  193. if (!sources.Contains(mainIniFilePath))
  194. sources.Add(mainIniFilePath);
  195. }
  196. }
  197. if (secondaryIniFileName != "")
  198. {
  199. if (IsUri(secondaryIniFileName))
  200. {
  201. if (!sources.Contains(secondaryIniFileName))
  202. sources.Add(secondaryIniFileName);
  203. }
  204. else
  205. {
  206. string secondaryIniFilePath = Path.Combine(mainIniDirectory, secondaryIniFileName);
  207. if (!sources.Contains(secondaryIniFilePath))
  208. sources.Add(secondaryIniFilePath);
  209. }
  210. }
  211. }
  212. IConfigSource m_config = new IniConfigSource();
  213. IConfigSource m_fakeconfig = new IniConfigSource();
  214. //Console.WriteLine(string.Format("[Config]: Reading configuration settings"));
  215. if (sources.Count == 0)
  216. {
  217. Console.WriteLine(string.Format("[CONFIG]: Could not load any configuration"));
  218. Console.WriteLine(string.Format("[CONFIG]: Did you copy the " + defaultIniFile + ".example file to " + defaultIniFile +
  219. "?"));
  220. throw new NotSupportedException();
  221. }
  222. List<string> triedPaths = new List<string>();
  223. for (int i = 0; i < sources.Count; i++)
  224. {
  225. //Read all non .example files first, then read all the example ones
  226. if (File.Exists(sources[i]) &&
  227. ReadConfig(sources[i], i, m_fakeconfig))
  228. iniFileExists = true;
  229. else if (File.Exists(sources[i] + ".example") &&
  230. ReadConfig(sources[i] + ".example", i, m_fakeconfig))
  231. iniFileExists = true;
  232. AddIncludes(sources, basePath, ref i, ref triedPaths, m_fakeconfig);
  233. }
  234. //
  235. sources.Reverse();
  236. for (int i = 0; i < sources.Count; i++)
  237. {
  238. //Read all non .example files first, then read all the example ones
  239. if (File.Exists(sources[i]))
  240. ReadConfig(sources[i], i, m_config);
  241. else if (File.Exists(sources[i] + ".example"))
  242. ReadConfig(sources[i] + ".example", i, m_config);
  243. }
  244. FixDefines(ref m_config);
  245. if (!iniFileExists)
  246. {
  247. Console.WriteLine(string.Format("[CONFIG]: Could not load any configuration"));
  248. Console.WriteLine(string.Format("[CONFIG]: Configuration exists, but there was an error loading it!"));
  249. throw new NotSupportedException();
  250. }
  251. // Make sure command line options take precedence
  252. if(argvSource != null)
  253. m_config.Merge(argvSource);
  254. return m_config;
  255. }
  256. private void FixDefines(ref IConfigSource m_config)
  257. {
  258. if (m_defines.Count == 0)
  259. return;
  260. foreach (IConfig config in m_config.Configs)
  261. {
  262. int i = 0;
  263. foreach (string value in config.GetValues())
  264. {
  265. string value1 = value;
  266. foreach (string newValue in from def in m_defines.Keys where value1.Contains(def) select value1.Replace(def, m_defines[def]))
  267. {
  268. config.Set(config.GetKeys()[i], newValue);
  269. }
  270. i++;
  271. }
  272. }
  273. }
  274. /// <summary>
  275. /// Adds the included files as ini configuration files
  276. /// </summary>
  277. /// <param name = "sources">List of URL strings or filename strings</param>
  278. /// <param name = "cntr">Where should we start inserting sources into the list?</param>
  279. private void AddIncludes(List<string> sources, string basePath, ref int cntr, ref List<string> triedPaths,
  280. IConfigSource configSource)
  281. {
  282. int cn = cntr;
  283. //Where should we insert the sources into the list?
  284. //loop over config sources
  285. foreach (IConfig config in configSource.Configs)
  286. {
  287. // Look for Include-* in the key name
  288. string[] keys = config.GetKeys();
  289. foreach (string k in keys)
  290. {
  291. if (k.StartsWith("Define-"))
  292. {
  293. if (!m_defines.ContainsKey(k.Remove(0, 7)))
  294. m_defines.Add(k.Remove(0, 7), config.GetString(k));
  295. }
  296. else if (k.StartsWith("Include-"))
  297. {
  298. // read the config file to be included.
  299. string file = config.GetString(k);
  300. if (triedPaths.Contains(file))
  301. continue;
  302. triedPaths.Add(file);
  303. if (IsUri(file))
  304. {
  305. if (!sources.Contains(file))
  306. {
  307. cn++;
  308. sources.Insert(cn, file);
  309. }
  310. }
  311. else
  312. {
  313. // Resolve relative paths with wildcards
  314. string chunkWithoutWildcards = file;
  315. string chunkWithWildcards = string.Empty;
  316. int wildcardIndex = file.IndexOfAny(new[] {'*', '?'});
  317. if (wildcardIndex != -1)
  318. {
  319. chunkWithoutWildcards = file.Substring(0, wildcardIndex);
  320. chunkWithWildcards = file.Substring(wildcardIndex);
  321. }
  322. string path = Path.Combine(basePath, chunkWithoutWildcards + chunkWithWildcards);
  323. List<string> paths = new List<string>(new string[1] {path});
  324. if (path.Contains("*"))
  325. if (path.Contains("*.ini"))
  326. {
  327. paths.AddRange(Util.GetSubFiles(path));
  328. List<string> examplefiles =
  329. new List<string>(Util.GetSubFiles(path.Replace(".ini", ".ini.example")));
  330. #if (!ISWIN)
  331. examplefiles.RemoveAll(delegate(string s)
  332. {
  333. return paths.Contains(s.Replace(".example", ""));
  334. });
  335. #else
  336. examplefiles.RemoveAll(
  337. s => paths.Contains(s.Replace(".example", "")));
  338. #endif
  339. paths.AddRange(examplefiles);
  340. }
  341. else
  342. paths.AddRange(Util.GetSubFiles(path));
  343. #if (!ISWIN)
  344. foreach (string p in paths)
  345. {
  346. if (!sources.Contains(p))
  347. {
  348. cn++;
  349. sources.Insert(cn, p);
  350. }
  351. }
  352. #else
  353. foreach (string p in paths.Where(p => !sources.Contains(p)))
  354. {
  355. cn++;
  356. sources.Insert(cn, p);
  357. }
  358. #endif
  359. }
  360. }
  361. else if (k.StartsWith("RemoveInclude-"))
  362. {
  363. // read the config file to be included.
  364. string file = config.GetString(k);
  365. if (triedPaths.Contains(file))
  366. continue;
  367. triedPaths.Add(file);
  368. if (IsUri(file))
  369. {
  370. if (!sources.Contains(file))
  371. {
  372. cn--;
  373. sources.Remove(file);
  374. }
  375. }
  376. else
  377. {
  378. // Resolve relative paths with wildcards
  379. string chunkWithoutWildcards = file;
  380. string chunkWithWildcards = string.Empty;
  381. int wildcardIndex = file.IndexOfAny(new[] {'*', '?'});
  382. if (wildcardIndex != -1)
  383. {
  384. chunkWithoutWildcards = file.Substring(0, wildcardIndex);
  385. chunkWithWildcards = file.Substring(wildcardIndex);
  386. }
  387. string path = Path.Combine(basePath, chunkWithoutWildcards + chunkWithWildcards);
  388. string[] paths = new string[1] {path};
  389. if (path.Contains("*"))
  390. paths = Util.GetSubFiles(path);
  391. #if (!ISWIN)
  392. foreach (string p in paths)
  393. {
  394. if (!sources.Contains(p))
  395. {
  396. cn--;
  397. sources.Remove(p);
  398. }
  399. }
  400. #else
  401. foreach (string p in paths.Where(p => !sources.Contains(p)))
  402. {
  403. cn--;
  404. sources.Remove(p);
  405. }
  406. #endif
  407. }
  408. }
  409. }
  410. }
  411. }
  412. /// <summary>
  413. /// Check if we can convert the string to a URI
  414. /// </summary>
  415. /// <param name = "file">String uri to the remote resource</param>
  416. /// <returns>true if we can convert the string to a Uri object</returns>
  417. private bool IsUri(string file)
  418. {
  419. Uri configUri;
  420. return Uri.TryCreate(file, UriKind.Absolute,
  421. out configUri) && configUri.Scheme == Uri.UriSchemeHttp;
  422. }
  423. /// <summary>
  424. /// Provide same ini loader functionality for standard ini and master ini - file system or XML over http
  425. /// </summary>
  426. /// <param name = "iniPath">Full path to the ini</param>
  427. /// <returns></returns>
  428. private bool ReadConfig(string iniPath, int i, IConfigSource source)
  429. {
  430. bool success = false;
  431. if (!IsUri(iniPath))
  432. {
  433. if (showIniLoading)
  434. Console.WriteLine(string.Format("[CONFIG]: Reading configuration file {0}", Util.BasePathCombine(iniPath)));
  435. source.Merge(new IniConfigSource(iniPath, IniFileType.AuroraStyle));
  436. if (inidbg)
  437. {
  438. WriteConfigFile(i, source);
  439. }
  440. success = true;
  441. }
  442. else
  443. {
  444. // The ini file path is a http URI
  445. // Try to read it
  446. try
  447. {
  448. string file = Utilities.ReadExternalWebsite(iniPath);
  449. string filename = Path.GetTempFileName();
  450. File.WriteAllText(filename, file);
  451. if (showIniLoading)
  452. Console.WriteLine(string.Format("[CONFIG]: Reading configuration file {0}", Util.BasePathCombine(iniPath)));
  453. source.Merge(new IniConfigSource(filename, IniFileType.AuroraStyle));
  454. if (inidbg)
  455. {
  456. WriteConfigFile(i, source);
  457. }
  458. File.Delete(filename);
  459. success = true;
  460. }
  461. catch (Exception e)
  462. {
  463. Console.WriteLine(string.Format("[CONFIG]: Exception reading config from URI {0}\n" + e, iniPath));
  464. Environment.Exit(1);
  465. }
  466. }
  467. return success;
  468. }
  469. private void WriteConfigFile(int i, IConfigSource m_config)
  470. {
  471. string m_fileName = "ConfigFileDump" + i + ".ini";
  472. Console.WriteLine(string.Format("Writing config dump file to " + m_fileName));
  473. try
  474. {
  475. //Add the user
  476. FileStream stream = new FileStream(m_fileName, FileMode.Create);
  477. StreamWriter m_streamWriter = new StreamWriter(stream);
  478. m_streamWriter.BaseStream.Position += m_streamWriter.BaseStream.Length;
  479. m_streamWriter.WriteLine(m_config.ToString());
  480. m_streamWriter.Close();
  481. }
  482. catch
  483. {
  484. }
  485. }
  486. }
  487. }