Ejemplo n.º 1
0
        /* Function: ProcessNewOrChangedFile
         * Takes a new or changed <File>, parses it, and updates <CodeDB.Manager> with its contents.  The <CodeDB.Accessor>
         * should NOT already hold a lock.
         */
        protected ProcessFileResult ProcessNewOrChangedFile(File file, Engine.CodeDB.Accessor codeDBAccessor,
                                                            CancelDelegate cancelDelegate)
        {
            if (file.Type == FileType.Source)
            {
                return(ProcessNewOrChangedSourceFile(file, codeDBAccessor, cancelDelegate));
            }

            else
            {
                // Style and image files are only processed by output builders.  They're not in CodeDB so we don't need to do
                // anything here.
                return(ProcessFileResult.Success);
            }
        }
Ejemplo n.º 2
0
        // Group: Group File Processing Functions
        // __________________________________________________________________________


        /* Function: WorkOnProcessingChanges
         *
         * Works on the task of going through all the file changes and deletions and calling <ProcessNewOrChangedFile()> and
         * <ProcessDeletedFile()> on each one.  This is a parallelizable task, so multiple threads can call this function and they
         * will divide up the work until it's done.
         *
         * The function returns when there is no more work for this thread to do.  If this is the only thread working on it then the
         * task is complete, but if there are multiple threads, the task is only complete after they all return.  An individual thread
         * may return prior to that point.
         */
        public void WorkOnProcessingChanges(CancelDelegate cancelDelegate)
        {
            using (Engine.CodeDB.Accessor codeDBAccessor = EngineInstance.CodeDB.GetAccessor())
            {
                bool deletedFiles, newOrChangedFiles;

                do
                {
                    deletedFiles      = false;
                    newOrChangedFiles = false;

                    while (!cancelDelegate())
                    {
                        File file = PickDeletedFile();

                        if (file == null)
                        {
                            break;
                        }

                        deletedFiles = true;
                        var result = ProcessDeletedFile(file, codeDBAccessor, cancelDelegate);
                        FinalizeDeletedFile(file, result);
                    }

                    while (!cancelDelegate())
                    {
                        File file = PickNewOrChangedFile();

                        if (file == null)
                        {
                            break;
                        }

                        newOrChangedFiles = true;
                        var result = ProcessNewOrChangedFile(file, codeDBAccessor, cancelDelegate);
                        FinalizeNewOrChangedFile(file, result);
                    }
                }
                // It's possible more deleted files appeared while processing changes so we have to make it through an
                // iteration where both pick functions come up empty.
                while (deletedFiles == true || newOrChangedFiles == true);
            }
        }
Ejemplo n.º 3
0
        // Group: Group File Processing Functions
        // __________________________________________________________________________


        /* Function: WorkOnProcessingChanges
         *
         * Works on the task of going through all the file changes and deletions and calling <ProcessChangedFile()> and
         * <ProcessDeletedFile()> on each one.  This is a parallelizable task, so multiple threads can call this function and they
         * will divide up the work until it's done.
         *
         * The function returns when there is no more work for this thread to do.  If this is the only thread working on it then the
         * task is complete, but if there are multiple threads, the task is only complete after they all return.  An individual thread
         * may return prior to that point.
         */
        public void WorkOnProcessingChanges(CancelDelegate cancelDelegate)
        {
            using (Engine.CodeDB.Accessor codeDBAccessor = EngineInstance.CodeDB.GetAccessor())
            {
                bool deletedFiles, changedFiles;

                do
                {
                    deletedFiles = false;
                    changedFiles = false;

                    for (;;)
                    {
                        File file = ClaimDeletedFile();

                        if (file == null)
                        {
                            break;
                        }

                        deletedFiles = true;
                        var result = ProcessDeletedFile(file, codeDBAccessor, cancelDelegate);
                        ReleaseClaimedFile(file, result);
                    }

                    for (;;)
                    {
                        File file = ClaimChangedFile();

                        if (file == null)
                        {
                            break;
                        }

                        changedFiles = true;
                        var result = ProcessChangedFile(file, codeDBAccessor, cancelDelegate);
                        ReleaseClaimedFile(file, result);
                    }
                }
                // It's possible more deleted files appeared while processing changes so we have to make it through an iteration where
                // both claim functions come up empty.
                while (deletedFiles == true || changedFiles == true);
            }
        }
