Example #1
0
        /// <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));
                }
            }
        }
Example #3
0
        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);
        }
Example #4
0
        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);
        }
Example #5
0
        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));
        }
Example #10
0
 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));
            }
        }