예제 #1
0
        internal static bool HasAmbiguousParameterValueMatch(this ITemplateMatchInfo templateMatchInfo)
        {
#pragma warning disable CS0618 // Type or member is obsolete
            return(templateMatchInfo.MatchDisposition.Any(x => x.Kind == MatchKind.AmbiguousValue));

#pragma warning restore CS0618 // Type or member is obsolete
        }
예제 #2
0
        public static bool IsMatchExceptContext(this ITemplateMatchInfo templateMatchInfo)
        {
            if (templateMatchInfo.MatchDisposition.Count == 0)
            {
                return(false);
            }

            bool hasContextMismatch = false;

            foreach (MatchInfo disposition in templateMatchInfo.MatchDisposition)
            {
                if (disposition.Location == MatchLocation.Context)
                {
                    if (disposition.Kind == MatchKind.Exact)
                    {
                        return(false);
                    }
                    else
                    {
                        hasContextMismatch = true;
                    }
                }
                else if (disposition.Kind == MatchKind.Mismatch)
                {
                    return(false);
                }
            }

            return(hasContextMismatch);
        }
        private void EnsureTemplateResolutionResult()
        {
            if (_resolutionResultInitialized)
            {
                return;
            }

            _templateResolutionResult = TemplateListResolver.GetTemplateResolutionResult(_settingsLoader.UserTemplateCache.TemplateInfo, _hostDataLoader, _commandInput, _defaultLanguage);
            _singleMatchStatus        = SingularInvokableMatchCheckStatus.None;

            // If any template in the group has any ambiguous params, it's not invokable.
            // The check for HasAmbiguousParameterValueMatch is for an example like:
            // "dotnet new mvc -f netcore"
            //      - '-f netcore' is ambiguous in the 1.x version (2 begins-with matches)
            //      - '-f netcore' is not ambiguous in the 2.x version (1 begins-with match)
            if (!_templateResolutionResult.TryGetUnambiguousTemplateGroupToUse(out IReadOnlyList <ITemplateMatchInfo> unambiguousTemplateGroup) ||
                !_templateResolutionResult.TryGetSingularInvokableMatch(out _templateToInvoke, out _singleMatchStatus) ||
                unambiguousTemplateGroup.Any(x => x.HasParameterMismatch()) ||
                unambiguousTemplateGroup.Any(x => x.HasAmbiguousParameterValueMatch()))
            {
                _templateToInvoke = null;

                if (_singleMatchStatus == SingularInvokableMatchCheckStatus.AmbiguousChoice)
                {
                    _environment.Host.LogDiagnosticMessage(LocalizableStrings.Authoring_AmbiguousChoiceParameterValue, "Authoring");
                }
                else if (_singleMatchStatus == SingularInvokableMatchCheckStatus.AmbiguousPrecedence)
                {
                    _environment.Host.LogDiagnosticMessage(LocalizableStrings.Authoring_AmbiguousBestPrecedence, "Authoring");
                }
            }

            _resolutionResultInitialized = true;
        }
예제 #4
0
 internal static IEnumerable <string> GetInvalidParameterNames(this ITemplateMatchInfo templateMatchInfo)
 {
     return(templateMatchInfo.MatchDisposition
            .OfType <ParameterMatchInfo>()
            .Where(match => match.Kind == MatchKind.InvalidName)
            .Select(match => match.Name));
 }
예제 #5
0
        public static bool CheckForArgsError(ITemplateMatchInfo template, out string commandParseFailureMessage)
        {
            bool argsError;

            if (template.HasParseError())
            {
                commandParseFailureMessage = template.GetParseError();
                argsError = true;
            }
            else
            {
                commandParseFailureMessage = null;
                IReadOnlyList <string> invalidParams = template.GetInvalidParameterNames();

                if (invalidParams.Count > 0)
                {
                    HelpForTemplateResolution.DisplayInvalidParameters(invalidParams);
                    argsError = true;
                }
                else
                {
                    argsError = false;
                }
            }

            return(argsError);
        }
예제 #6
0
        public void TestFindHighestPrecedenceTemplateIfAllSameGroupIdentity_ReturnsNullIfGroupsAreDifferent()
        {
            List <ITemplateMatchInfo> templatesToCheck = new List <ITemplateMatchInfo>();

            templatesToCheck.Add(new TemplateMatchInfo(
                                     new TemplateInfo()
            {
                Precedence    = 10,
                Name          = "Template1",
                Identity      = "Template1",
                GroupIdentity = "TestGroup"
            }
                                     , null));
            templatesToCheck.Add(new TemplateMatchInfo(
                                     new TemplateInfo()
            {
                Precedence    = 20,
                Name          = "Template2",
                Identity      = "Template2",
                GroupIdentity = "RealGroup"
            }
                                     , null));
            ITemplateMatchInfo highestPrecedenceTemplate = TemplateListResolver.FindHighestPrecedenceTemplateIfAllSameGroupIdentity(templatesToCheck);

            Assert.Null(highestPrecedenceTemplate);
        }
