// ------------------------------------------------------------------- // Private // ------------------------------------------------------------------- private void Compile() { if (this.sourceDirectory == null || this.targetDirectory == null) { this.Arguments.PrintArgumentUse(); return; } if (!this.sourceDirectory.Exists) { Diagnostic.Error("Source directory does not exist: {0}", this.sourceDirectory); return; } this.config.Load(new CarbonFile(Constants.ConfigFileName)); var context = new CompileContext(); context.Initialize(this.sourceDirectory, this.targetDirectory); var scanner = this.factory.Resolve<IAddonScanner>(); if (!scanner.Run(context) || context.HasError) { Diagnostic.Error("Scanning Addons failed: {0}\n{1}", context.LastError, context.LastErrorException?.ToString() ?? "N/A"); return; } var compiler = this.factory.Resolve<ICompiler>(); if (!compiler.Run(context) || context.HasError) { Diagnostic.Error("Compilation failed: {0}\n{1}", context.LastError, context.LastErrorException?.ToString() ?? "N/A"); } }
private static void PurgeDuplicateContent(CompileContext context) { int duplicateFileCount = 0; IDictionary<string, CompileContent> duplicateCheck = new Dictionary<string, CompileContent>(); foreach (CompileContent content in new List<CompileContent>(context.FullContentList)) { if (!content.AbsoluteFile.Extension.Equals(Constants.ExtensionLua)) { // This check only applies to .lua scripts continue; } CompileContent existingContent; if (duplicateCheck.TryGetValue(content.Md5, out existingContent)) { duplicateFileCount++; context.FullContentList.Remove(content); continue; } duplicateCheck.Add(content.Md5, content); } Diagnostic.Info("Removed {0} Duplicate Content Files, {1} left", duplicateFileCount, context.FullContentList.Count); }
// ------------------------------------------------------------------- // Public // ------------------------------------------------------------------- public bool Run(CompileContext context) { Diagnostic.Info(string.Empty); Diagnostic.Info("Starting compilation of {0} Addons", context.ScannedEntries.Count); ResolveAddonDependency(context); AssembleContent(context); PurgeDuplicateContent(context); WriteContentToTarget(context); return true; }
private static void AssembleContent(CompileContext context) { context.Target.Create(); foreach (AddonEntry entry in context.EntriesOrderedByPriority) { foreach (AddonContent content in entry.Contents.Values) { AssembleContentRecursive(context, entry, content); } } Diagnostic.Info("Found {0} Content files to compile", context.FullContentList.Count); }
private static AddonEntry ReadToc(CompileContext context, CarbonFile file) { var entry = new AddonEntry(file); context.CurrentScanEntry = entry; using (var stream = file.OpenRead()) { using (var reader = new StreamReader(stream)) { while (!reader.EndOfStream) { var line = reader.ReadLine(); ParseTocLine(context, line); } } } context.FinalizeScannedEntry(); return entry; }
private static void ParseTocLine(CompileContext context, string line) { string trimmedLine = line.Trim(); if (string.IsNullOrEmpty(trimmedLine)) { // skip emptry lines return; } Match match = TocMetaRegex.Match(line); if (match.Success) { string key = match.Groups[1].Value.Trim(); string value = match.Groups[2].Value.Trim(); context.CurrentScanEntry.AddMeta(key, value); return; } if (trimmedLine.StartsWith("#")) { // Ignore comments return; } if (trimmedLine.EndsWith(Constants.ExtensionLua)) { context.CurrentScanEntry.AddContent(new AddonContent(new CarbonFile(trimmedLine), context.CurrentScanEntry.RootDirectory)); return; } if (trimmedLine.EndsWith(Constants.ExtensionXml)) { AddonContent xmlContent = ReadXMLContent(new CarbonFile(line), context.CurrentScanEntry.RootDirectory); if (xmlContent != null) { context.CurrentScanEntry.AddContent(xmlContent); } return; } Diagnostic.Warning("Unhandled Toc Entry: {0}", trimmedLine); }
private static void AssembleContentRecursive(CompileContext context, AddonEntry addon, AddonContent currentContent) { foreach (AddonContent subContent in currentContent.SubContent) { AssembleContentRecursive(context, addon, subContent); } CarbonFile absoluteFile = currentContent.RootDirectory.ToFile(currentContent.File); if (!absoluteFile.Exists) { Diagnostic.Warning("Content File {0} does not exist! ({1})", absoluteFile, currentContent.File); return; } var content = new CompileContent(addon, absoluteFile, absoluteFile.ToRelative<CarbonFile>(context.Source.ToDirectory(addon.Name))); using (var stream = absoluteFile.OpenRead()) { byte[] md5 = HashUtils.GetMd5(stream); content.Md5 = HashUtils.Md5ToString(md5); } context.FullContentList.Add(content); }
private static void WriteContentToTarget(CompileContext context) { StringBuilder contentTocBuilder = new StringBuilder(); contentTocBuilder.AppendLine("## Interface: 60200"); contentTocBuilder.AppendLine("## Title: Built"); contentTocBuilder.AppendLine("## Notes: Built"); contentTocBuilder.AppendLine("## Author: AddonCompiler"); contentTocBuilder.AppendLine("## Version: 6.0.001"); int filesCopied = 0; int resourcesCopied = 0; foreach (CompileContent content in context.FullContentList) { CarbonFile targetRelativeFile = new CarbonDirectory(content.Addon.Name).ToFile(content.RelativeFile); CarbonFile targetAbsoluteFile = context.Target.ToFile(targetRelativeFile); if (content.AbsoluteFile.Extension == Constants.ExtensionXml) { if (!WriteXmlContentToTarget(content.AbsoluteFile, targetAbsoluteFile)) { continue; } filesCopied++; } else { if (!WriteScriptContentToTarget(content, targetAbsoluteFile)) { continue; } filesCopied++; } // Register the content in the TOC contentTocBuilder.AppendLine(targetRelativeFile.GetPath()); } foreach (AddonEntry addon in context.EntriesOrderedByPriority) { foreach (CarbonFile resource in addon.Resources) { CarbonFile targetAbsoluteResourceFile = context.Target.ToDirectory(addon.Name).ToFile(resource); CarbonFile sourceAbsoluteResourceFile = addon.RootDirectory.ToFile(resource); sourceAbsoluteResourceFile.CopyTo(targetAbsoluteResourceFile, true); resourcesCopied++; } } CarbonFile builtTocFile = context.Target.ToFile("Built.toc"); builtTocFile.WriteAsString(contentTocBuilder.ToString()); Diagnostic.Info("Finished Compile with {0} content files and {1} resources", filesCopied, resourcesCopied); }
// ------------------------------------------------------------------- // Private // ------------------------------------------------------------------- private static void ResolveAddonDependency(CompileContext context) { foreach (AddonEntry entry in context.ScannedEntries.Values) { string dependencyValues; if (entry.Meta.TryGetValue(Constants.MetaDependencies, out dependencyValues)) { string[] dependencies = dependencyValues.Split(','); foreach (string dependency in dependencies) { if (dependency.Contains(Constants.BlizzardAddonPrefix)) { continue; } AddonEntry dependencyEntry; if (context.ScannedEntries.TryGetValue(dependency.Trim(), out dependencyEntry)) { entry.AddDependency(dependencyEntry); dependencyEntry.ModifyOrder(1); } else { Diagnostic.Warning("Could not resolve dependency {0} of {1}", dependency, entry.Name); } } } } context.EntriesOrderedByPriority = context.ScannedEntries.Values.OrderByDescending(x => x.Order).ThenBy(x => x.Name).ToList(); }
// ------------------------------------------------------------------- // Public // ------------------------------------------------------------------- public bool Run(CompileContext context) { ScanSource(context); return true; }
// ------------------------------------------------------------------- // Private // ------------------------------------------------------------------- private static void ScanSource(CompileContext context) { context.ScannedEntries.Clear(); CarbonDirectoryResult[] candidates = context.Source.GetDirectories(); foreach (CarbonDirectoryResult candidate in candidates) { CarbonFileResult[] tocResults = candidate.Absolute.GetFiles("*" + Constants.ExtensionToc); if (tocResults == null || tocResults.Length <= 0) { Diagnostic.Info("Skipping directory {0}, no TOC found", candidate.Absolute.DirectoryNameWithoutPath); continue; } foreach (CarbonFileResult tocResult in tocResults) { Diagnostic.Info("Scanning {0}", tocResult.Absolute.FileName); AddonEntry entry = ReadToc(context, tocResult.Absolute); // Now scan for resources CarbonFileResult[] fileResults = candidate.Absolute.GetFiles(options: SearchOption.AllDirectories); foreach (CarbonFileResult fileResult in fileResults) { if (Constants.ResourceExtensions.Contains(fileResult.Absolute.Extension.ToLowerInvariant())) { entry.AddResource(fileResult.Relative); } } continue; } } }