/// <summary> /// Creates the instance. /// </summary> /// <param name="host">caller <see cref="ITemplateEngineHost"/>.</param> /// <param name="virtualizeConfiguration">if true, settings will be stored in memory and will be disposed with instance.</param> /// <param name="loadDefaultComponents">if true, the default components (providers, installers, generator) will be loaded. Same as calling <see cref="LoadDefaultComponents()"/> after instance is created.</param> /// <param name="hostSettingsLocation">the file path to store host specific settings. Use null for default location. /// Note: this parameter changes only directory of host and host version specific settings. Global settings path remains unchanged.</param> public Bootstrapper(ITemplateEngineHost host, bool virtualizeConfiguration, bool loadDefaultComponents = true, string?hostSettingsLocation = null) { _host = host ?? throw new ArgumentNullException(nameof(host)); if (string.IsNullOrWhiteSpace(hostSettingsLocation)) { _engineEnvironmentSettings = new EngineEnvironmentSettings(host, virtualizeSettings: virtualizeConfiguration); } else { string hostSettingsDir = Path.Combine(hostSettingsLocation, host.HostIdentifier); string hostVersionSettingsDir = Path.Combine(hostSettingsLocation, host.HostIdentifier, host.Version); IEnvironment environment = new DefaultEnvironment(); IPathInfo pathInfo = new DefaultPathInfo(environment, host, hostSettingsDir: hostSettingsDir, hostVersionSettingsDir: hostVersionSettingsDir); _engineEnvironmentSettings = new EngineEnvironmentSettings( host, virtualizeSettings: virtualizeConfiguration, environment: environment, pathInfo: pathInfo); } _templateCreator = new TemplateCreator(_engineEnvironmentSettings); _templatePackagesManager = new Edge.Settings.TemplatePackageManager(_engineEnvironmentSettings); if (loadDefaultComponents) { LoadDefaultComponents(); } }
internal static CreationResultStatus CoordinateHelpAndUsageDisplay( TemplateListResolutionResult templateResolutionResult, IEngineEnvironmentSettings environmentSettings, INewCommandInput commandInput, IHostSpecificDataLoader hostDataLoader, ITelemetryLogger telemetryLogger, TemplateCreator templateCreator, string?defaultLanguage) { //in case only --help option is specified we don't need to show templates list if (commandInput.IsHelpFlagSpecified && string.IsNullOrEmpty(commandInput.TemplateName)) { ShowUsageHelp(commandInput, telemetryLogger); return(CreationResultStatus.Success); } // in case list is specified we always need to list templates if (commandInput.IsListFlagSpecified) { return(DisplayListOrHelpForAmbiguousTemplateGroup(templateResolutionResult, environmentSettings, commandInput, hostDataLoader, telemetryLogger, defaultLanguage)); } else // help flag specified or no flag specified { if (!string.IsNullOrEmpty(commandInput.TemplateName) && templateResolutionResult.HasUnambiguousTemplateGroup) { // This will show detailed help on the template group, which only makes sense if there is a single template group adn all templates are the same language. return(DisplayHelpForUnambiguousTemplateGroup(templateResolutionResult, environmentSettings, commandInput, hostDataLoader, templateCreator, telemetryLogger, defaultLanguage)); } else { return(DisplayListOrHelpForAmbiguousTemplateGroup(templateResolutionResult, environmentSettings, commandInput, hostDataLoader, telemetryLogger, defaultLanguage)); } } }
internal TemplateInvoker(IEngineEnvironmentSettings environment, INewCommandInput commandInput, ITelemetryLogger telemetryLogger, string commandName, Func <string> inputGetter, New3Callbacks callbacks) { _environment = environment; _commandInput = commandInput; _telemetryLogger = telemetryLogger; _commandName = commandName; _inputGetter = inputGetter; _callbacks = callbacks; _templateCreator = new TemplateCreator(_environment); _hostDataLoader = new HostSpecificDataLoader(_environment.SettingsLoader); }
internal TemplateInvoker( IEngineEnvironmentSettings environment, ITelemetryLogger telemetryLogger, Func <string> inputGetter, NewCommandCallbacks callbacks) { _environmentSettings = environment; _telemetryLogger = telemetryLogger; _inputGetter = inputGetter; _callbacks = callbacks; _templateCreator = new TemplateCreator(_environmentSettings); _postActionDispatcher = new PostActionDispatcher(_environmentSettings, _callbacks, _inputGetter); }
internal New3Command(string commandName, ITemplateEngineHost host, ITelemetryLogger telemetryLogger, New3Callbacks callbacks, INewCommandInput commandInput, string?hivePath, bool virtualize = false) { _telemetryLogger = telemetryLogger; host = new ExtendedTemplateEngineHost(host, this); EnvironmentSettings = new EngineEnvironmentSettings(host, settingsLocation: hivePath, onFirstRun: FirstRun, virtualizeSettings: virtualize); _settingsLoader = EnvironmentSettings.SettingsLoader; _templateCreator = new TemplateCreator(EnvironmentSettings); _aliasRegistry = new AliasRegistry(EnvironmentSettings); CommandName = commandName; _hostDataLoader = new HostSpecificDataLoader(EnvironmentSettings.SettingsLoader); _commandInput = commandInput; _callbacks = callbacks; if (callbacks == null) { callbacks = new New3Callbacks(); } if (!EnvironmentSettings.Host.TryGetHostParamDefault("prefs:language", out _defaultLanguage)) { _defaultLanguage = null; } }
private static TemplateGroupParameterDetails?DetermineParameterDispositionsForTemplateGroup(IReadOnlyList <ITemplateInfo> templateGroup, IEngineEnvironmentSettings environmentSettings, INewCommandInput commandInput, IHostSpecificDataLoader hostDataLoader, TemplateCreator templateCreator) { HashSet <string> groupUserParamsWithInvalidValues = new HashSet <string>(StringComparer.Ordinal); bool groupHasPostActionScriptRunner = false; List <IParameterSet> parameterSetsForAllTemplatesInGroup = new List <IParameterSet>(); IDictionary <string, InvalidParameterInfo> invalidParametersForGroup = new Dictionary <string, InvalidParameterInfo>(StringComparer.Ordinal); bool firstInList = true; Dictionary <string, IReadOnlyList <string> > defaultVariantsForCanonicals = new Dictionary <string, IReadOnlyList <string> >(StringComparer.Ordinal); Dictionary <string, IReadOnlyList <string> > groupVariantsForCanonicals = new Dictionary <string, IReadOnlyList <string> >(StringComparer.Ordinal); HashSet <string> groupUserParamsWithDefaultValues = new HashSet <string>(StringComparer.Ordinal); Dictionary <string, bool> parameterHidingDisposition = new Dictionary <string, bool>(StringComparer.OrdinalIgnoreCase); HashSet <string> parametersToAlwaysShow = new HashSet <string>(StringComparer.Ordinal); foreach (ITemplateInfo templateInfo in templateGroup.OrderByDescending(x => x.Precedence)) { TemplateUsageInformation?usageInformationNullable = TemplateUsageHelp.GetTemplateUsageInformation(templateInfo, environmentSettings, commandInput, hostDataLoader, templateCreator); if (usageInformationNullable == null) { return(null); } TemplateUsageInformation usageInformation = usageInformationNullable.Value; HostSpecificTemplateData hostSpecificTemplateData = hostDataLoader.ReadHostSpecificTemplateData(templateInfo); HashSet <string> parametersToExplicitlyHide = hostSpecificTemplateData?.HiddenParameterNames ?? new HashSet <string>(StringComparer.Ordinal); foreach (ITemplateParameter parameter in usageInformation.AllParameters.ParameterDefinitions) { //If the parameter has previously been encountered... if (parameterHidingDisposition.TryGetValue(parameter.Name, out bool isCurrentlyHidden)) { //...and it was hidden, but it's not hidden in this template in the group, // remove its hiding, otherwise leave it as is if (isCurrentlyHidden && !parametersToExplicitlyHide.Contains(parameter.Name)) { parameterHidingDisposition[parameter.Name] = false; } } else { //...otherwise, since this is the first time the parameter has been seen, // its hiding state should be used as the current disposition parameterHidingDisposition[parameter.Name] = parametersToExplicitlyHide.Contains(parameter.Name); } } if (firstInList) { invalidParametersForGroup = usageInformation.InvalidParameters.ToDictionary(x => x.Canonical, x => x); firstInList = false; } else { invalidParametersForGroup = InvalidParameterInfo.IntersectWithExisting(invalidParametersForGroup, usageInformation.InvalidParameters); } groupUserParamsWithInvalidValues.IntersectWith(usageInformation.UserParametersWithInvalidValues); // intersect because if the value is valid for any version, it's valid. groupHasPostActionScriptRunner |= usageInformation.HasPostActionScriptRunner; parameterSetsForAllTemplatesInGroup.Add(usageInformation.AllParameters); // If this template has name overrides (either long or short), it's opinionated. // If it's the first opinionated template about the param, use its variants. // Else this template is not opinionated, note its values if there aren't defaults for the param already. // At the end, anything in the default list that isn't in the opinionated list will get merged in. // TODO: write tests for this code (and the rest of this method while we're at it) foreach (KeyValuePair <string, IReadOnlyList <string> > canonicalAndVariants in usageInformation.VariantsForCanonicals) { if (hostSpecificTemplateData.LongNameOverrides.ContainsKey(canonicalAndVariants.Key) || hostSpecificTemplateData.ShortNameOverrides.ContainsKey(canonicalAndVariants.Key)) { // this template is opinionated about this parameter. If no previous template is opinionated about this param, use this template's variants. if (!groupVariantsForCanonicals.ContainsKey(canonicalAndVariants.Key)) { groupVariantsForCanonicals[canonicalAndVariants.Key] = canonicalAndVariants.Value; } } else { // this template is not opinionated about this parameter. If no previous template had defaults for this param, use this template's defaults. if (!defaultVariantsForCanonicals.ContainsKey(canonicalAndVariants.Key)) { defaultVariantsForCanonicals[canonicalAndVariants.Key] = canonicalAndVariants.Value; } } } // If any template says the user input value is the default, include it here. groupUserParamsWithDefaultValues.UnionWith(usageInformation.UserParametersWithDefaultValues); parametersToAlwaysShow.UnionWith(hostSpecificTemplateData.ParametersToAlwaysShow); } // aggregate the parameter variants foreach (KeyValuePair <string, IReadOnlyList <string> > defaultVariants in defaultVariantsForCanonicals) { if (!groupVariantsForCanonicals.ContainsKey(defaultVariants.Key)) { // there were no opinionated variants, take the preferred default. groupVariantsForCanonicals[defaultVariants.Key] = defaultVariants.Value; } } IParameterSet allGroupParameters = new TemplateGroupParameterSet(parameterSetsForAllTemplatesInGroup); string parameterErrors = InvalidParameterInfo.InvalidParameterListToString(invalidParametersForGroup.Values.ToList()); HashSet <string> parametersToHide = new HashSet <string>(parameterHidingDisposition.Where(x => x.Value).Select(x => x.Key), StringComparer.Ordinal); return(new TemplateGroupParameterDetails { AllParams = allGroupParameters, AdditionalInfo = parameterErrors, InvalidParams = groupUserParamsWithInvalidValues.ToList(), ExplicitlyHiddenParams = parametersToHide, GroupVariantsForCanonicals = groupVariantsForCanonicals, GroupUserParamsWithDefaultValues = groupUserParamsWithDefaultValues, HasPostActionScriptRunner = groupHasPostActionScriptRunner, ParametersToAlwaysShow = parametersToAlwaysShow, }); }
internal static void ShowTemplateGroupHelp(IReadOnlyCollection <ITemplateMatchInfo> templateGroup, IEngineEnvironmentSettings environmentSettings, INewCommandInput commandInput, IHostSpecificDataLoader hostDataLoader, TemplateCreator templateCreator, bool showImplicitlyHiddenParams = false) { if (templateGroup.Count == 0 || !TemplateResolver.AreAllTemplatesSameGroupIdentity(templateGroup)) { return; } IReadOnlyList <ITemplateInfo> templateInfoList = templateGroup.Select(x => x.Info).ToList(); TemplateGroupParameterDetails?groupParameterDetails = DetermineParameterDispositionsForTemplateGroup(templateInfoList, environmentSettings, commandInput, hostDataLoader, templateCreator); if (groupParameterDetails != null) { if (!string.IsNullOrEmpty(groupParameterDetails.Value.AdditionalInfo)) { Reporter.Error.WriteLine(groupParameterDetails.Value.AdditionalInfo.Bold().Red()); Reporter.Error.WriteLine(); return; } // get the input params valid for any param in the group IReadOnlyDictionary <string, string> inputTemplateParams = CoalesceInputParameterValuesFromTemplateGroup(templateGroup); ShowTemplateDetailHeaders(templateInfoList); ShowParameterHelp(inputTemplateParams, showImplicitlyHiddenParams, groupParameterDetails.Value, environmentSettings, commandInput); } else { Reporter.Error.WriteLine(string.Format(LocalizableStrings.MissingTemplateContentDetected, commandInput.CommandName).Bold().Red()); } }
internal static TemplateUsageInformation?GetTemplateUsageInformation(ITemplateInfo templateInfo, IEngineEnvironmentSettings environmentSettings, INewCommandInput commandInput, IHostSpecificDataLoader hostDataLoader, TemplateCreator templateCreator) { IParameterSet allParams; IReadOnlyList <string> userParamsWithInvalidValues; HashSet <string> userParamsWithDefaultValues; bool hasPostActionScriptRunner; ITemplate?template = environmentSettings.SettingsLoader.LoadTemplate(templateInfo, commandInput.BaselineName); if (template == null) { return(null); } TemplateResolver.ParseTemplateArgs(templateInfo, hostDataLoader, commandInput); allParams = templateCreator.SetupDefaultParamValuesFromTemplateAndHost(template, template.DefaultName ?? "testName", out IReadOnlyList <string> defaultParamsWithInvalidValues); templateCreator.ResolveUserParameters(template, allParams, commandInput.InputTemplateParams, out userParamsWithInvalidValues); hasPostActionScriptRunner = CheckIfTemplateHasScriptRunningPostActions(template, environmentSettings, commandInput, templateCreator); templateCreator.ReleaseMountPoints(template); List <InvalidParameterInfo> invalidParameters = new List <InvalidParameterInfo>(); if (userParamsWithInvalidValues.Any()) { // Lookup the input param formats - userParamsWithInvalidValues has canonical. foreach (string canonical in userParamsWithInvalidValues) { commandInput.InputTemplateParams.TryGetValue(canonical, out string specifiedValue); string inputFormat = commandInput.TemplateParamInputFormat(canonical); InvalidParameterInfo invalidParam = new InvalidParameterInfo(InvalidParameterInfo.Kind.InvalidParameterValue, inputFormat, specifiedValue, canonical); invalidParameters.Add(invalidParam); } } if (templateCreator.AnyParametersWithInvalidDefaultsUnresolved(defaultParamsWithInvalidValues, userParamsWithInvalidValues, commandInput.InputTemplateParams, out IReadOnlyList <string> defaultsWithUnresolvedInvalidValues)) { IParameterSet templateParams = template.Generator.GetParametersForTemplate(environmentSettings, template); foreach (string defaultParamName in defaultsWithUnresolvedInvalidValues) { ITemplateParameter param = templateParams.ParameterDefinitions.FirstOrDefault(x => string.Equals(x.Name, defaultParamName, StringComparison.Ordinal)); if (param != null) { // Get the best input format available. IReadOnlyList <string> inputVariants = commandInput.VariantsForCanonical(param.Name); string displayName = inputVariants.FirstOrDefault(x => x.Contains(param.Name)) ?? inputVariants.Aggregate("", (max, cur) => max.Length > cur.Length ? max : cur) ?? param.Name; InvalidParameterInfo invalidParam = new InvalidParameterInfo(InvalidParameterInfo.Kind.InvalidDefaultValue, displayName, param.DefaultValue, displayName); invalidParameters.Add(invalidParam); } } } // get all the flags // get all the user input params that have the default value Dictionary <string, IReadOnlyList <string> > inputFlagVariants = new Dictionary <string, IReadOnlyList <string> >(); userParamsWithDefaultValues = new HashSet <string>(); foreach (string paramName in allParams.ParameterDefinitions.Select(x => x.Name)) { inputFlagVariants[paramName] = commandInput.VariantsForCanonical(paramName); if (commandInput.TemplateParamHasValue(paramName) && string.IsNullOrEmpty(commandInput.TemplateParamValue(paramName))) { userParamsWithDefaultValues.Add(paramName); } } IReadOnlyDictionary <string, IReadOnlyList <string> > variantsForCanonicals = inputFlagVariants; return(new TemplateUsageInformation { InvalidParameters = invalidParameters, AllParameters = allParams, UserParametersWithInvalidValues = userParamsWithInvalidValues, UserParametersWithDefaultValues = userParamsWithDefaultValues, VariantsForCanonicals = variantsForCanonicals, HasPostActionScriptRunner = hasPostActionScriptRunner }); }
private static bool CheckIfTemplateHasScriptRunningPostActions(ITemplate template, IEngineEnvironmentSettings environmentSettings, INewCommandInput commandInput, TemplateCreator templateCreator) { // use a throwaway set of params for getting the creation effects - it makes changes to them. string targetDir = commandInput.OutputPath ?? environmentSettings.Host.FileSystem.GetCurrentDirectory(); IParameterSet paramsForCreationEffects = templateCreator.SetupDefaultParamValuesFromTemplateAndHost(template, template.DefaultName ?? "testName", out IReadOnlyList <string> throwaway); templateCreator.ResolveUserParameters(template, paramsForCreationEffects, commandInput.InputTemplateParams, out IReadOnlyList <string> userParamsWithInvalidValues); ICreationEffects creationEffects = template.Generator.GetCreationEffects(environmentSettings, template, paramsForCreationEffects, environmentSettings.SettingsLoader.Components, targetDir); return(creationEffects.CreationResult.PostActions.Any(x => x.ActionId == ProcessStartPostActionProcessor.ActionProcessorId)); }
public Bootstrapper(ITemplateEngineHost host, Action <IEngineEnvironmentSettings> onFirstRun, bool virtualizeConfiguration) { _host = host ?? throw new ArgumentNullException(nameof(host)); _engineEnvironmentSettings = new EngineEnvironmentSettings(host, virtualizeSettings: virtualizeConfiguration, onFirstRun: onFirstRun); _templateCreator = new TemplateCreator(_engineEnvironmentSettings); }
private static CreationResultStatus TemplateDetailedHelpForSingularTemplateGroup(IReadOnlyCollection <ITemplateMatchInfo> unambiguousTemplateGroup, IEngineEnvironmentSettings environmentSettings, INewCommandInput commandInput, IHostSpecificDataLoader hostDataLoader, TemplateCreator templateCreator) { // sanity check: should never happen; as condition for unambiguous template group is checked above if (!unambiguousTemplateGroup.Any()) { return(CreationResultStatus.NotFound); } GetParametersInvalidForTemplatesInList(unambiguousTemplateGroup, out IReadOnlyList <string> invalidForAllTemplates, out IReadOnlyList <string> invalidForSomeTemplates); if (invalidForAllTemplates.Count > 0 || invalidForSomeTemplates.Count > 0) { DisplayInvalidParameters(invalidForAllTemplates); DisplayParametersInvalidForSomeTemplates(invalidForSomeTemplates, LocalizableStrings.SingleTemplateGroupPartialMatchSwitchesNotValidForAllMatches); } if (invalidForAllTemplates.Count == 0) { bool showImplicitlyHiddenParams = unambiguousTemplateGroup.Count > 1; TemplateDetailsDisplay.ShowTemplateGroupHelp(unambiguousTemplateGroup, environmentSettings, commandInput, hostDataLoader, templateCreator, showImplicitlyHiddenParams); } else { string?templateHelpCommand = GetTemplateHelpCommand(commandInput.CommandName, unambiguousTemplateGroup.First().Info); if (!string.IsNullOrWhiteSpace(templateHelpCommand)) { Reporter.Error.WriteLine( string.Format(LocalizableStrings.InvalidParameterTemplateHint, templateHelpCommand).Bold().Red()); } } return(invalidForAllTemplates.Count > 0 || invalidForSomeTemplates.Count > 0 ? CreationResultStatus.InvalidParamValues : CreationResultStatus.Success); }
private static CreationResultStatus DisplayHelpForUnambiguousTemplateGroup(TemplateListResolutionResult templateResolutionResult, IEngineEnvironmentSettings environmentSettings, INewCommandInput commandInput, IHostSpecificDataLoader hostDataLoader, TemplateCreator templateCreator, ITelemetryLogger telemetryLogger, string?defaultLanguage) { // sanity check: should never happen; as condition for unambiguous template group is checked above if (!templateResolutionResult.UnambiguousTemplateGroup.Any()) { return(DisplayListOrHelpForAmbiguousTemplateGroup(templateResolutionResult, environmentSettings, commandInput, hostDataLoader, telemetryLogger, defaultLanguage)); } //if language is specified and all templates in unambigiuos group match the language show the help for that template if (templateResolutionResult.AllTemplatesInUnambiguousTemplateGroupAreSameLanguage) { IReadOnlyCollection <ITemplateMatchInfo> unambiguousTemplateGroupForDetailDisplay = templateResolutionResult.UnambiguousTemplateGroup; return(TemplateDetailedHelpForSingularTemplateGroup(unambiguousTemplateGroupForDetailDisplay, environmentSettings, commandInput, hostDataLoader, templateCreator)); } //if language is not specified and group has template that matches the language show the help for that the template that matches the language if (string.IsNullOrEmpty(commandInput.Language) && !string.IsNullOrEmpty(defaultLanguage) && templateResolutionResult.HasUnambiguousTemplateGroupForDefaultLanguage) { IReadOnlyCollection <ITemplateMatchInfo> unambiguousTemplateGroupForDetailDisplay = templateResolutionResult.UnambiguousTemplatesForDefaultLanguage; return(TemplateDetailedHelpForSingularTemplateGroup(unambiguousTemplateGroupForDetailDisplay, environmentSettings, commandInput, hostDataLoader, templateCreator)); } else { return(DisplayListOrHelpForAmbiguousTemplateGroup(templateResolutionResult, environmentSettings, commandInput, hostDataLoader, telemetryLogger, defaultLanguage)); } }