예제 #7
0
        private static IReadOnlyList <TemplateGroupForListDisplay> GetTemplateGroupsForListDisplay(IReadOnlyCollection <IGrouping <string, ITemplateMatchInfo> > groupedTemplateList, string language, string defaultLanguage)
        {
            List <TemplateGroupForListDisplay> templateGroupsForDisplay = new List <TemplateGroupForListDisplay>();

            foreach (IGrouping <string, ITemplateMatchInfo> grouping in groupedTemplateList)
            {
                List <string>    languageForDisplay     = new List <string>();
                HashSet <string> uniqueLanguages        = new HashSet <string>(StringComparer.OrdinalIgnoreCase);
                string           defaultLanguageDisplay = string.Empty;

                foreach (ITemplateMatchInfo template in grouping)
                {
                    if (template.Info.Tags != null && template.Info.Tags.TryGetValue("language", out ICacheTag languageTag))
                    {
                        foreach (string lang in languageTag.ChoicesAndDescriptions.Keys)
                        {
                            if (uniqueLanguages.Add(lang))
                            {
                                if (string.IsNullOrEmpty(language) && string.Equals(defaultLanguage, lang, StringComparison.OrdinalIgnoreCase))
                                {
                                    defaultLanguageDisplay = $"[{lang}]";
                                }
                                else
                                {
                                    languageForDisplay.Add(lang);
                                }
                            }
                        }
                    }
                }

                languageForDisplay.Sort(StringComparer.OrdinalIgnoreCase);
                if (!string.IsNullOrEmpty(defaultLanguageDisplay))
                {
                    languageForDisplay.Insert(0, defaultLanguageDisplay);
                }

                ITemplateMatchInfo highestPrecedenceTemplate = grouping.OrderByDescending(x => x.Info.Precedence).First();
                string             shortName;
                if (highestPrecedenceTemplate.Info is IShortNameList highestWithShortNameList)
                {
                    shortName = highestWithShortNameList.ShortNameList[0];
                }
                else
                {
                    shortName = highestPrecedenceTemplate.Info.ShortName;
                }

                TemplateGroupForListDisplay groupDisplayInfo = new TemplateGroupForListDisplay()
                {
                    Name            = highestPrecedenceTemplate.Info.Name,
                    ShortName       = shortName,
                    Languages       = string.Join(",", languageForDisplay),
                    Classifications = highestPrecedenceTemplate.Info.Classifications != null?string.Join("/", highestPrecedenceTemplate.Info.Classifications) : null
                };
                templateGroupsForDisplay.Add(groupDisplayInfo);
            }

            return(templateGroupsForDisplay);
        }
        // check for updates for the matched template, based on the Identity
        private async Task CheckForTemplateUpdateAsync(ITemplateMatchInfo templateToInvoke)
        {
            if (!_settingsLoader.InstallUnitDescriptorCache.TryGetDescriptorForTemplate(templateToInvoke.Info, out IInstallUnitDescriptor descriptor))
            {
                Reporter.Error.WriteLine(string.Format(LocalizableStrings.InstallDescriptor_NotFound, templateToInvoke.Info.Identity));
                return;
            }

            List <IInstallUnitDescriptor> descriptorList = new List <IInstallUnitDescriptor>()
            {
                descriptor
            };
            TemplateUpdateChecker updateChecker     = new TemplateUpdateChecker(_environment);
            IUpdateCheckResult    updateCheckResult = await updateChecker.CheckForUpdatesAsync(descriptorList).ConfigureAwait(false);

            if (updateCheckResult.Updates.Count == 0)
            {
                return;
            }
            else if (updateCheckResult.Updates.Count == 1)
            {
                DisplayUpdateMessage(updateCheckResult.Updates[0]);
            }
            else
            {
                Reporter.Error.WriteLine(string.Format(LocalizableStrings.UpdateCheck_UnknownError, descriptor.Identifier));
            }
        }
