Пример #1
0
        private static async Task <DocItem> DocumentElement(
            this IDocProvider docProvider,
            DocItemCache cache,
            CppElement element,
            bool documentInnerElements = true,
            string name = null)
        {
            var docName = name ?? element.Name;

            DocItem cacheEntry = cache.Find(docName);
            var     docItem    = cacheEntry ?? await docProvider.FindDocumentationAsync(docName);

            element.Id          = docItem.ShortId;
            element.Description = docItem.Summary;
            element.Remarks     = docItem.Remarks;

            if (cacheEntry == null)
            {
                docItem.Name = docName;
                cache.Add(docItem);
            }

            if (element.IsEmpty)
            {
                return(docItem);
            }

            if (documentInnerElements)
            {
                DocumentInnerElements(element.Items, docItem);
            }

            return(docItem);
        }
Пример #2
0
    private static async Task <IDocItem?> DocumentElement(IDocProvider?docProvider,
                                                          DocItemCache cache,
                                                          CsBase element,
                                                          DocumentationContext context,
                                                          bool documentInnerElements,
                                                          string?name)
    {
        var docName = name ?? element.CppElementName;

        if (string.IsNullOrEmpty(docName))
        {
            return(null);
        }

        docName = docName.Trim();

        if (string.IsNullOrEmpty(docName))
        {
            return(null);
        }

        var cacheEntry = cache.Find(docName);
        var docItem    = cacheEntry ?? await QueryDocumentationProvider();

        if (docItem == null)
        {
            return(null);
        }

        element.DocId       = docItem.ShortId;
        element.Description = docItem.Summary;
        element.Remarks     = docItem.Remarks;
        docItem.Names.Add(docName);

        if (cacheEntry == null)
        {
            cache.Add(docItem);
        }

        if (element.Items.Count == 0)
        {
            return(docItem);
        }

        if (documentInnerElements)
        {
            DocumentInnerElements(element.Items, docItem);
        }

        return(docItem);

        async Task <IDocItem?> QueryDocumentationProvider()
        {
            if (docProvider == null)
            {
                return(null);
            }

            Lazy <string> docProviderName = new(
                () =>
            {
                try
                {
                    var friendlyName = docProvider.UserFriendlyName;
                    return(string.IsNullOrWhiteSpace(friendlyName) ? FullName() : friendlyName);
                }
                catch
                {
                    return(FullName());
                }

                string FullName()
                {
                    var type = docProvider.GetType();
                    var name = type.FullName;
                    return(string.IsNullOrEmpty(name) ? type.Name : name !);
                }
            },
                LazyThreadSafetyMode.None
                );

            List <Exception> exceptions = new(3);

            var(backoff, backoffIndex, nextDelay) = GenerateBackoff(TimeSpan.Zero);

            try
            {
                for (uint retry = 0; retry <= 5; retry++)
                {
                    if (retry != 0)
                    {
                        TimeSpan delay;
                        if (nextDelay.HasValue)
                        {
                            delay = nextDelay.Value;
                        }
                        else
                        {
                            // TODO: fix the bug and remove this hack
                            if (backoffIndex >= 5)
                            {
                                context.Logger.Message(
                                    $"SharpGen internal invalid state on delay: backoffIndex == {backoffIndex}"
                                    );
                                if (Debugger.IsAttached)
                                {
                                    Debugger.Break();
                                }
                                backoffIndex = 0;
                            }

                            delay = backoff[backoffIndex++];
                        }
                        if (delay > TimeSpan.Zero)
                        {
                            await Task.Delay(delay);
                        }
                        nextDelay = null;
                    }

                    try
                    {
                        var result = await docProvider.FindDocumentationAsync(docName, context);

                        switch (result)
                        {
                        case null:
                            throw new ArgumentNullException(
                                      nameof(result),
                                      $"Unexpected null {nameof(IFindDocumentationResult)}"
                                      );

                        case FindDocumentationResultFailure resultFailure:
                        {
                            var retryDelay = resultFailure.RetryDelay;
                            if (retryDelay == TimeSpan.MaxValue)
                            {
                                return(null);
                            }

                            if (retryDelay <= TimeSpan.Zero)
                            {
                                nextDelay = TimeSpan.Zero;
                            }

                            // TODO: fix the bug and remove this hack
                            if (backoffIndex >= 5)
                            {
                                context.Logger.Message(
                                    $"SharpGen internal invalid state on reschedule: backoffIndex = {backoffIndex}"
                                    );
                                if (Debugger.IsAttached)
                                {
                                    Debugger.Break();
                                }
                                (backoff, backoffIndex, nextDelay) = GenerateBackoff(retryDelay);
                            }

                            nextDelay = backoff[backoffIndex++];

                            if (nextDelay < retryDelay)
                            {
                                (backoff, backoffIndex, nextDelay) = GenerateBackoff(retryDelay);
                            }

                            break;
                        }

                        case FindDocumentationResultSuccess resultSuccess:
                            return(resultSuccess.Item);    // TODO: check if the item is empty (therefore, useless)

                        default:
                            throw new ArgumentOutOfRangeException(
                                      nameof(result),
                                      $"Unexpected {nameof(IFindDocumentationResult)}: {result.GetType().FullName}"
                                      );
                        }
                    }
                    catch (Exception e)
                    {
                        e.Data["SDK:" + nameof(docProvider)]           = docProvider;
                        e.Data["SDK:" + nameof(docName)]               = docName;
                        e.Data["SDK:" + nameof(context)]               = context;
                        e.Data["SDK:" + nameof(retry)]                 = retry;
                        e.Data["SDK:" + nameof(backoffIndex)]          = backoffIndex;
                        e.Data["SDK:" + nameof(exceptions) + ".Count"] = exceptions.Count;

                        exceptions.Add(e);

                        // We should retry less when it's due to unhandled exception.
                        // So in exception case we step twice in retry count on each iteration.
                        retry++;
                    }
                }

                context.Logger.Message($"{docProviderName.Value} extension failed to find documentation for \"{docName}\"");

                return(null);
            }
            finally
            {
                if (exceptions.Count > 0)
                {
                    var failure = new DocumentationQueryFailure(docName)
                    {
                        Exceptions                    = exceptions,
                        FailedProviderName            = docProviderName.Value,
                        TreatProviderFailuresAsErrors = docProvider.TreatFailuresAsErrors
                    };

                    context.Failures.Add(failure);
                }
            }
        }
    }