Example #1
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;

            string fallbackName = new DirectoryInfo(_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;
            }

            TemplateCreationResult instantiateResult;

            try
            {
                instantiateResult = await _templateCreator.InstantiateAsync(template, _commandInput.Name, fallbackName, _commandInput.OutputPath, templateMatchDetails.GetValidTemplateParameters(), _commandInput.SkipUpdateCheck, _commandInput.IsForceFlagSpecified, _commandInput.BaselineName).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) ? TemplateName : instantiateResult.TemplateFullName;

            switch (instantiateResult.Status)
            {
            case CreationResultStatus.Success:
                Reporter.Output.WriteLine(string.Format(LocalizableStrings.CreateSuccessful, resultTemplateName));

                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.
                    TemplateListResolver.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.InvalidParamValues:
                TemplateUsageInformation usageInformation = TemplateUsageHelp.GetTemplateUsageInformation(template, EnvironmentSettings, _commandInput, _hostDataLoader, _templateCreator);
                string invalidParamsError = InvalidParameterInfo.InvalidParameterListToString(usageInformation.InvalidParameters);
                Reporter.Error.WriteLine(invalidParamsError.Bold().Red());
                Reporter.Error.WriteLine(string.Format(LocalizableStrings.RunHelpForInformationAboutAcceptedParameters, $"{CommandName} {TemplateName}").Bold().Red());
                break;

            default:
                break;
            }

            return(instantiateResult.Status);
        }
Example #2
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);
        }
        private static CreationResultStatus DisplayHelpForAmbiguousTemplateGroup(TemplateListResolutionResult templateResolutionResult, IEngineEnvironmentSettings environmentSettings, INewCommandInput commandInput, IHostSpecificDataLoader hostDataLoader, ITelemetryLogger telemetryLogger, string defaultLanguage)
        {
            if (!string.IsNullOrEmpty(commandInput.TemplateName) &&
                templateResolutionResult.GetBestTemplateMatchList(true).Count > 0 &&
                templateResolutionResult.GetBestTemplateMatchList(true).All(x => x.MatchDisposition.Any(d => d.Location == MatchLocation.Language && d.Kind == MatchKind.Mismatch)))
            {
                string errorMessage = GetLanguageMismatchErrorMessage(commandInput);
                //Reporter.Error.WriteLine(errorMessage.Bold().Red());
                //Reporter.Error.WriteLine(string.Format(LocalizableStrings.RunHelpForInformationAboutAcceptedParameters, $"{commandInput.CommandName} {commandInput.TemplateName}").Bold().Red());
                return(CreationResultStatus.NotFound);
            }

            // The following occurs when:
            //      --alias <value> is specifed
            //      --help is specified
            //      template (group) can't be resolved
            if (!string.IsNullOrWhiteSpace(commandInput.Alias))
            {
                //Reporter.Error.WriteLine(LocalizableStrings.InvalidInputSwitch.Bold().Red());
                //Reporter.Error.WriteLine("  " + commandInput.TemplateParamInputFormat("--alias").Bold().Red());
                return(CreationResultStatus.NotFound);
            }

            bool hasInvalidParameters = false;
            IReadOnlyList <ITemplateMatchInfo> templatesForDisplay = templateResolutionResult.GetBestTemplateMatchList(true);

            GetParametersInvalidForTemplatesInList(templatesForDisplay, out IReadOnlyList <string> invalidForAllTemplates, out IReadOnlyList <string> invalidForSomeTemplates);
            if (invalidForAllTemplates.Any() || invalidForSomeTemplates.Any())
            {
                hasInvalidParameters = true;
                DisplayInvalidParameters(invalidForAllTemplates);
                DisplayParametersInvalidForSomeTemplates(invalidForSomeTemplates, LocalizableStrings.PartialTemplateMatchSwitchesNotValidForAllMatches);
            }

            if (commandInput.IsHelpFlagSpecified)
            {
                // usage help should show first (if it's being shown at all).
                telemetryLogger.TrackEvent(commandInput.CommandName + "-Help");
                ShowUsageHelp(commandInput);
            }

            ShowContextAndTemplateNameMismatchHelp(templateResolutionResult, commandInput.TemplateName, commandInput.TypeFilter);
            DisplayTemplateList(templatesForDisplay, environmentSettings, commandInput.Language, defaultLanguage);

            if (!commandInput.IsListFlagSpecified)
            {
                TemplateUsageHelp.ShowInvocationExamples(templateResolutionResult, hostDataLoader, commandInput.CommandName);
            }

            if (hasInvalidParameters)
            {
                return(CreationResultStatus.NotFound);
            }
            else if (commandInput.IsListFlagSpecified || commandInput.IsHelpFlagSpecified)
            {
                return(CreationResultStatus.Success);
            }
            else
            {
                return(CreationResultStatus.OperationNotSpecified);
            }
        }