예제 #9
0
        public static ITemplateMatchInfo FindHighestPrecedenceTemplateIfAllSameGroupIdentity(IReadOnlyCollection<ITemplateMatchInfo> templateList, out bool ambiguousResult)
        {
            ambiguousResult = false;

            if (!AreAllTemplatesSameGroupIdentity(templateList))
            {
                return null;
            }

            ITemplateMatchInfo highestPrecedenceTemplate = null;

            foreach (ITemplateMatchInfo template in templateList)
            {
                if (highestPrecedenceTemplate == null)
                {
                    highestPrecedenceTemplate = template;
                }
                else if (template.Info.Precedence > highestPrecedenceTemplate.Info.Precedence)
                {
                    highestPrecedenceTemplate = template;
                }
                else if (template.Info.Precedence == highestPrecedenceTemplate.Info.Precedence)
                {
                    ambiguousResult = true;
                    highestPrecedenceTemplate = null;
                    break;
                }
            }

            return highestPrecedenceTemplate;
        }
        public void AddMatchForPack(PackInfo packInfo, ITemplateMatchInfo matchInfo)
        {
            if (!_packsWithMatches.TryGetValue(packInfo, out TemplatePackSearchResult matchesForPack))
            {
                matchesForPack = new TemplatePackSearchResult(packInfo);
                _packsWithMatches[packInfo] = matchesForPack;
            }

            matchesForPack.AddMatch(matchInfo);
        }
        public void TestFindHighestPrecedenceTemplateIfAllSameGroupIdentity_ReturnsNullIfGroupsAreDifferent()
        {
            List <ITemplateMatchInfo> templatesToCheck = new List <ITemplateMatchInfo>();

            templatesToCheck.Add(new TemplateMatchInfo(
                                     new MockTemplateInfo("Template1", name: "Template1", identity: "Template1", groupIdentity: "TestGroup", precedence: 10), null));
            templatesToCheck.Add(new TemplateMatchInfo(
                                     new MockTemplateInfo("Template2", name: "Template2", identity: "Template2", groupIdentity: "RealGroup", precedence: 20), null));

            ITemplateMatchInfo highestPrecedenceTemplate = TemplateResolver.FindHighestPrecedenceTemplateIfAllSameGroupIdentity(templatesToCheck);

            Assert.Null(highestPrecedenceTemplate);
        }
        private static TemplateGroupTableRow GetTemplateGroupRow(IEnumerable <ITemplateMatchInfo> templateGroup, string language, string defaultLanguage)
        {
            List <string>    languageForDisplay     = new List <string>();
            HashSet <string> uniqueLanguages        = new HashSet <string>(StringComparer.OrdinalIgnoreCase);
            string           defaultLanguageDisplay = string.Empty;

            foreach (ITemplateMatchInfo template in templateGroup)
            {
                string lang = template.Info.GetLanguage();
                if (string.IsNullOrWhiteSpace(lang))
                {
                    continue;
                }

                if (!uniqueLanguages.Add(lang))
                {
                    continue;
                }
                if (string.IsNullOrEmpty(language) && string.Equals(defaultLanguage, lang, StringComparison.OrdinalIgnoreCase))
                {
                    defaultLanguageDisplay = $"[{lang}]";
                }
                else
                {
                    languageForDisplay.Add(lang);
                }
            }

            languageForDisplay.Sort(StringComparer.OrdinalIgnoreCase);
            if (!string.IsNullOrEmpty(defaultLanguageDisplay))
            {
                languageForDisplay.Insert(0, defaultLanguageDisplay);
            }

            ITemplateMatchInfo highestPrecedenceTemplate = templateGroup.OrderByDescending(x => x.Info.Precedence).First();
            string             shortName = highestPrecedenceTemplate.Info is IShortNameList highestWithShortNameList
                                ? highestWithShortNameList.ShortNameList[0]
                                : highestPrecedenceTemplate.Info.ShortName;

            TemplateGroupTableRow groupDisplayInfo = new TemplateGroupTableRow
            {
                Name            = highestPrecedenceTemplate.Info.Name,
                ShortName       = shortName,
                Languages       = string.Join(",", languageForDisplay),
                Classifications = highestPrecedenceTemplate.Info.Classifications != null?string.Join("/", highestPrecedenceTemplate.Info.Classifications) : null,
                                      Author = highestPrecedenceTemplate.Info.Author,
                                      Type   = highestPrecedenceTemplate.Info.GetTemplateType() ?? string.Empty
            };

            return(groupDisplayInfo);
        }
예제 #13
0
        internal static bool HasMismatchOnConstraints(this ITemplateMatchInfo templateMatchInfo)
        {
            var constraintsMatches = templateMatchInfo.MatchDisposition.Where(mi => mi.Name.StartsWith(MatchInfo.BuiltIn.Constraint));
            var otherMatches       = templateMatchInfo.MatchDisposition.Where(mi => !mi.Name.StartsWith(MatchInfo.BuiltIn.Constraint));

            if (!constraintsMatches.Any())
            {
                return(false);
            }
            if (otherMatches.Any(mi => mi.Kind == MatchKind.Mismatch || mi.Kind == MatchKind.InvalidName || mi.Kind == MatchKind.InvalidValue))
            {
                //there are other mismatches than on constraints
                return(false);
            }
            return(constraintsMatches.Any(mi => mi.Kind == MatchKind.Mismatch));
        }
