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 }
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; }
internal static IEnumerable <string> GetInvalidParameterNames(this ITemplateMatchInfo templateMatchInfo) { return(templateMatchInfo.MatchDisposition .OfType <ParameterMatchInfo>() .Where(match => match.Kind == MatchKind.InvalidName) .Select(match => match.Name)); }
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); }
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); }
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)); } }
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); }
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)); }
/// <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); }
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); }
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); }
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 }
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); }
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)); }
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); }
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); }
// 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(); }
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); } }
// 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); }
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)); }
internal static bool HasInvalidParameterName(this ITemplateMatchInfo templateMatchInfo) { return(templateMatchInfo.MatchDisposition.OfType <ParameterMatchInfo>().Any(x => x.Kind == MatchKind.InvalidName)); }
internal static bool HasDefaultLanguageMatch(this ITemplateMatchInfo templateMatchInfo) { return(templateMatchInfo.MatchDisposition.Any(x => x.Name == TemplateResolver.DefaultLanguageMatchParameterName && x.Kind == MatchKind.Exact)); }
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))); }