internal static SageContext InitializeConfiguration(SageContext context) { string projectConfigPathBinDir = Path.Combine(Project.AssemblyCodeBaseDirectory, ProjectConfiguration.ProjectConfigName); string projectConfigPathProjDir = Path.Combine(Project.AssemblyCodeBaseDirectory, "..\\" + ProjectConfiguration.ProjectConfigName); string projectConfigPath = projectConfigPathBinDir; if (File.Exists(projectConfigPathProjDir)) { projectConfigPath = projectConfigPathProjDir; } var projectConfig = ProjectConfiguration.Create(); if (!File.Exists(projectConfigPath)) { log.Warn("Project configuration file not found; configuration initialized with default values"); return new SageContext(context); } installOrder = new List<string>(); extensions = new OrderedDictionary<string, ExtensionInfo>(); if (File.Exists(projectConfigPath)) projectConfig.Parse(projectConfigPath); if (projectConfig.Locales.Count == 0) { var defaultLocale = new LocaleInfo(); projectConfig.Locales.Add(defaultLocale.Name, defaultLocale); } var result = projectConfig.ValidationResult; if (!result.Success) { initializationError = result.Exception; initializationProblemInfo = new ProblemInfo(ProblemType.ProjectSchemaValidationError, result.SourceFile); } else { configuration = projectConfig; // this will ensure the new context uses the just // created configuration immediately context = new SageContext(context); var extensionManager = new ExtensionManager(); try { extensionManager.Initialize(context); } catch (ProjectInitializationException ex) { initializationError = ex; initializationProblemInfo = new ProblemInfo(ex.Reason, ex.SourceFile); if (ex.Reason == ProblemType.MissingExtensionDependency) { initializationProblemInfo.InfoBlocks .Add("Dependencies", ex.Dependencies.ToDictionary(name => name)); } } if (initializationError == null) { var missingDependencies = projectConfig.Dependencies .Where(name => extensionManager.Count(ex => ex.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase)) == 0) .ToList(); var extraDependencies = extensionManager .Where(extension => projectConfig.Dependencies.Count(name => name.Equals(extension.Name, StringComparison.InvariantCultureIgnoreCase)) == 0) .ToList(); if (missingDependencies.Count != 0) { string errorMessage = string.Format("Project is missing one or more dependencies ({0}) - installation cancelled.", string.Join(", ", missingDependencies)); initializationError = new ProjectInitializationException(errorMessage); initializationProblemInfo = new ProblemInfo(ProblemType.MissingDependency); initializationProblemInfo.InfoBlocks .Add("Dependencies", missingDependencies.ToDictionary(name => name)); } if (extraDependencies.Count != 0) { log.WarnFormat("There are additional, unreferenced extensions in the extensions directory: {0}", string.Join(",", extraDependencies)); } foreach (var name in projectConfig.Dependencies) { var extension = extensionManager.First(ex => ex.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase)); installOrder.Add(extension.Config.Id); Project.RelevantAssemblies.AddRange(extension.Assemblies); projectConfig.RegisterExtension(extension.Config); extensions.Add(extension.Config.Id, extension); } // fire this event at the end rather than once for each extension var totalAssemblies = extensionManager.Sum(info => info.Assemblies.Count); if (totalAssemblies != 0) { if (Project.AssembliesUpdated != null) { log.DebugFormat("{0} extension assemblies loaded, triggering AssembliesUpdated event", totalAssemblies); Project.AssembliesUpdated(null, EventArgs.Empty); } } installOrder.Add(projectConfig.Id); projectConfig.RegisterRoutes(); context.LmCache.Put(ConfigWatchName, DateTime.Now, projectConfig.Files); } } return context; }
internal void Parse(XmlElement configNode) { Contract.Requires<ArgumentNullException>(configNode != null); this.ValidationResult = ResourceManager.ValidateElement(configNode, ConfigSchemaPath); if (!this.ValidationResult.Success) return; var nm = XmlNamespaces.Manager; var packageElement = configNode.SelectSingleNode("p:package", nm); this.Type = (ProjectType) Enum.Parse(typeof(ProjectType), configNode.Name, true); if (this.Type == ProjectType.Project && packageElement != null) { this.Type = ProjectType.ExtensionProject; } foreach (XmlElement child in configNode.SelectNodes( string.Format("*[namespace-uri() != '{0}']", XmlNamespaces.ProjectConfigurationNamespace))) { customElements.Add(child); } foreach (XmlElement element in configNode.SelectNodes("p:dependencies/p:extension", nm)) { string extensionName = element.GetAttribute("name"); if (!this.Dependencies.Contains(extensionName)) this.Dependencies.Add(extensionName); } XmlNode variablesNode = configNode.SelectSingleNode("p:variables", nm); if (variablesNode != null) { if (this.VariablesNode != null) { foreach (XmlElement variableNode in variablesNode.SelectNodes("*")) { var importReady = this.VariablesNode.OwnerDocument.ImportNode(variableNode, true); var id = variableNode.GetAttribute("id"); var current = this.VariablesNode.SelectSingleNode( string.Format("intl:variable[@id='{0}']", id), nm); if (current != null) this.VariablesNode.ReplaceChild(importReady, current); else this.VariablesNode.AppendChild(importReady); } } else { this.VariablesNode = variablesNode; } this.Variables = new Dictionary<string, NameValueCollection>(); var variables = variablesNode.SelectNodes("intl:variable", nm); foreach (XmlElement elem in variables) { var values = elem.SelectNodes("intl:value", nm); var valueDictionary = new NameValueCollection(); if (values.Count == 0) { valueDictionary["default"] = elem.InnerText; } else { foreach (XmlElement val in values) valueDictionary.Add(val.GetAttribute("locale"), val.InnerText.Trim()); } this.Variables[elem.GetAttribute("id")] = valueDictionary; } } XmlElement routingNode = configNode.SelectSingleElement("p:routing", nm); XmlElement pathsNode = configNode.SelectSingleElement("p:paths", nm); string nodeValue = configNode.GetAttribute("name"); if (!string.IsNullOrEmpty(nodeValue)) this.Name = nodeValue; nodeValue = configNode.GetAttribute("sharedCategory"); if (!string.IsNullOrEmpty(nodeValue)) this.SharedCategory = nodeValue; nodeValue = configNode.GetAttribute("defaultLocale"); if (!string.IsNullOrEmpty(nodeValue)) this.DefaultLocale = nodeValue; nodeValue = configNode.GetAttribute("defaultCategory"); if (!string.IsNullOrEmpty(nodeValue)) this.DefaultCategory = nodeValue; nodeValue = configNode.GetAttribute("autoInternationalize"); if (!string.IsNullOrEmpty(nodeValue)) this.AutoInternationalize = nodeValue.ContainsAnyOf("yes", "1", "true"); nodeValue = configNode.GetAttribute("debugMode"); if (!string.IsNullOrEmpty(nodeValue)) this.IsDebugEnabled = nodeValue.ContainsAnyOf("yes", "1", "true"); if (pathsNode != null) { this.PathTemplates.Parse(pathsNode); XmlNode node = pathsNode.SelectSingleNode("p:AssetPath", nm); if (node != null) { nodeValue = node.InnerText; if (!string.IsNullOrEmpty(nodeValue)) this.AssetPath = nodeValue.TrimEnd('/') + "/"; } } if (routingNode != null) this.Routing.Parse(routingNode); XmlElement linkingNode = configNode.SelectSingleElement("p:linking", nm); if (linkingNode != null) this.Linking.Parse(linkingNode); XmlElement environmentNode = configNode.SelectSingleElement("p:environment", nm); if (environmentNode != null) this.Environment.Parse(environmentNode); XmlElement cachingNode = configNode.SelectSingleElement("p:viewcaching", nm); if (cachingNode != null) this.ViewCaching.Parse(cachingNode); foreach (XmlElement libraryNode in configNode.SelectNodes("p:libraries/p:library", nm)) { ResourceLibraryInfo info = new ResourceLibraryInfo(libraryNode, this.Id); this.ResourceLibraries.Add(info.Name, info); } foreach (XmlElement moduleNode in configNode.SelectNodes("p:modules/p:module", nm)) { ModuleConfiguration moduleConfig = new ModuleConfiguration(moduleNode, this.Id); var moduleKey = string.IsNullOrWhiteSpace(moduleConfig.Category) ? moduleConfig.Name : moduleConfig.Category + "/" + moduleConfig.Name; this.Modules.Add(moduleKey, moduleConfig); } var localeNodes = configNode.SelectNodes("p:internationalization/p:locale", nm); if (localeNodes.Count != 0) { this.Locales = new Dictionary<string, LocaleInfo>(); this.Categories[this.DefaultCategory].Locales.Clear(); foreach (XmlElement locale in localeNodes) { var name = locale.GetAttribute("name"); var info = new LocaleInfo(locale); this.Locales[name] = info; this.Categories[this.DefaultCategory].Locales.Add(name); } } if (this.Locales.Count != 0 && !this.Locales.ContainsKey(this.DefaultLocale)) { string firstLocale = this.Locales.First().Key; log.ErrorFormat("The default locale '{0}' doesn't exist, resetting it to '{1}'.", this.DefaultLocale, firstLocale); this.DefaultLocale = firstLocale; } var categoryNodes = configNode.SelectNodes("p:categories/p:category", nm); if (categoryNodes.Count != 0) { this.Categories.Clear(); foreach (XmlElement categoryElement in categoryNodes) { var category = new CategoryInfo(categoryElement); this.Categories[category.Name] = category; var undefinedLocales = category.Locales.Where(name => !this.Locales.ContainsKey(name)).ToList(); if (undefinedLocales.Count != 0) { log.ErrorFormat("Category '{0}' is configured to use these unsupported locales: {1}.", category.Name, string.Join(",", undefinedLocales)); } } } if (this.Categories.Count != 0 && !this.Categories.ContainsKey(this.DefaultCategory)) { string firstCategory = this.Categories.First().Key; log.ErrorFormat("The default category '{0}' doesn't exist, resetting it to '{1}'.", this.DefaultCategory, firstCategory); this.DefaultCategory = firstCategory; } foreach (XmlElement viewNode in configNode.SelectNodes("p:metaViews/p:metaView", nm)) { var name = viewNode.GetAttribute("name"); var info = new MetaViewInfo(viewNode); this.MetaViews[name] = info; } foreach (XmlElement viewNode in configNode.SelectNodes("p:errorViews/p:view", nm)) { var error = viewNode.GetAttribute("error"); var info = new ErrorViewInfo(viewNode); this.ErrorViews[error] = info; } this.Package = new PackageConfiguration(packageElement); if (this.Changed != null) this.Changed(this, EventArgs.Empty); }