예제 #14
0
        /// <summary>
        /// The method returns the single invokable template with highest precedence
        /// </summary>
        /// <param name="highestPrecedenceTemplate">Contains the invokable template with highest precedence</param>
        /// <param name="useDefaultLanguage">Defines if default language template should be preferred in case of ambiguity</param>
        /// <returns>
        /// <see cref="true"/> when single invokable template with highest precedence can be defined,
        /// <see cref="false"/> otherwise
        /// </returns>
        internal bool TryGetHighestPrecedenceInvokableTemplate(out ITemplateMatchInfo highestPrecedenceTemplate, bool useDefaultLanguage = false)
        {
            highestPrecedenceTemplate = null;
            if (!InvokableTemplates.Any())
            {
                return(false);
            }
            IEnumerable <ITemplateMatchInfo> highestPrecendenceTemplates = GetHighestPrecedenceInvokableTemplates(useDefaultLanguage);

            if (highestPrecendenceTemplates.Count() == 1)
            {
                highestPrecedenceTemplate = highestPrecendenceTemplates.First();
                return(true);
            }
            return(false);
        }
예제 #15
0
 public static bool IsInvokableMatch(this ITemplateMatchInfo templateMatchInfo)
 {
     return(templateMatchInfo.MatchDisposition.Count > 0 &&
            templateMatchInfo.MatchDisposition.All(x =>
                                                   x.Kind == MatchKind.Exact
                                                   ||
                                                   ( // these locations can have partial or exact matches.
                                                       x.Kind == MatchKind.Partial &&
                                                       (x.Location == MatchLocation.Name || x.Location == MatchLocation.ShortName || x.Location == MatchLocation.Classification)
                                                   )
                                                   ||
                                                   (
                                                       x.Location == MatchLocation.OtherParameter && x.Kind == MatchKind.SingleStartsWith
                                                   )
                                                   ));
 }
        public static bool HasClassificationMatchAndNameMismatch(this ITemplateMatchInfo templateMatchInfo)
        {
            if (templateMatchInfo.MatchDisposition.Count == 0)
            {
                return(false);
            }

            bool hasNameMismatch        = false;
            bool hasClassificationMatch = false;

            foreach (MatchInfo disposition in templateMatchInfo.MatchDisposition)
            {
                if (disposition.Location == MatchLocation.Name && disposition.Kind != MatchKind.Mismatch)
                {
                    return(false);
                }
                else if (disposition.Location == MatchLocation.Name && disposition.Kind == MatchKind.Mismatch)
                {
                    hasNameMismatch = true;
                }
                else if (disposition.Location == MatchLocation.ShortName && disposition.Kind != MatchKind.Mismatch)
                {
                    return(false);
                }
                else if (disposition.Location == MatchLocation.ShortName && disposition.Kind == MatchKind.Mismatch)
                {
                    hasNameMismatch = true;
                }
                else if (disposition.Location == MatchLocation.Classification)
                {
                    if (disposition.Kind == MatchKind.Exact || disposition.Kind == MatchKind.Partial)
                    {
                        hasClassificationMatch = true;
                    }
                    else
                    {
                        return(false);
                    }
                }
                else if (disposition.Kind == MatchKind.Mismatch)
                {
                    return(false);
                }
            }

            return(hasNameMismatch && hasClassificationMatch);
        }
예제 #17
0
        internal static bool CheckForArgsError(ITemplateMatchInfo template)
        {
            bool argsError;
            IEnumerable <string> invalidParams = template.GetInvalidParameterNames();

            if (invalidParams.Any())
            {
                HelpForTemplateResolution.DisplayInvalidParameters(invalidParams);
                argsError = true;
            }
            else
            {
                argsError = false;
            }

            return(argsError);
        }
        public void TestFindHighestPrecedenceTemplateIfAllSameGroupIdentity()
        {
            List <ITemplateMatchInfo> templatesToCheck = new List <ITemplateMatchInfo>();

            templatesToCheck.Add(new TemplateMatchInfo(
                                     new MockTemplateInfo("Template1", name: "Template1", identity: "Template1", groupIdentity: "TestGroup", precedence: 10), null));
            templatesToCheck.Add(new TemplateMatchInfo(
                                     new MockTemplateInfo("Template2", name: "Template2", identity: "Template2", groupIdentity: "TestGroup", precedence: 20), null));
            templatesToCheck.Add(new TemplateMatchInfo(
                                     new MockTemplateInfo("Template3", name: "Template3", identity: "Template3", groupIdentity: "TestGroup", precedence: 0), null));

            ITemplateMatchInfo highestPrecedenceTemplate = TemplateResolver.FindHighestPrecedenceTemplateIfAllSameGroupIdentity(templatesToCheck);

            Assert.NotNull(highestPrecedenceTemplate);
            Assert.Equal("Template2", highestPrecedenceTemplate.Info.Identity);
            Assert.Equal(20, highestPrecedenceTemplate.Info.Precedence);
        }