Ejemplo n.º 4
0
        /* Function: ProcessNewOrChangedImageFile
         * Takes a new or changed <ImageFile> and determines its dimensions if it can.
         */
        protected ProcessFileResult ProcessNewOrChangedImageFile(ImageFile file, Engine.CodeDB.Accessor codeDBAccessor,
                                                                 CancelDelegate cancelDelegate)
        {
            try
            {
                uint width, height;

                ImageFileProcessor.Result result = ImageFileProcessor.GetDimensions(file.FileName, out width, out height);

                if (result == ImageFileProcessor.Result.FileDoesntExist)
                {
                    return(ProcessFileResult.FileDoesntExist);
                }
                else if (result == ImageFileProcessor.Result.CantAccessFile)
                {
                    return(ProcessFileResult.CantAccessFile);
                }
                else if (result == ImageFileProcessor.Result.Success)
                {
                    file.SetDimensions(width, height);
                    return(ProcessFileResult.Success);
                }
                else
                {
                    // If we can't determine the dimensions because of a file format error or some other reason, then the dimensions
                    // aren't knowable to us.  Knowing that is still a successful evaluation of the file because there's no point in trying
                    // to do it again.
                    file.DimensionsKnown = false;
                    return(ProcessFileResult.Success);
                }
            }

            catch (Exception e)
            {
                try
                { e.AddNaturalDocsTask("Determining dimensions of " + file.FileName); }
                catch
                {  }

                throw;
            }
        }
Ejemplo n.º 5
0
        /* Function: ProcessNewOrChangedSourceFile
         * Takes a new or changed <File>, parses it, and updates <CodeDB.Manager> with its contents.  The <CodeDB.Accessor>
         * should NOT already hold a lock.
         */
        protected ProcessFileResult ProcessNewOrChangedSourceFile(File file, Engine.CodeDB.Accessor codeDBAccessor,
                                                                  CancelDelegate cancelDelegate)
        {
            try
            {
                var           language   = EngineInstance.Languages.FromFileName(file.FileName);
                IList <Topic> topics     = null;
                LinkSet       links      = null;
                ImageLinkSet  imageLinks = null;


                // Parse the file

                var parseResult = language.Parser.Parse(file.FileName, file.ID, cancelDelegate, out topics, out links);

                if (parseResult == Parser.ParseResult.Cancelled)
                {
                    return(ProcessFileResult.Cancelled);
                }
                else if (parseResult == Parser.ParseResult.CantAccessFile)
                {
                    return(ProcessFileResult.CantAccessFile);
                }
                else if (parseResult == Parser.ParseResult.FileDoesntExist)
                {
                    return(ProcessFileResult.FileDoesntExist);
                }


                // Extract links from the bodies and prototypes

                if (topics != null && topics.Count > 0)
                {
                    imageLinks = new ImageLinkSet();

                    foreach (Topic topic in topics)
                    {
                        GetLinks(topic, ref links, ref imageLinks);

                        if (cancelDelegate())
                        {
                            return(ProcessFileResult.Cancelled);
                        }
                    }
                }


                // Update the database

                codeDBAccessor.GetReadPossibleWriteLock();

                try
                {
                    if (topics != null && topics.Count > 0)
                    {
                        codeDBAccessor.UpdateTopicsInFile(file.ID, topics, cancelDelegate);
                    }
                    else
                    {
                        codeDBAccessor.DeleteTopicsInFile(file.ID, cancelDelegate);
                    }

                    if (links != null && links.Count > 0)
                    {
                        codeDBAccessor.UpdateLinksInFile(file.ID, links, cancelDelegate);
                    }
                    else
                    {
                        codeDBAccessor.DeleteLinksInFile(file.ID, cancelDelegate);
                    }

                    if (imageLinks != null && imageLinks.Count > 0)
                    {
                        codeDBAccessor.UpdateImageLinksInFile(file.ID, imageLinks, cancelDelegate);
                    }
                    else
                    {
                        codeDBAccessor.DeleteImageLinksInFile(file.ID, cancelDelegate);
                    }

                    // Need this check in case CodeDB quit early because of the cancel delegate.
                    if (cancelDelegate())
                    {
                        return(ProcessFileResult.Cancelled);
                    }
                }
                finally
                { codeDBAccessor.ReleaseLock(); }

                return(ProcessFileResult.Success);
            }

            catch (Exception e)
            {
                try
                { e.AddNaturalDocsTask("Parsing file " + file.FileName); }
                catch
                {  }

                throw;
            }
        }
