예제 #1
0
        public async Task <string> GenerateProject(GeneratorModel model)
        {
            var randomString = Guid.NewGuid().ToString() + DateTime.Now.Millisecond;
            var outFolder    = Path.Combine(_outPath, randomString, model.ProjectName);

            var iParams = new Dictionary <string, string> {
                { "Name", model.ProjectName }
            };

            foreach (var p in model.GetTemplateParameters())
            {
                if (p.Contains('='))
                {
                    var paramkvp = p.Split('=');
                    if (paramkvp.Length == 2)
                    {
                        iParams.Add(paramkvp[0], paramkvp[1]);
                    }
                }
                else
                {
                    iParams.Add(p, "true");
                }
            }

            if (!string.IsNullOrEmpty(model.TargetFrameworkVersion))
            {
                iParams.Add("Framework", model.TargetFrameworkVersion);
            }

            var templateShortName = string.IsNullOrEmpty(model.TemplateShortName) ? DEFAULT_TEMPLATE : model.TemplateShortName;

            TemplateInfo templateInfo = FindTemplateByShortName(templateShortName, model.TemplateVersion, EnvSettings);

            if (templateInfo == null)
            {
                throw new Exception($"Could not find template with shortName: {templateShortName} ");
            }

            TemplateCreator creator        = new TemplateCreator(EnvSettings);
            var             creationResult = await creator.InstantiateAsync(
                templateInfo : templateInfo,
                name : model.ProjectName,
                fallbackName : "SteeltoeProject",
                outputPath : outFolder,
                inputParameters : iParams,
                skipUpdateCheck : true,
                forceCreation : false,
                baselineName : "baseLine");

            if (creationResult.Status != CreationResultStatus.Success)
            {
                throw new InvalidDataException(creationResult.Message + ": " + creationResult.Status + " " + templateShortName);
            }

            return(outFolder);
        }
예제 #2
0
        private async Task <CreationResultStatus> CreateTemplateAsync(ITemplateInfo template)
        {
            string fallbackName = new DirectoryInfo(OutputPath ?? Directory.GetCurrentDirectory()).Name;
            TemplateCreationResult instantiateResult;

            try
            {
                instantiateResult = await _templateCreator.InstantiateAsync(template, Name, fallbackName, OutputPath, _app.AllTemplateParams, SkipUpdateCheck, IsForceFlagSpecified).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));
                HandlePostActions(instantiateResult);
                break;

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

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

            case CreationResultStatus.OperationNotSpecified:
                break;

            case CreationResultStatus.InvalidParamValues:
            case CreationResultStatus.NotFound:
                ShowTemplateHelp();
                break;

            default:
                break;
            }

            return(instantiateResult.Status);
        }
예제 #3
0
 public Task <TemplateCreationResult> Create(
     CustomSolutionTemplate template,
     NewProjectConfiguration config,
     IReadOnlyDictionary <string, string> parameters)
 {
     return(templateCreator.InstantiateAsync(
                template.Info,
                config.ProjectName,
                config.GetValidProjectName(),
                config.ProjectLocation,
                parameters,
                true,
                false,
                null
                ));
 }
예제 #4
0
        public async Task <CreationResult> CreateTemplate(ITemplate template, string path, string name = "")
        {
            if (template is DotNetTemplateAdaptor templateImpl)
            {
                if (string.IsNullOrEmpty(name))
                {
                    _commandInput.ResetArgs(templateImpl.DotnetTemplate.Info.ShortName, "--output", path);
                }
                else
                {
                    _commandInput.ResetArgs(templateImpl.DotnetTemplate.Info.ShortName, "--output", path, "--name", name);
                }

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

                var result = await _templateCreator.InstantiateAsync(templateImpl.DotnetTemplate.Info, _commandInput.Name, fallbackName, _commandInput.OutputPath, templateImpl.DotnetTemplate.GetValidTemplateParameters(), _commandInput.SkipUpdateCheck, _commandInput.IsForceFlagSpecified, _commandInput.BaselineName).ConfigureAwait(false);

                return((CreationResult)result.Status);
            }

            return(CreationResult.NotFound);
        }