예제 #19
0
        internal static bool IsInvokableMatch(this ITemplateMatchInfo templateMatchInfo)
        {
            return(templateMatchInfo.MatchDisposition.Count > 0 &&
                   templateMatchInfo.MatchDisposition.All(x =>
                                                          x.Kind == MatchKind.Exact
                                                          ||
                                                          // these locations can have partial or exact matches.
                                                          x.Kind == MatchKind.Partial &&
                                                          (x.Name == MatchInfo.BuiltIn.Name ||
                                                           x.Name == MatchInfo.BuiltIn.ShortName ||
                                                           x.Name == MatchInfo.BuiltIn.Classification ||
                                                           x.Name == MatchInfo.BuiltIn.Author)
#pragma warning disable CS0618 // Type or member is obsolete
                                                          || x.Kind == MatchKind.SingleStartsWith));

#pragma warning restore CS0618 // Type or member is obsolete
        }
예제 #20
0
        public bool TryGetSingularInvokableMatch(out ITemplateMatchInfo template)
        {
            IReadOnlyList <ITemplateMatchInfo> invokableMatches = _coreMatchedTemplates.Where(x => x.IsInvokableMatch() &&
                                                                                              (_hasUserInputLanguage ||
                                                                                               x.DispositionOfDefaults.Count == 0 ||
                                                                                               x.DispositionOfDefaults.Any(y => y.Location == MatchLocation.DefaultLanguage && y.Kind == MatchKind.Exact))
                                                                                              )
                                                                  .ToList();

            if (invokableMatches.Count == 1)
            {
                template = invokableMatches[0];
                return(true);
            }

            // if multiple templates in the group have single starts with matches on the same parameter, it's ambiguous.
            // For the case where one template has single starts with, and another has ambiguous - on the same param:
            //      The one with single starts with is chosen as invokable because if the template with an ambiguous match
            //      was not installed, the one with the singluar invokable would be chosen.
            HashSet <string> singleStartsWithParamNames = new HashSet <string>();

            foreach (ITemplateMatchInfo checkTemplate in invokableMatches)
            {
                IList <string> singleStartParamNames = checkTemplate.MatchDisposition.Where(x => x.Location == MatchLocation.OtherParameter && x.Kind == MatchKind.SingleStartsWith).Select(x => x.ChoiceIfLocationIsOtherChoice).ToList();
                foreach (string paramName in singleStartParamNames)
                {
                    if (!singleStartsWithParamNames.Add(paramName))
                    {
                        template = null;
                        return(false);
                    }
                }
            }

            ITemplateMatchInfo highestInGroupIfSingleGroup = TemplateListResolver.FindHighestPrecedenceTemplateIfAllSameGroupIdentity(invokableMatches);

            if (highestInGroupIfSingleGroup != null)
            {
                template = highestInGroupIfSingleGroup;
                return(true);
            }

            template = null;
            return(false);
        }
예제 #21
0
        internal static bool HasMismatchOnListFilters(this ITemplateMatchInfo templateMatchInfo)
        {
            IEnumerable <string> supportedFilters = BaseListCommand.SupportedFilters.OfType <TemplateFilterOptionDefinition>().Select(f => f.MatchInfoName);

            var filterMatches = templateMatchInfo.MatchDisposition.Where(mi => supportedFilters.Any(f => f == mi.Name));
            var otherMatches  = templateMatchInfo.MatchDisposition.Where(mi => !supportedFilters.Any(f => f == mi.Name));

            if (!filterMatches.Any())
            {
                return(false);
            }
            if (otherMatches.Any(mi => mi.Kind == MatchKind.Mismatch || mi.Kind == MatchKind.InvalidName || mi.Kind == MatchKind.InvalidValue))
            {
                //there are other mismatches than on constraints
                return(false);
            }
            return(filterMatches.Any(mi => mi.Kind == MatchKind.Mismatch));
        }
예제 #22
0
        public static ITemplateMatchInfo FindHighestPrecedenceTemplateIfAllSameGroupIdentity(IReadOnlyList <ITemplateMatchInfo> templateList)
        {
            if (!AreAllTemplatesSameGroupIdentity(templateList))
            {
                return(null);
            }

            ITemplateMatchInfo highestPrecedenceTemplate = null;

            foreach (ITemplateMatchInfo template in templateList)
            {
                if (highestPrecedenceTemplate == null)
                {
                    highestPrecedenceTemplate = template;
                }
                else if (template.Info.Precedence > highestPrecedenceTemplate.Info.Precedence)
                {
                    highestPrecedenceTemplate = template;
                }
            }

            return(highestPrecedenceTemplate);
        }
