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 bool Process( IEngineEnvironmentSettings environment, IPostAction action, ICreationEffects creationEffects, ICreationResult templateCreationResult, string outputBasePath) { if (string.IsNullOrWhiteSpace(outputBasePath)) { throw new ArgumentException($"'{nameof(outputBasePath)}' cannot be null or whitespace.", nameof(outputBasePath)); } outputBasePath = Path.GetFullPath(outputBasePath); return(ProcessInternal(environment, action, creationEffects, templateCreationResult, outputBasePath)); }
public void TestLocalizedPostActionFields( int postActionIndex, string locale, string expectedDescription, string expectedManualInstructions) { _ = LoadHostWithLocalizationTemplates(out SettingsLoader settingsLoader); IReadOnlyList <TemplateInfo> localizedTemplates = settingsLoader.UserTemplateCache.GetTemplatesForLocale(locale, SettingsStore.CurrentVersion); Assert.True(localizedTemplates.Count != 0, "Test template couldn't be loaded."); TemplateInfo localizationTemplate = localizedTemplates.FirstOrDefault(t => t.Identity == "TestAssets.TemplateWithLocalization"); Assert.NotNull(localizationTemplate); ITemplate template = settingsLoader.LoadTemplate(localizationTemplate, null); Assert.NotNull(template); Assert.NotNull(template.Generator); ICreationEffects effects = template.Generator.GetCreationEffects( settingsLoader.EnvironmentSettings, template, new MockParameterSet(), settingsLoader.Components, Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()) ); Assert.NotNull(effects); Assert.NotNull(effects.CreationResult); Assert.NotNull(effects.CreationResult.PostActions); Assert.True(effects.CreationResult.PostActions.Count > postActionIndex, "Template does not contain enough post actions"); Assert.Equal(expectedDescription, effects.CreationResult.PostActions[postActionIndex].Description); Assert.Equal(expectedManualInstructions, effects.CreationResult.PostActions[postActionIndex].ManualInstructions); }
public TemplateCreationResult(string message, CreationResultStatus status, string templateFullName, ICreationResult creationOutputs, string outputBaseDir, ICreationEffects creationEffects) { Message = message; Status = status; TemplateFullName = templateFullName; ResultInfo = creationOutputs; OutputBaseDirectory = outputBaseDir; CreationEffects = creationEffects; }
protected abstract bool ProcessInternal( IEngineEnvironmentSettings environment, IPostAction action, ICreationEffects creationEffects, ICreationResult templateCreationResult, string outputBasePath);
public async Task <TemplateCreationResult> InstantiateAsync(ITemplateInfo templateInfo, string name, string fallbackName, string outputPath, IReadOnlyDictionary <string, string> inputParameters, bool skipUpdateCheck, bool forceCreation, string baselineName, bool dryRun) { // SettingsLoader.LoadTemplate is where the loc info should be read!!! // templateInfo knows enough to get at the loc, if any ITemplate template = _environmentSettings.SettingsLoader.LoadTemplate(templateInfo, baselineName); try { if (template == null) { return(new TemplateCreationResult("Could not load template", CreationResultStatus.NotFound, templateInfo.Name)); } string realName = name ?? fallbackName ?? template.DefaultName; if (string.IsNullOrEmpty(realName)) { return(new TemplateCreationResult("--name", CreationResultStatus.MissingMandatoryParam, template.Name)); } if (template.IsNameAgreementWithFolderPreferred && string.IsNullOrEmpty(outputPath)) { outputPath = name; } ICreationResult creationResult = null; string targetDir = outputPath ?? _environmentSettings.Host.FileSystem.GetCurrentDirectory(); try { if (!dryRun) { _environmentSettings.Host.FileSystem.CreateDirectory(targetDir); } Stopwatch sw = Stopwatch.StartNew(); IComponentManager componentManager = _environmentSettings.SettingsLoader.Components; // setup separate sets of parameters to be used for GetCreationEffects() and by CreateAsync(). if (!TryCreateParameterSet(template, realName, inputParameters, out IParameterSet effectParams, out TemplateCreationResult resultIfParameterCreationFailed)) { return(resultIfParameterCreationFailed); } ICreationEffects creationEffects = template.Generator.GetCreationEffects(_environmentSettings, template, effectParams, componentManager, targetDir); IReadOnlyList <IFileChange> changes = creationEffects.FileChanges; IReadOnlyList <IFileChange> destructiveChanges = changes.Where(x => x.ChangeKind != ChangeKind.Create).ToList(); if (!forceCreation && destructiveChanges.Count > 0) { if (!_environmentSettings.Host.OnPotentiallyDestructiveChangesDetected(changes, destructiveChanges)) { return(new TemplateCreationResult("Cancelled", CreationResultStatus.Cancelled, template.Name)); } } if (!TryCreateParameterSet(template, realName, inputParameters, out IParameterSet creationParams, out resultIfParameterCreationFailed)) { return(resultIfParameterCreationFailed); } if (!dryRun) { creationResult = await template.Generator.CreateAsync(_environmentSettings, template, creationParams, componentManager, targetDir).ConfigureAwait(false); } sw.Stop(); _environmentSettings.Host.LogTiming("Content generation time", sw.Elapsed, 0); return(new TemplateCreationResult(string.Empty, CreationResultStatus.Success, template.Name, creationResult, targetDir, creationEffects)); } catch (ContentGenerationException cx) { string message = cx.Message; if (cx.InnerException != null) { message += Environment.NewLine + cx.InnerException; } return(new TemplateCreationResult(message, CreationResultStatus.CreateFailed, template.Name)); } catch (Exception ex) { return(new TemplateCreationResult(ex.Message, CreationResultStatus.CreateFailed, template.Name)); } } finally { ReleaseMountPoints(template); } }
public async Task <ITemplateCreationResult> InstantiateAsync( ITemplateInfo templateInfo, string?name, string?fallbackName, string?outputPath, IReadOnlyDictionary <string, string?> inputParameters, bool forceCreation = false, string?baselineName = null, bool dryRun = false, CancellationToken cancellationToken = default) { _ = templateInfo ?? throw new ArgumentNullException(nameof(templateInfo)); inputParameters = inputParameters ?? new Dictionary <string, string?>(); cancellationToken.ThrowIfCancellationRequested(); ITemplate?template = LoadTemplate(templateInfo, baselineName); if (template == null) { return(new TemplateCreationResult(CreationResultStatus.NotFound, templateInfo.Name, LocalizableStrings.TemplateCreator_TemplateCreationResult_Error_CouldNotLoadTemplate)); } string?realName = name ?? fallbackName ?? template.DefaultName; if (string.IsNullOrWhiteSpace(realName)) { return(new TemplateCreationResult(CreationResultStatus.MissingMandatoryParam, template.Name, "--name")); } if (template.IsNameAgreementWithFolderPreferred && string.IsNullOrEmpty(outputPath)) { outputPath = name; } string targetDir = !string.IsNullOrWhiteSpace(outputPath) ? outputPath ! : _environmentSettings.Host.FileSystem.GetCurrentDirectory(); Timing contentGeneratorBlock = Timing.Over(_logger, "Template content generation"); try { ICreationResult?creationResult = null; if (!dryRun) { _environmentSettings.Host.FileSystem.CreateDirectory(targetDir); } IComponentManager componentManager = _environmentSettings.Components; // setup separate sets of parameters to be used for GetCreationEffects() and by CreateAsync(). if (!TryCreateParameterSet(template, realName !, inputParameters, out IParameterSet? effectParams, out TemplateCreationResult? resultIfParameterCreationFailed)) { //resultIfParameterCreationFailed is not null when TryCreateParameterSet is false return(resultIfParameterCreationFailed !); } if (effectParams is null) { throw new InvalidOperationException($"{nameof(effectParams)} cannot be null when {nameof(TryCreateParameterSet)} returns 'true'"); } ICreationEffects creationEffects = await template.Generator.GetCreationEffectsAsync( _environmentSettings, template, effectParams, targetDir, cancellationToken).ConfigureAwait(false); IReadOnlyList <IFileChange> changes = creationEffects.FileChanges; IReadOnlyList <IFileChange> destructiveChanges = changes.Where(x => x.ChangeKind != ChangeKind.Create).ToList(); if (!forceCreation && destructiveChanges.Count > 0) { #pragma warning disable CS0618 // Type or member is obsolete if (!_environmentSettings.Host.OnPotentiallyDestructiveChangesDetected(changes, destructiveChanges)) #pragma warning restore CS0618 // Type or member is obsolete { return(new TemplateCreationResult( CreationResultStatus.DestructiveChangesDetected, template.Name, LocalizableStrings.TemplateCreator_TemplateCreationResult_Error_DestructiveChanges, null, null, creationEffects)); } } if (!TryCreateParameterSet(template, realName !, inputParameters, out IParameterSet? creationParams, out resultIfParameterCreationFailed)) { return(resultIfParameterCreationFailed !); } if (creationParams is null) { throw new InvalidOperationException($"{nameof(creationParams)} cannot be null when {nameof(TryCreateParameterSet)} returns 'true'"); } if (!dryRun) { creationResult = await template.Generator.CreateAsync( _environmentSettings, template, creationParams, targetDir, cancellationToken).ConfigureAwait(false); } return(new TemplateCreationResult( status: CreationResultStatus.Success, templateName: template.Name, creationOutputs: creationResult, outputBaseDir: targetDir, creationEffects: creationEffects)); } catch (Exception cx) { string message = string.Join(Environment.NewLine, ExceptionMessages(cx)); return(new TemplateCreationResult( status: cx is TemplateAuthoringException ? CreationResultStatus.TemplateIssueDetected : CreationResultStatus.CreateFailed, templateName: template.Name, localizedErrorMessage: string.Format(LocalizableStrings.TemplateCreator_TemplateCreationResult_Error_CreationFailed, message), outputBaseDir: targetDir)); } finally { #pragma warning disable CS0618 // Type or member is obsolete - temporary until the method becomes internal. ReleaseMountPoints(template); #pragma warning restore CS0618 // Type or member is obsolete contentGeneratorBlock.Dispose(); } }
protected override bool ProcessInternal(IEngineEnvironmentSettings environment, IPostAction action, ICreationEffects creationEffects, ICreationResult templateCreationResult, string outputBasePath) { IReadOnlyList <string>?projectsToProcess = GetConfiguredFiles(action.Args, creationEffects, "targetFiles", outputBasePath); if (projectsToProcess is null) { //If the author didn't opt in to the new behavior by specifying "targetFiles", search for project file in current output directory or above. HashSet <string> extensionLimiters = new HashSet <string>(StringComparer.Ordinal); if (action.Args.TryGetValue("projectFileExtensions", out string?projectFileExtensions)) { if (projectFileExtensions.Contains("/") || projectFileExtensions.Contains("\\") || projectFileExtensions.Contains("*")) { // these must be literals Reporter.Error.WriteLine(LocalizableStrings.PostAction_AddReference_Error_ActionMisconfigured); return(false); } extensionLimiters.UnionWith(projectFileExtensions.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries)); } projectsToProcess = FindProjFileAtOrAbovePath(environment.Host.FileSystem, outputBasePath, extensionLimiters); if (projectsToProcess.Count > 1) { // multiple projects at the same level. Error. Reporter.Error.WriteLine(LocalizableStrings.PostAction_AddReference_Error_UnresolvedProjFile); Reporter.Error.WriteLine(LocalizableStrings.PostAction_AddReference_Error_ProjFileListHeader); foreach (string projectFile in projectsToProcess) { Reporter.Error.WriteLine(string.Format("\t{0}", projectFile)); } return(false); } } if (projectsToProcess is null || !projectsToProcess.Any()) { // no projects found. Error. Reporter.Error.WriteLine(LocalizableStrings.PostAction_AddReference_Error_UnresolvedProjFile); return(false); } bool success = true; foreach (string projectFile in projectsToProcess) { success &= AddReference(environment, action, projectFile, outputBasePath); if (!success) { return(false); } } return(true); }
protected override bool ProcessInternal(IEngineEnvironmentSettings environment, IPostAction actionConfig, ICreationEffects creationEffects, ICreationResult templateCreationResult, string outputBasePath) { if (!actionConfig.Args.TryGetValue("executable", out string?executable) || string.IsNullOrWhiteSpace(executable)) { Reporter.Error.WriteLine(LocalizableStrings.PostAction_ProcessStartProcessor_Error_ConfigMissingExecutable); return(false); } actionConfig.Args.TryGetValue("args", out string?args); bool redirectStandardOutput = true; // By default, standard out is redirected. // Only redirect when the configuration says "redirectStandardOutput = false" if (actionConfig.Args.TryGetValue("redirectStandardOutput", out string?redirectStandardOutputString) && string.Equals(redirectStandardOutputString, "false", StringComparison.OrdinalIgnoreCase)) { redirectStandardOutput = false; } bool redirectStandardError = true; // By default, standard error is redirected. // Only redirect when the configuration says "redirectStandardError = false" if (actionConfig.Args.TryGetValue("redirectStandardError", out string?redirectStandardErrorString) && string.Equals(redirectStandardErrorString, "false", StringComparison.OrdinalIgnoreCase)) { redirectStandardError = false; } try { string command = executable; if (!string.IsNullOrWhiteSpace(args)) { command = command + " " + args; } Reporter.Output.WriteLine(string.Format(LocalizableStrings.RunningCommand, command)); string resolvedExecutablePath = ResolveExecutableFilePath(environment.Host.FileSystem, executable, outputBasePath); Process?commandResult = System.Diagnostics.Process.Start(new ProcessStartInfo { RedirectStandardError = redirectStandardError, RedirectStandardOutput = redirectStandardOutput, UseShellExecute = false, CreateNoWindow = false, WorkingDirectory = outputBasePath, FileName = resolvedExecutablePath, Arguments = args }); if (commandResult == null) { Reporter.Error.WriteLine(LocalizableStrings.CommandFailed); Reporter.Verbose.WriteLine("Unable to start sub-process."); return(false); } commandResult.WaitForExit(); if (commandResult.ExitCode != 0) { Reporter.Error.WriteLine(LocalizableStrings.CommandFailed); Reporter.Error.WriteCommandOutput(commandResult); Reporter.Error.WriteLine(string.Empty); return(false); } else { Reporter.Output.WriteLine(LocalizableStrings.CommandSucceeded); return(true); } } catch (Exception ex) { Reporter.Error.WriteLine(LocalizableStrings.CommandFailed); Reporter.Error.WriteLine(ex.Message); Reporter.Error.WriteLine(string.Empty); Reporter.Verbose.WriteLine(string.Format(LocalizableStrings.Generic_Details, ex.ToString())); return(false); } }
protected override bool ProcessInternal(IEngineEnvironmentSettings environment, IPostAction actionConfig, ICreationEffects creationEffects, ICreationResult templateCreationResult, string outputBasePath) { Reporter.Output.WriteLine(string.Format(LocalizableStrings.PostActionDescription, actionConfig.Description)); Reporter.Output.WriteLine(string.Format(LocalizableStrings.PostActionInstructions, actionConfig.ManualInstructions)); if (actionConfig.Args != null && actionConfig.Args.TryGetValue("executable", out string?executable)) { actionConfig.Args.TryGetValue("args", out string?commandArgs); Reporter.Output.WriteLine(string.Format(LocalizableStrings.PostActionCommand, $"{executable} {commandArgs}").Bold().Red()); } return(true); }
protected override bool ProcessInternal(IEngineEnvironmentSettings environment, IPostAction actionConfig, ICreationEffects creationEffects, ICreationResult templateCreationResult, string outputBasePath) { bool allSucceeded = true; foreach (KeyValuePair <string, string> entry in actionConfig.Args) { string[] values; try { JArray valueArray = JArray.Parse(entry.Value); values = new string[valueArray.Count]; for (int i = 0; i < valueArray.Count; ++i) { values[i] = valueArray[i].ToString(); } } catch { values = new[] { entry.Value }; } foreach (string file in values) { try { Process?commandResult = System.Diagnostics.Process.Start(new ProcessStartInfo { RedirectStandardError = false, RedirectStandardOutput = false, UseShellExecute = false, CreateNoWindow = false, WorkingDirectory = outputBasePath, FileName = "/bin/sh", Arguments = $"-c \"chmod {entry.Key} {file}\"" }); if (commandResult == null) { Reporter.Error.WriteLine(string.Format(LocalizableStrings.UnableToSetPermissions, entry.Key, file)); Reporter.Verbose.WriteLine("Unable to start sub-process."); allSucceeded = false; continue; } commandResult.WaitForExit(); if (commandResult.ExitCode != 0) { Reporter.Error.WriteLine(string.Format(LocalizableStrings.UnableToSetPermissions, entry.Key, file)); allSucceeded = false; } } catch (Exception ex) { Reporter.Error.WriteLine(string.Format(LocalizableStrings.UnableToSetPermissions, entry.Key, file)); Reporter.Verbose.WriteLine(string.Format(LocalizableStrings.Generic_Details, ex.ToString())); allSucceeded = false; } } } return(allSucceeded); }
protected override bool ProcessInternal(IEngineEnvironmentSettings environment, IPostAction action, ICreationEffects creationEffects, ICreationResult templateCreationResult, string outputBasePath) { IReadOnlyList <string> nearestSlnFilesFound = FindSolutionFilesAtOrAbovePath(environment.Host.FileSystem, outputBasePath); if (nearestSlnFilesFound.Count != 1) { Reporter.Error.WriteLine(LocalizableStrings.PostAction_AddProjToSln_Error_NoSolutionFile); return(false); } IReadOnlyList <string>?projectFiles = GetConfiguredFiles(action.Args, creationEffects, "projectFiles", outputBasePath, (path) => Path.GetExtension(path).EndsWith("proj", StringComparison.OrdinalIgnoreCase)); if (projectFiles is null) { //If the author didn't opt in to the new behavior by specifying "projectFiles", use the old behavior if (!TryGetProjectFilesToAdd(action, templateCreationResult, outputBasePath, out projectFiles)) { Reporter.Error.WriteLine(LocalizableStrings.PostAction_AddProjToSln_Error_NoProjectsToAdd); return(false); } } if (projectFiles.Count == 0) { Reporter.Error.WriteLine(LocalizableStrings.PostAction_AddProjToSln_Error_NoProjectsToAdd); return(false); } string solutionFolder = GetSolutionFolder(action); bool succeeded = false; if (Callbacks?.AddProjectsToSolution != null) { Reporter.Output.WriteLine(string.Format(LocalizableStrings.PostAction_AddProjToSln_Running, string.Join(" ", projectFiles), nearestSlnFilesFound[0], solutionFolder)); succeeded = Callbacks.AddProjectsToSolution(nearestSlnFilesFound[0], projectFiles, solutionFolder); } if (!succeeded) { Reporter.Error.WriteLine(LocalizableStrings.PostAction_AddProjToSln_Failed); if (Callbacks?.AddProjectsToSolution == null) { Reporter.Error.WriteLine(LocalizableStrings.Generic_NoCallbackError); } return(false); } else { Reporter.Output.WriteLine(LocalizableStrings.PostAction_AddProjToSln_Succeeded); return(true); } }
protected override bool ProcessInternal(IEngineEnvironmentSettings environment, IPostAction actionConfig, ICreationEffects creationEffects, ICreationResult templateCreationResult, string outputBasePath) { bool allSucceeded = true; IEnumerable <string>?targetFiles = GetConfiguredFiles(actionConfig.Args, creationEffects, "files", outputBasePath); if (targetFiles is null || !targetFiles.Any()) { //If the author didn't opt in to the new behavior by specifying "projectFiles", use the old behavior - primary outputs if (templateCreationResult.PrimaryOutputs.Count == 0) { Reporter.Output.WriteLine(LocalizableStrings.PostAction_Restore_Error_NoProjectsToRestore); return(true); } targetFiles = templateCreationResult.PrimaryOutputs.Select(output => Path.GetFullPath(output.Path, outputBasePath)); } if (targetFiles is null || !targetFiles.Any()) { Reporter.Error.WriteLine(string.Format(LocalizableStrings.PostAction_Restore_Error_FailedToDetermineProjectToRestore)); return(false); } foreach (string pathToRestore in targetFiles) { //do not check for file existance. The restore will fail in case file doesn't exist. Reporter.Output.WriteLine(string.Format(LocalizableStrings.PostAction_Restore_Running, pathToRestore)); // Prefer to restore the project in-proc vs. creating a new process. bool succeeded = false; if (Callbacks?.RestoreProject != null) { succeeded = Callbacks.RestoreProject(pathToRestore); } if (!succeeded) { Reporter.Error.WriteLine(LocalizableStrings.PostAction_Restore_Failed); if (Callbacks?.RestoreProject == null) { Reporter.Error.WriteLine(LocalizableStrings.Generic_NoCallbackError); } allSucceeded = false; } else { Reporter.Output.WriteLine(LocalizableStrings.PostAction_Restore_Succeeded); } } return(allSucceeded); }