예제 #5
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);
        }
예제 #6
0
        public async Task <ICreationResult> CreateAsync(ITemplateInfo info, string name, string outputPath, IReadOnlyDictionary <string, string> parameters, bool skipUpdateCheck, string baselineName)
        {
            TemplateCreationResult instantiateResult = await _templateCreator.InstantiateAsync(info, name, name, outputPath, parameters, skipUpdateCheck, forceCreation : false, baselineName : baselineName).ConfigureAwait(false);

            return(instantiateResult.ResultInfo);
        }
예제 #7
0
        private static int Main(string[] args)
        {
            string profileDir = GetHomeDirectory();
            string hivePath   = Path.Combine(profileDir, ".templateengine", HostName, HostVersion);

            ITemplateEngineHost host = CreateHost(HostName, HostVersion);

            EnvironmentSettings = new EngineEnvironmentSettings(host, x => new SettingsLoader(x), hivePath);
            EnvironmentSettings.SettingsLoader.Components.OfType <IIdentifiedComponent>().ToList();
            _paths = new Paths(EnvironmentSettings);

            //NOTE: With the base directory virtualized, packages cannot be installed from NuGet,
            //  only local packages and folders
            EnvironmentSettings.Host.VirtualizeDirectory(_paths.User.Content);
            EnvironmentSettings.Host.VirtualizeDirectory(_paths.User.Packages);
            _settingsLoader = (SettingsLoader)EnvironmentSettings.SettingsLoader;
            _hostDataLoader = new HostSpecificDataLoader(EnvironmentSettings.SettingsLoader);

            CommandLineParser parser = new CommandLineParser(args)
                                       .AddOptionWithConstrainedValue("--operation", new[]
            {
                "list",
                "create"
            })
                                       .AddOptionWithValue("--require")
                                       .AddOptionWithValue("--source");

            if (!parser.TryGetValues("--require", out IReadOnlyList <string> requireDirectives) ||
                !parser.TryGetSingleValue("--operation", out string operation))
            {
                Console.SetOut(Console.Error);
                Console.WriteLine("ERROR: Expected \"--require\" and/or \"--operation\" parameter.");
                return(-1);
            }

            IInstaller installer = new Installer(EnvironmentSettings);

            if (!parser.TryGetValues("--source", out IReadOnlyList <string> sources))
            {
                sources = null;
            }

            installer.InstallPackages(requireDirectives, sources?.ToList());

            //All required templates/components/lang packs have now been configured
            //Desired operation information starts at args[commandArgsStart]

            _templateCreator = new TemplateCreator(EnvironmentSettings);
            IReadOnlyList <TemplateInfo> rawTemplates = _settingsLoader.UserTemplateCache.TemplateInfo;

            var templates = new JArray();

            foreach (var rawTemplate in rawTemplates)
            {
                var template = JObject.FromObject(rawTemplate);
                template.Add("Parameters", JArray.FromObject(rawTemplate.Parameters));
                templates.Add(template);
            }


            if (string.Equals(operation, "list"))
            {
                Console.WriteLine(templates);
                return(0);
            }

            parser = parser.AddOptionWithValue("--identity");

            if (!parser.TryGetSingleValue("--identity", out string identity))
            {
                Console.SetOut(Console.Error);
                Console.WriteLine("ERROR: Expected \"--identity\" parameter.");
                return(-1);
            }

            TemplateInfo info = rawTemplates.FirstOrDefault(x => string.Equals(x.Identity, identity, StringComparison.Ordinal));

            if (info == null)
            {
                Console.SetOut(Console.Error);
                Console.WriteLine("ERROR: Failed to find template with identity \"{0}\".", identity);
                return(-1);
            }

            if (string.Equals(operation, "create"))
            {
                Dictionary <string, string> templateArgs = new Dictionary <string, string>(StringComparer.Ordinal);

                foreach (ITemplateParameter x in info.Parameters)
                {
                    if (x.DataType != null && x.DataType.StartsWith("bool", StringComparison.OrdinalIgnoreCase))
                    {
                        parser = parser.AddOptionWithBooleanValue($"--arg:{x.Name}", string.IsNullOrEmpty(x.DefaultValue) || string.Equals(x.DefaultValue, "true"));
                    }
                    else if (x.DataType != null && x.DataType.Equals("choice", StringComparison.OrdinalIgnoreCase))
                    {
                        parser = parser.AddOptionWithConstrainedValue($"--arg:{x.Name}", x.Choices.Keys.ToList());
                    }
                    else
                    {
                        parser = parser.AddOptionWithValue($"--arg:{x.Name}");
                    }

                    if (parser.TryGetSingleValue($"--arg:{x.Name}", out string val))
                    {
                        templateArgs[x.Name] = val;
                    }
                }

                TemplateCreationResult result = _templateCreator.InstantiateAsync(info, null, null, null, templateArgs, true, false, null).Result;
                if (result.Status == CreationResultStatus.Success)
                {
                    PostActionDispatcher postActionDispatcher = new PostActionDispatcher(EnvironmentSettings, result, AllowPostActionsSetting.Yes, false);
                    postActionDispatcher.Process(null);
                }

                Console.WriteLine(JObject.FromObject(result));
                return((int)result.Status);
            }

            return(0);
        }