예제 #23
0
        public void TestFindHighestPrecedenceTemplateIfAllSameGroupIdentity()
        {
            List <ITemplateMatchInfo> templatesToCheck = new List <ITemplateMatchInfo>();

            templatesToCheck.Add(new TemplateMatchInfo(
                                     new TemplateInfo()
            {
                Precedence    = 10,
                Name          = "Template1",
                Identity      = "Template1",
                GroupIdentity = "TestGroup"
            }
                                     , null));
            templatesToCheck.Add(new TemplateMatchInfo(
                                     new TemplateInfo()
            {
                Precedence    = 20,
                Name          = "Template2",
                Identity      = "Template2",
                GroupIdentity = "TestGroup"
            }
                                     , null));
            templatesToCheck.Add(new TemplateMatchInfo(
                                     new TemplateInfo()
            {
                Precedence    = 0,
                Name          = "Template3",
                Identity      = "Template3",
                GroupIdentity = "TestGroup"
            }));

            ITemplateMatchInfo highestPrecedenceTemplate = TemplateListResolver.FindHighestPrecedenceTemplateIfAllSameGroupIdentity(templatesToCheck);

            Assert.NotNull(highestPrecedenceTemplate);
            Assert.Equal("Template2", highestPrecedenceTemplate.Info.Identity);
            Assert.Equal(20, highestPrecedenceTemplate.Info.Precedence);
        }
예제 #24
0
        // This version is preferred, its clear which template the results are in the context of.
        public static bool ValidateRemainingParameters(ITemplateMatchInfo template, out IReadOnlyList<string> invalidParams)
        {
            invalidParams = template.GetInvalidParameterNames();

            return !invalidParams.Any();
        }
예제 #25
0
        public async Task <CreationResultStatus> InvokeTemplate(ITemplateMatchInfo templateToInvoke)
        {
            templateToInvoke.Info.Tags.TryGetValue("language", out ICacheTag language);
            bool   isMicrosoftAuthored = string.Equals(templateToInvoke.Info.Author, "Microsoft", StringComparison.OrdinalIgnoreCase);
            string framework           = null;
            string auth         = null;
            string templateName = TelemetryHelper.HashWithNormalizedCasing(templateToInvoke.Info.Identity);

            if (isMicrosoftAuthored)
            {
                _commandInput.InputTemplateParams.TryGetValue("Framework", out string inputFrameworkValue);
                framework = TelemetryHelper.HashWithNormalizedCasing(TelemetryHelper.GetCanonicalValueForChoiceParamOrDefault(templateToInvoke.Info, "Framework", inputFrameworkValue));

                _commandInput.InputTemplateParams.TryGetValue("auth", out string inputAuthValue);
                auth = TelemetryHelper.HashWithNormalizedCasing(TelemetryHelper.GetCanonicalValueForChoiceParamOrDefault(templateToInvoke.Info, "auth", inputAuthValue));
            }

            bool argsError = CheckForArgsError(templateToInvoke, out string commandParseFailureMessage);

            if (argsError)
            {
                _telemetryLogger.TrackEvent(_commandName + TelemetryConstants.CreateEventSuffix, new Dictionary <string, string>
                {
                    { TelemetryConstants.Language, language?.Choices.Keys.FirstOrDefault() },
                    { TelemetryConstants.ArgError, "True" },
                    { TelemetryConstants.Framework, framework },
                    { TelemetryConstants.TemplateName, templateName },
                    { TelemetryConstants.IsTemplateThirdParty, (!isMicrosoftAuthored).ToString() },
                    { TelemetryConstants.Auth, auth }
                });

                if (commandParseFailureMessage != null)
                {
                    Reporter.Error.WriteLine(commandParseFailureMessage.Bold().Red());
                }

                Reporter.Error.WriteLine(string.Format(LocalizableStrings.RunHelpForInformationAboutAcceptedParameters, $"{_commandName} {_commandInput.TemplateName}").Bold().Red());
                return(CreationResultStatus.InvalidParamValues);
            }
            else
            {
                bool success = true;

                try
                {
                    return(await CreateTemplateAsync(templateToInvoke).ConfigureAwait(false));
                }
                catch (ContentGenerationException cx)
                {
                    success = false;
                    Reporter.Error.WriteLine(cx.Message.Bold().Red());
                    if (cx.InnerException != null)
                    {
                        Reporter.Error.WriteLine(cx.InnerException.Message.Bold().Red());
                    }

                    return(CreationResultStatus.CreateFailed);
                }
                catch (Exception ex)
                {
                    success = false;
                    Reporter.Error.WriteLine(ex.Message.Bold().Red());
                }
                finally
                {
                    _telemetryLogger.TrackEvent(_commandName + TelemetryConstants.CreateEventSuffix, new Dictionary <string, string>
                    {
                        { TelemetryConstants.Language, language?.Choices.Keys.FirstOrDefault() },
                        { TelemetryConstants.ArgError, "False" },
                        { TelemetryConstants.Framework, framework },
                        { TelemetryConstants.TemplateName, templateName },
                        { TelemetryConstants.IsTemplateThirdParty, (!isMicrosoftAuthored).ToString() },
                        { TelemetryConstants.CreationResult, success.ToString() },
                        { TelemetryConstants.Auth, auth }
                    });
                }

                return(CreationResultStatus.CreateFailed);
            }
        }