Ejemplo n.º 6
0
        /* Function: TestFolder
         * Tests all the input files contained in this folder.  See <EngineInstanceManager.Start()> for how relative paths are handled.
         */
        public void TestFolder(Path testDataFolder, Path projectConfigFolder = default(Path))
        {
            TestList  allTests            = new TestList();
            StringSet expectedOutputFiles = new StringSet();

            engineInstanceManager = new EngineInstanceManager();
            engineInstanceManager.Start(testDataFolder, projectConfigFolder);

            // Store this so we can still use it for error messages after the engine is disposed of.
            Path inputFolder = engineInstanceManager.InputFolder;

            try
            {
                engineInstanceManager.Run();


                // Iterate through classes to build output files.

                using (Engine.CodeDB.Accessor accessor = EngineInstance.CodeDB.GetAccessor())
                {
                    // Class IDs should be assigned sequentially.  It's not an ideal way to do this though.
                    int classID = 1;
                    accessor.GetReadOnlyLock();

                    try
                    {
                        for (;;)
                        {
                            List <Topic> classTopics = accessor.GetTopicsInClass(classID, Delegates.NeverCancel);
                            Engine.Output.Components.ClassView.MergeTopics(classTopics, engineInstanceManager.HTMLBuilder);

                            if (classTopics == null || classTopics.Count == 0)
                            {
                                break;
                            }

                            string testName       = classTopics[0].ClassString.Symbol.FormatWithSeparator(".");
                            Path   outputFilePath = Test.ActualOutputFileOf(testName, inputFolder);

                            Test test = Test.FromActualOutputFile(outputFilePath);
                            expectedOutputFiles.Add(test.ExpectedOutputFile);

                            try
                            {
                                test.SetActualOutput(OutputOf(classTopics));
                            }
                            catch (Exception e)
                            { test.TestException = e; }

                            test.Run();
                            allTests.Add(test);

                            classID++;
                        }
                    }
                    finally
                    { accessor.ReleaseLock(); }
                }


                // Now search for any expected output files that didn't have corresponding actual output files.

                string[] files = System.IO.Directory.GetFiles(inputFolder);

                foreach (string file in files)
                {
                    if (Test.IsExpectedOutputFile(file) && expectedOutputFiles.Contains(file) == false)
                    {
                        Test test = Test.FromExpectedOutputFile(file);
                        test.Run();
                        allTests.Add(test);

                        expectedOutputFiles.Add(file);
                    }
                }
            }

            finally
            {
                engineInstanceManager.Dispose();
                engineInstanceManager = null;
            }


            if (allTests.Count == 0)
            {
                Assert.Fail("There were no tests found in " + inputFolder);
            }
            else if (allTests.Passed == false)
            {
                Assert.Fail(allTests.BuildFailureMessage());
            }
        }