예제 #8
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);
        }
예제 #9
0
        public async void InstantiateAsync_ParamsProperlyHonored(string?parameterValue, string expectedOutput, bool instantiateShouldFail)
        {
            //
            // Template content preparation
            //

            string sourceSnippet = @"
//#if( ChoiceParam == FirstChoice )
FIRST
//#elseif (ChoiceParam == SecondChoice )
SECOND
//#elseif (ChoiceParam == ThirdChoice )
THIRD
//#else
UNKNOWN
//#endif
";
            IDictionary <string, string?> templateSourceFiles = new Dictionary <string, string?>();

            // template.json
            templateSourceFiles.Add(TestFileSystemHelper.DefaultConfigRelativePath, TemplateConfigQuotelessLiteralsEnabled);

            //content
            templateSourceFiles.Add("sourceFile", sourceSnippet);

            //
            // Dependencies preparation and mounting
            //

            IEngineEnvironmentSettings environment = _engineEnvironmentSettings;
            string sourceBasePath = FileSystemHelpers.GetNewVirtualizedPath(environment);

            TestFileSystemHelper.WriteTemplateSource(environment, sourceBasePath, templateSourceFiles);
            IMountPoint?sourceMountPoint = TestFileSystemHelper.CreateMountPoint(environment, sourceBasePath);
            RunnableProjectGenerator rpg = new RunnableProjectGenerator();
            // cannot use SimpleConfigModel dirrectly - due to missing easy way of creating ParameterSymbols
            SimpleConfigModel configModel = SimpleConfigModel.FromJObject(JObject.Parse(TemplateConfigQuotelessLiteralsEnabled));
            var runnableConfig            = new RunnableProjectConfig(environment, rpg, configModel, sourceMountPoint.FileInfo(TestFileSystemHelper.DefaultConfigRelativePath));

            TemplateCreator creator = new TemplateCreator(_engineEnvironmentSettings);

            string targetDir = FileSystemHelpers.GetNewVirtualizedPath(_engineEnvironmentSettings);

            IReadOnlyDictionary <string, string?> parameters = new Dictionary <string, string?>()
            {
                { "ChoiceParam", parameterValue }
            };

            var res = await creator.InstantiateAsync(
                templateInfo : runnableConfig,
                name : "tst",
                fallbackName : "tst2",
                inputParameters : parameters,
                outputPath : targetDir);

            if (instantiateShouldFail)
            {
                Assert.NotNull(res.ErrorMessage);
                Assert.Null(res.OutputBaseDirectory);
            }
            else
            {
                Assert.Null(res.ErrorMessage);
                Assert.NotNull(res.OutputBaseDirectory);
                string resultContent = _engineEnvironmentSettings.Host.FileSystem
                                       .ReadAllText(Path.Combine(res.OutputBaseDirectory !, "sourceFile")).Trim();
                Assert.Equal(expectedOutput, resultContent);
            }
        }