예제 #26
0
        // Attempts to invoke the template.
        // Warning: The _commandInput cannot be assumed to be in a state that is parsed for the template being invoked.
        //      So be sure to only get template-agnostic information from it. Anything specific to the template must be gotten from the ITemplateMatchInfo
        //      Or do a reparse if necessary (currently occurs in one error case).
        private async Task <CreationResultStatus> CreateTemplateAsync(ITemplateMatchInfo templateMatchDetails)
        {
            ITemplateInfo template = templateMatchDetails.Info;

            char[] invalidChars = Path.GetInvalidFileNameChars();

            if (_commandInput?.Name != null && _commandInput.Name.IndexOfAny(invalidChars) > -1)
            {
                string printableChars    = string.Join(", ", invalidChars.Where(x => !char.IsControl(x)).Select(x => $"'{x}'"));
                string nonPrintableChars = string.Join(", ", invalidChars.Where(char.IsControl).Select(x => $"char({(int)x})"));
                Reporter.Error.WriteLine(string.Format(LocalizableStrings.InvalidNameParameter, printableChars, nonPrintableChars).Bold().Red());
                return(CreationResultStatus.CreateFailed);
            }

            string fallbackName = new DirectoryInfo(
                !string.IsNullOrWhiteSpace(_commandInput.OutputPath)
                    ? _commandInput.OutputPath
                    : Directory.GetCurrentDirectory())
                                  .Name;

            if (string.IsNullOrEmpty(fallbackName) || string.Equals(fallbackName, "/", StringComparison.Ordinal))
            {   // DirectoryInfo("/").Name on *nix returns "/", as opposed to null or "".
                fallbackName = null;
            }
            // Name returns <disk letter>:\ for root disk folder on Windows - replace invalid chars
            else if (fallbackName.IndexOfAny(invalidChars) > -1)
            {
                Regex pattern = new Regex($"[{Regex.Escape(new string(invalidChars))}]");
                fallbackName = pattern.Replace(fallbackName, "");
                if (string.IsNullOrWhiteSpace(fallbackName))
                {
                    fallbackName = null;
                }
            }

            TemplateCreationResult instantiateResult;

            try
            {
                instantiateResult = await _templateCreator.InstantiateAsync(template, _commandInput.Name, fallbackName, _commandInput.OutputPath,
                                                                            templateMatchDetails.GetValidTemplateParameters(), _commandInput.SkipUpdateCheck, _commandInput.IsForceFlagSpecified,
                                                                            _commandInput.BaselineName, _commandInput.IsDryRun)
                                    .ConfigureAwait(false);
            }
            catch (ContentGenerationException cx)
            {
                Reporter.Error.WriteLine(cx.Message.Bold().Red());
                if (cx.InnerException != null)
                {
                    Reporter.Error.WriteLine(cx.InnerException.Message.Bold().Red());
                }

                return(CreationResultStatus.CreateFailed);
            }
            catch (TemplateAuthoringException tae)
            {
                Reporter.Error.WriteLine(tae.Message.Bold().Red());
                return(CreationResultStatus.CreateFailed);
            }

            string resultTemplateName = string.IsNullOrEmpty(instantiateResult.TemplateFullName) ? _commandInput.TemplateName : instantiateResult.TemplateFullName;

            switch (instantiateResult.Status)
            {
            case CreationResultStatus.Success:
                if (!_commandInput.IsDryRun)
                {
                    Reporter.Output.WriteLine(string.Format(LocalizableStrings.CreateSuccessful, resultTemplateName));
                }
                else
                {
                    Reporter.Output.WriteLine(LocalizableStrings.FileActionsWouldHaveBeenTaken);
                    foreach (IFileChange change in instantiateResult.CreationEffects.FileChanges)
                    {
                        Reporter.Output.WriteLine($"  {change.ChangeKind}: {change.TargetRelativePath}");
                    }
                }

                if (!string.IsNullOrEmpty(template.ThirdPartyNotices))
                {
                    Reporter.Output.WriteLine(string.Format(LocalizableStrings.ThirdPartyNotices, template.ThirdPartyNotices));
                }

                HandlePostActions(instantiateResult);
                break;

            case CreationResultStatus.CreateFailed:
                Reporter.Error.WriteLine(string.Format(LocalizableStrings.CreateFailed, resultTemplateName, instantiateResult.Message).Bold().Red());
                break;

            case CreationResultStatus.MissingMandatoryParam:
                if (string.Equals(instantiateResult.Message, "--name", StringComparison.Ordinal))
                {
                    Reporter.Error.WriteLine(string.Format(LocalizableStrings.MissingRequiredParameter, instantiateResult.Message, resultTemplateName).Bold().Red());
                }
                else
                {
                    // TODO: rework to avoid having to reparse.
                    // The canonical info could be in the ITemplateMatchInfo, but currently isn't.
                    TemplateResolver.ParseTemplateArgs(template, _hostDataLoader, _commandInput);

                    IReadOnlyList <string> missingParamNamesCanonical = instantiateResult.Message.Split(new[] { ',' })
                                                                        .Select(x => _commandInput.VariantsForCanonical(x.Trim())
                                                                                .DefaultIfEmpty(x.Trim()).First())
                                                                        .ToList();
                    string fixedMessage = string.Join(", ", missingParamNamesCanonical);
                    Reporter.Error.WriteLine(string.Format(LocalizableStrings.MissingRequiredParameter, fixedMessage, resultTemplateName).Bold().Red());
                }
                break;

            case CreationResultStatus.OperationNotSpecified:
                break;

            case CreationResultStatus.NotFound:
                Reporter.Error.WriteLine(string.Format(LocalizableStrings.MissingTemplateContentDetected, _commandName).Bold().Red());
                break;

            case CreationResultStatus.InvalidParamValues:
                TemplateUsageInformation?usageInformation = TemplateUsageHelp.GetTemplateUsageInformation(template, _environment, _commandInput, _hostDataLoader, _templateCreator);

                if (usageInformation != null)
                {
                    string invalidParamsError = InvalidParameterInfo.InvalidParameterListToString(usageInformation.Value.InvalidParameters);
                    Reporter.Error.WriteLine(invalidParamsError.Bold().Red());
                    Reporter.Error.WriteLine(string.Format(LocalizableStrings.RunHelpForInformationAboutAcceptedParameters, $"{_commandName} {_commandInput.TemplateName}").Bold().Red());
                }
                else
                {
                    Reporter.Error.WriteLine(string.Format(LocalizableStrings.MissingTemplateContentDetected, _commandName).Bold().Red());
                    return(CreationResultStatus.NotFound);
                }
                break;

            default:
                break;
            }

            return(instantiateResult.Status);
        }
