/* Function: Start * * Dependencies: * * - <Config.Manager> must be started before using the rest of the class. */ public bool Start(Errors.ErrorList errors) { EngineInstance.AddStartupWatcher(this); SQLite.API.Result sqliteResult = SQLite.API.Initialize(); if (sqliteResult != SQLite.API.Result.OK) { throw new SQLite.Exceptions.UnexpectedResult("Could not initialize SQLite.", sqliteResult); } Path databaseFile = EngineInstance.Config.WorkingDataFolder + "/CodeDB.nd"; connection = new SQLite.Connection(); bool success = false; if (!EngineInstance.HasIssues(StartupIssues.NeedToStartFresh | StartupIssues.FileIDsInvalidated | StartupIssues.CodeIDsInvalidated | StartupIssues.CommentIDsInvalidated)) { try { connection.Open(databaseFile, false); Version version = GetVersion(); if (BinaryFile.IsCompatible(version, Engine.Instance.Version, "2.0.2") == true) { LoadSystemVariables(); success = true; } } catch { } } if (!success) { connection.Dispose(); if (System.IO.File.Exists(databaseFile)) { System.IO.File.Delete(databaseFile); } connection.Open(databaseFile, true); CreateDatabase(); EngineInstance.AddStartupIssues(StartupIssues.CodeIDsInvalidated | StartupIssues.CommentIDsInvalidated | StartupIssues.NeedToReparseAllFiles, dontNotify: this); } started = true; return(true); }
/* Function: Start */ public bool Start(ErrorList errorList) { StartupIssues newStartupIssues = StartupIssues.None; // Load SearchIndex.nd bool hasBinaryFile; if (!EngineInstance.HasIssues(StartupIssues.NeedToStartFresh | StartupIssues.CommentIDsInvalidated | StartupIssues.CodeIDsInvalidated | StartupIssues.CommentIDsInvalidated)) { SearchIndex_nd binaryFileParser = new SearchIndex_nd(); hasBinaryFile = binaryFileParser.Load(Target.WorkingDataFolder + "/SearchIndex.nd", out prefixTopicIDs); } else { prefixTopicIDs = new StringTable <NumberSet>(KeySettingsForPrefixes); hasBinaryFile = false; } if (!hasBinaryFile) { // If we don't have the binary file we need to reparse all the source files to rebuild the index. However, setting NeedToReparseAllFiles // isn't enough because it will reparse those files, send them to CodeDB, and then CodeDB won't send topic updates if the underlying // content hasn't changed. So f**k it, blow it all up and start over. newStartupIssues |= StartupIssues.NeedToStartFresh; } // Add watchers EngineInstance.CodeDB.AddChangeWatcher(this); EngineInstance.AddStartupWatcher(this); if (newStartupIssues != StartupIssues.None) { EngineInstance.AddStartupIssues(newStartupIssues, dontNotify: this); } started = true; return(true); }
public override bool Start(Errors.ErrorList errorList) { int errors = errorList.Count; StartupIssues newStartupIssues = StartupIssues.None; // // Validate the output folder. // if (System.IO.Directory.Exists(config.Folder) == false) { errorList.Add(Locale.Get("NaturalDocs.Engine", "Error.FolderDoesntExist(type, name)", "output", config.Folder)); return(false); } // // Load and validate the styles, including any inherited styles. // string styleName = config.ProjectInfo.StyleName; Style_txt styleParser = new Style_txt(); if (styleName == null) { style = EngineInstance.Styles.LoadStyle("Default", errorList, Config.PropertySource.SystemDefault); } else if (EngineInstance.Styles.StyleExists(styleName)) { style = EngineInstance.Styles.LoadStyle(styleName, errorList, config.ProjectInfo.StyleNamePropertyLocation); } // Check if it's an empty folder we want to generate a default Style.txt for else if (System.IO.Directory.Exists(EngineInstance.Config.ProjectConfigFolder + '/' + styleName) && !System.IO.File.Exists(EngineInstance.Config.ProjectConfigFolder + '/' + styleName + "/Style.txt")) { style = new Styles.Advanced(EngineInstance.Config.ProjectConfigFolder + '/' + styleName + "/Style.txt"); // Inherit Default so everything still works before it's filled out. style.AddInheritedStyle("Default", Config.PropertySource.SystemGenerated); if (!styleParser.Save((Styles.Advanced)style, errorList, false)) { return(false); } // Now we have to reload it so it loads the inherited style as well. style = EngineInstance.Styles.LoadStyle(styleName, errorList, config.ProjectInfo.StyleNamePropertyLocation); } else { errorList.Add(Locale.Get("NaturalDocs.Engine", "Style.txt.CantFindStyle(name)", styleName), config.ProjectInfo.StyleNamePropertyLocation); return(false); } stylesWithInheritance = style.BuildInheritanceList(); // // Load Config.nd // Config_nd binaryConfigParser = new Config_nd(); List <Style> previousStyles; List <FileSourceInfo> previousFileSourceInfoList; bool hasBinaryConfigFile = false; if (!EngineInstance.HasIssues(StartupIssues.NeedToStartFresh)) { hasBinaryConfigFile = binaryConfigParser.Load(WorkingDataFolder + "/Config.nd", out previousStyles, out previousFileSourceInfoList); } else // start fresh { previousStyles = new List <Style>(); previousFileSourceInfoList = new List <FileSourceInfo>(); } // // Compare to the previous list of styles. // bool inPurgingOperation = false; if (!hasBinaryConfigFile) { // If we don't have the binary config file we have to purge every style folder because some of them may no longer be in // use and we won't know which. PurgeAllStyleFolders(ref inPurgingOperation); newStartupIssues |= StartupIssues.NeedToReparseStyleFiles; } else // (hasBinaryConfigFile) { // Purge the style folders for any no longer in use. foreach (var previousStyle in previousStyles) { bool stillExists = false; foreach (var currentStyle in stylesWithInheritance) { if (currentStyle.IsSameFundamentalStyle(previousStyle)) { stillExists = true; break; } } if (!stillExists) { PurgeStyleFolder(previousStyle.Name, ref inPurgingOperation); } } // Reparse styles on anything new. If a style is new we can't assume all its files are going to be sent to the // IChangeWatcher functions because another output target may have been using it, and thus they are already in // Files.Manager. foreach (var currentStyle in stylesWithInheritance) { bool foundMatch = false; foreach (var previousStyle in previousStyles) { if (previousStyle.IsSameFundamentalStyle(currentStyle)) { foundMatch = true; break; } } if (!foundMatch) { newStartupIssues |= StartupIssues.NeedToReparseStyleFiles; break; } } } // // Compare to the previous list of FileSources. // if (!hasBinaryConfigFile) { // If we don't have the binary config file we need to rebuild all the output because we don't know which FileSource was // previously set to which number, which determines which output folder they use, like /files vs /files2. newStartupIssues |= StartupIssues.NeedToRebuildAllOutput; // This also means we have to purge every source or image output folder because we won't know which changed or are // no longer in use. PurgeAllSourceAndImageFolders(ref inPurgingOperation); } else // (hasBinaryConfigFile) { bool hasDeletions = false; bool hasAdditions = false; // Purge the output folders of any deleted FileSources foreach (var previousFileSourceInfo in previousFileSourceInfoList) { bool stillExists = false; foreach (var fileSource in EngineInstance.Files.FileSources) { if (previousFileSourceInfo.IsSameFundamentalFileSource(fileSource)) { stillExists = true; break; } } if (!stillExists) { hasDeletions = true; Path outputFolder; if (previousFileSourceInfo.Type == InputType.Source) { outputFolder = Paths.SourceFile.OutputFolder(OutputFolder, previousFileSourceInfo.Number); } else if (previousFileSourceInfo.Type == InputType.Image) { outputFolder = Paths.Image.OutputFolder(OutputFolder, previousFileSourceInfo.Number, previousFileSourceInfo.Type); } else { throw new NotImplementedException(); } PurgeFolder(outputFolder, ref inPurgingOperation); } } // Check if any FileSources were added foreach (var fileSource in EngineInstance.Files.FileSources) { if (fileSource.Type == InputType.Source || fileSource.Type == InputType.Image) { bool foundMatch = false; foreach (var previousFileSourceInfo in previousFileSourceInfoList) { if (previousFileSourceInfo.IsSameFundamentalFileSource(fileSource)) { foundMatch = true; break; } } if (!foundMatch) { hasAdditions = true; break; } } } // If there were both additions and deletions, force a rebuild. This covers if a FileSource was simply moved from one // number to another, in which case the rebuild is required to populate the new folder. This also covers if a folder // FileSource is replaced by one for its parent folder, in which case a rebuild is required to recreate the output for the // files in the child folder. if (hasAdditions && hasDeletions) { newStartupIssues |= StartupIssues.NeedToRebuildAllOutput; } } // // Load BuildState.nd // BuildState_nd buildStateParser = new BuildState_nd(); bool hasBinaryBuildStateFile = false; if (!EngineInstance.HasIssues(StartupIssues.NeedToStartFresh | StartupIssues.FileIDsInvalidated | StartupIssues.CodeIDsInvalidated | StartupIssues.CommentIDsInvalidated)) { hasBinaryBuildStateFile = buildStateParser.Load(WorkingDataFolder + "/BuildState.nd", out buildState, out unprocessedChanges); } else // start fresh { buildState = new BuildState(); unprocessedChanges = new UnprocessedChanges(); } if (!hasBinaryBuildStateFile) { // If we don't have a build state file we need to reparse all the source files because we need to know sourceFilesWithContent // and classesWithContent. We also need to rebuild all the output because we don't know if there was anything left in // sourceFilesToRebuild from the last run. But those two flags actually aren't enough, because it will reparse those files, send // them to CodeDB, and then CodeDB won't send topic updates if the underlying content hasn't changed. We'd actually need // to add all files and classes to UnprocessedChanges, but the Files module isn't started yet. So f**k it, blow it all up and start // over. newStartupIssues |= StartupIssues.NeedToStartFresh; // Purge everything so no stray files are left behind from the previous build. PurgeAllSourceAndImageFolders(ref inPurgingOperation); PurgeAllClassFolders(ref inPurgingOperation); PurgeAllDatabaseFolders(ref inPurgingOperation); PurgeAllStyleFolders(ref inPurgingOperation); PurgeAllMenuFolders(ref inPurgingOperation); PurgeAllSearchIndexFolders(ref inPurgingOperation); } // // We're done with anything that could purge. // FinishedPurging(ref inPurgingOperation); // // Resave the Style.txt-based styles. // foreach (var style in stylesWithInheritance) { if (style is Styles.Advanced) { var advancedStyle = style as Styles.Advanced; bool isSystemStyle = EngineInstance.Config.SystemStyleFolder.Contains(advancedStyle.ConfigFile); // No error on save for system styles. styleParser.Save(advancedStyle, errorList, noErrorOnFail: isSystemStyle); } } // // Save Config.nd. // if (!System.IO.Directory.Exists(WorkingDataFolder)) { System.IO.Directory.CreateDirectory(WorkingDataFolder); } List <FileSourceInfo> fileSourceInfoList = new List <FileSourceInfo>(); foreach (var fileSource in EngineInstance.Files.FileSources) { if (fileSource.Type == Files.InputType.Source || fileSource.Type == Files.InputType.Image) { FileSourceInfo fileSourceInfo = new FileSourceInfo(); fileSourceInfo.CopyFrom(fileSource); fileSourceInfoList.Add(fileSourceInfo); } ; } binaryConfigParser.Save(WorkingDataFolder + "/Config.nd", stylesWithInheritance, fileSourceInfoList); // // Always rebuild the scaffolding since they're quick. If you ever make this differential, remember that FramePage depends // on the project name and other information. // unprocessedChanges.AddFramePage(); unprocessedChanges.AddMainStyleFiles(); // // Load up unprocessedChanges if we're rebuilding // if (EngineInstance.HasIssues(StartupIssues.NeedToRebuildAllOutput) || (newStartupIssues & StartupIssues.NeedToRebuildAllOutput) != 0) { unprocessedChanges.AddSourceFiles(buildState.sourceFilesWithContent); unprocessedChanges.AddClasses(buildState.classesWithContent); unprocessedChanges.AddImageFiles(buildState.usedImageFiles); newStartupIssues |= StartupIssues.NeedToReparseStyleFiles; unprocessedChanges.AddMainStyleFiles(); unprocessedChanges.AddMainSearchFiles(); unprocessedChanges.AddFramePage(); unprocessedChanges.AddMenu(); // We'll handle search prefixes after starting SearchIndex } // // Create the search index, watch other modules, and apply new StartupIssues // searchIndex = new SearchIndex.Manager(this); EngineInstance.CodeDB.AddChangeWatcher(this); EngineInstance.Files.AddChangeWatcher(this); searchIndex.AddChangeWatcher(this); EngineInstance.AddStartupWatcher(this); if (newStartupIssues != StartupIssues.None) { EngineInstance.AddStartupIssues(newStartupIssues, dontNotify: this); } searchIndex.Start(errorList); // // If we're rebuilding everything, add the search index prefixes now that that's started // if (EngineInstance.HasIssues(StartupIssues.NeedToRebuildAllOutput)) { var usedPrefixes = searchIndex.UsedPrefixes(); foreach (var searchPrefix in usedPrefixes) { unprocessedChanges.AddSearchPrefix(searchPrefix); } } return(errors == errorList.Count); }
private static bool BuildDocumentation (ErrorList errorList) { ShowConsoleHeader(); bool rebuildAllOutputFromCommandLine = EngineInstance.Config.RebuildAllOutput; bool reparseEverythingFromCommandLine = EngineInstance.Config.ReparseEverything; EngineInstance.AddStartupWatcher(new EngineStartupWatcher()); executionTimer.Start("Engine Startup"); if (EngineInstance.Start(errorList, commandLineConfig) == true) { executionTimer.End("Engine Startup"); // File Search executionTimer.Start("Finding Source Files"); using ( StatusManagers.FileSearch statusManager = new StatusManagers.FileSearch() ) { statusManager.Start(); Multithread("File Adder", EngineInstance.Files.WorkOnAddingAllFiles); statusManager.End(); } EngineInstance.Files.DeleteFilesNotInFileSources( Engine.Delegates.NeverCancel ); executionTimer.End("Finding Source Files"); // Rebuild notice string alternateStartMessage = null; if (reparseEverythingFromCommandLine || rebuildAllOutputFromCommandLine) { alternateStartMessage = "Status.RebuildEverythingByRequest"; } else if (EngineInstance.Config.ReparseEverything && EngineInstance.Config.RebuildAllOutput) { alternateStartMessage = "Status.RebuildEverythingAutomatically"; } // Parsing executionTimer.Start("Parsing Source Files"); using ( StatusManagers.Parsing statusManager = new StatusManagers.Parsing(alternateStartMessage) ) { statusManager.Start(); totalFileChanges = statusManager.TotalFilesToProcess; Multithread("Parser", EngineInstance.Files.WorkOnProcessingChanges); statusManager.End(); } executionTimer.End("Parsing Source Files"); // Resolving executionTimer.Start("Resolving Links"); using ( StatusManagers.ResolvingLinks statusManager = new StatusManagers.ResolvingLinks() ) { statusManager.Start(); Multithread("Resolver", EngineInstance.Links.WorkOnResolvingLinks); statusManager.End(); } executionTimer.End("Resolving Links"); // Building executionTimer.Start("Building Output"); using ( StatusManagers.Building statusManager = new StatusManagers.Building() ) { statusManager.Start(); Multithread("Builder", EngineInstance.Output.WorkOnUpdatingOutput); Multithread("Finalizer", EngineInstance.Output.WorkOnFinalizingOutput); statusManager.End(); } executionTimer.End("Building Output"); // End EngineInstance.Cleanup(Delegates.NeverCancel); ShowConsoleFooter(true); return true; } else // engine did not start correctly { executionTimer.End("Engine Startup"); ShowConsoleFooter(false); return false; } }
private static bool BuildDocumentation(ErrorList errorList) { ShowConsoleHeader(); EngineInstance.AddStartupWatcher(new EngineStartupWatcher()); executionTimer.Start("Engine Startup"); if (EngineInstance.Start(errorList, commandLineConfig) == true) { executionTimer.End("Engine Startup"); // File Search executionTimer.Start("Finding Source Files"); var adderProcess = EngineInstance.Files.CreateAdderProcess(); using (StatusManagers.FileSearch statusManager = new StatusManagers.FileSearch(adderProcess)) { statusManager.Start(); Multithread("File Adder", adderProcess.WorkOnAddingAllFiles); statusManager.End(); } EngineInstance.Files.DeleteFilesNotReAdded(Engine.Delegates.NeverCancel); adderProcess.Dispose(); executionTimer.End("Finding Source Files"); // Rebuild notice string alternativeStartMessage = null; if (EngineInstance.Config.UserWantsEverythingRebuilt || EngineInstance.Config.UserWantsOutputRebuilt) { alternativeStartMessage = "Status.RebuildEverythingByRequest"; } else if (EngineInstance.HasIssues(StartupIssues.NeedToStartFresh | StartupIssues.NeedToReparseAllFiles | StartupIssues.NeedToRebuildAllOutput)) { alternativeStartMessage = "Status.RebuildEverythingAutomatically"; } // Parsing executionTimer.Start("Parsing Source Files"); var changeProcessor = EngineInstance.Files.CreateChangeProcessor(); using (StatusManagers.Parsing statusManager = new StatusManagers.Parsing(changeProcessor, alternativeStartMessage)) { statusManager.Start(); totalFileChanges = statusManager.TotalFilesToProcess; Multithread("Parser", changeProcessor.WorkOnProcessingChanges); statusManager.End(); } changeProcessor.Dispose(); executionTimer.End("Parsing Source Files"); // Resolving executionTimer.Start("Resolving Links"); var resolverProcess = EngineInstance.Links.CreateResolverProcess(); using (StatusManagers.ResolvingLinks statusManager = new StatusManagers.ResolvingLinks(resolverProcess)) { statusManager.Start(); Multithread("Resolver", resolverProcess.WorkOnResolvingLinks); statusManager.End(); } resolverProcess.Dispose(); executionTimer.End("Resolving Links"); // Building executionTimer.Start("Building Output"); var builderProcess = EngineInstance.Output.CreateBuilderProcess(); using (StatusManagers.Building statusManager = new StatusManagers.Building(builderProcess)) { statusManager.Start(); Multithread("Builder", builderProcess.WorkOnUpdatingOutput); Multithread("Finalizer", builderProcess.WorkOnFinalizingOutput); statusManager.End(); } builderProcess.Dispose(); executionTimer.End("Building Output"); // End EngineInstance.Cleanup(Delegates.NeverCancel); ShowConsoleFooter(true); return(true); } else // engine did not start correctly { executionTimer.End("Engine Startup"); ShowConsoleFooter(false); return(false); } }