Ejemplo n.º 7
0
        /* Function: ProcessChangedFile
         * Takes a changed <File>, parses it, and updates <CodeDB.Manager> with its contents.  It returns the result code that
         * should be passed to <ReleaseClaimedFile()> if the file was retrieved with <ClaimChangedFile()>.  The <CodeDB.Accessor>
         * should NOT already hold a lock.
         */
        public ReleaseClaimedFileReason ProcessChangedFile(File file, Engine.CodeDB.Accessor codeDBAccessor,
                                                           CancelDelegate cancelDelegate)
        {
            // Process source files

            if (file.Type == FileType.Source)
            {
                try
                {
                    var           language   = EngineInstance.Languages.FromFileName(file.FileName);
                    IList <Topic> topics     = null;
                    LinkSet       links      = null;
                    ImageLinkSet  imageLinks = null;

                    var parseResult = language.Parse(file.FileName, file.ID, cancelDelegate, out topics, out links);

                    if (parseResult == Language.ParseResult.FileDoesntExist)
                    {
                        return(ReleaseClaimedFileReason.FileDoesntExist);
                    }
                    else if (parseResult == Language.ParseResult.CantAccessFile)
                    {
                        return(ReleaseClaimedFileReason.CantAccessFile);
                    }
                    else if (parseResult == Language.ParseResult.Cancelled)
                    {
                        return(ReleaseClaimedFileReason.CancelledProcessing);
                    }


                    // Parse the topic bodies for Natural Docs links and image links.  Parse the prototypes for type links.

                    if (topics != null && topics.Count > 0)
                    {
                        imageLinks = new ImageLinkSet();

                        foreach (Topic topic in topics)
                        {
                            if (topic.Body != null)
                            {
                                ExtractBodyLinks(topic, links, imageLinks);

                                if (cancelDelegate())
                                {
                                    return(ReleaseClaimedFileReason.CancelledProcessing);
                                }
                            }

                            // We want to extract type links even for prototypes in the class hierarchy because the HTML output falls back to
                            // regular prototypes if there's no class prototype.  Also, if there's parameter lists in the description the HTML
                            // generator will require type links to exist regardless of what type of prototype it creates.  For example, this
                            // SystemVerilog interface:
                            //
                            //    // Interface: myInterface
                            //    //
                            //    // Parameters:
                            //    //    PARAMNAME - description
                            //
                            //    interface myInterface #(parameter PARAMNAME = 8) (input reset, clk);
                            //
                            // The HTML generation for the Parameters section will expect a type link to exist for PARAMNAME.
                            //
                            if (topic.Prototype != null
                                )
                            {
                                ExtractTypeLinks(topic, links);

                                if (cancelDelegate())
                                {
                                    return(ReleaseClaimedFileReason.CancelledProcessing);
                                }
                            }
                        }
                    }


                    // Update the database

                    codeDBAccessor.GetReadPossibleWriteLock();

                    try
                    {
                        if (topics != null && topics.Count > 0)
                        {
                            codeDBAccessor.UpdateTopicsInFile(file.ID, topics, cancelDelegate);
                        }
                        else
                        {
                            codeDBAccessor.DeleteTopicsInFile(file.ID, cancelDelegate);
                        }

                        if (links != null && links.Count > 0)
                        {
                            codeDBAccessor.UpdateLinksInFile(file.ID, links, cancelDelegate);
                        }
                        else
                        {
                            codeDBAccessor.DeleteLinksInFile(file.ID, cancelDelegate);
                        }

                        if (imageLinks != null && imageLinks.Count > 0)
                        {
                            codeDBAccessor.UpdateImageLinksInFile(file.ID, imageLinks, cancelDelegate);
                        }
                        else
                        {
                            codeDBAccessor.DeleteImageLinksInFile(file.ID, cancelDelegate);
                        }
                    }
                    finally
                    { codeDBAccessor.ReleaseLock(); }

                    // Need this final check in case CodeDB quit with a cancellation.
                    if (cancelDelegate())
                    {
                        return(ReleaseClaimedFileReason.CancelledProcessing);
                    }

                    return(ReleaseClaimedFileReason.SuccessfullyProcessed);
                }
                catch (Exception e)
                {
                    try
                    { e.AddNaturalDocsTask("Parsing File: " + file.FileName); }
                    catch
                    {  }

                    throw;
                }
            }


            // Process style and image files

            else
            {
                // These are only processed by output builders.  They're not in CodeDB so we don't need to do anything here.
                return(ReleaseClaimedFileReason.SuccessfullyProcessed);
            }
        }