예제 #27
0
        internal static IReadOnlyDictionary <string, string?> GetValidTemplateParameters(this ITemplateMatchInfo templateMatchInfo)
        {
            //https://github.com/dotnet/templating/issues/2494
            //after tab completion is implemented we no longer will be using this match kind - only exact matches will be allowed
            //the method should be revised as valid parameters should be taken from command and not from match dispositionS
            return(templateMatchInfo.MatchDisposition.OfType <ParameterMatchInfo>().Where(
#pragma warning disable CS0618 // Type or member is obsolete
                       x => x.Kind == MatchKind.Exact || x.Kind == MatchKind.SingleStartsWith)
#pragma warning restore CS0618 // Type or member is obsolete
                   .ToDictionary(x => x.Name, x => x.Value));
        }
예제 #28
0
 internal static bool HasInvalidParameterName(this ITemplateMatchInfo templateMatchInfo)
 {
     return(templateMatchInfo.MatchDisposition.OfType <ParameterMatchInfo>().Any(x => x.Kind == MatchKind.InvalidName));
 }
예제 #29
0
 internal static bool HasDefaultLanguageMatch(this ITemplateMatchInfo templateMatchInfo)
 {
     return(templateMatchInfo.MatchDisposition.Any(x => x.Name == TemplateResolver.DefaultLanguageMatchParameterName && x.Kind == MatchKind.Exact));
 }
예제 #30
0
 public static bool IsNameOrContextMatch(this ITemplateMatchInfo templateMatchInfo)
 {
     return(templateMatchInfo.MatchDisposition.Any(x => (x.Location == MatchLocation.Name && x.Kind == MatchKind.Exact) ||
                                                   (x.Location == MatchLocation.Context && x.Kind == MatchKind.Exact)));
 }