/// <summary> /// Add a "baseHref" property in .angular-cli.json. /// </summary> /// <param name="projectDirectory"></param> /// <returns></returns> private bool ModifyAngularCliJsonFile(string projectDirectory) { const string BaseHrefPropertyName = "baseHref"; const string BaseHrefApi = "/"; const string BaseHrefMvc = "/ng/"; var projectIsMvc = Directory.Exists(Path.Combine(projectDirectory, "Views")); var projectIsRazorPages = Directory.Exists(Path.Combine(projectDirectory, "Pages")); var baseHrefPropertyValue = (projectIsMvc || projectIsRazorPages) ? BaseHrefMvc : BaseHrefApi; var filePath = Path.Combine(projectDirectory, NgWizardHelper.AngularCliJsonFileName); if (File.Exists(filePath)) { var rootObj = JObject.Parse(File.ReadAllText(filePath)); var apps = (JArray)rootObj["apps"]; if ((apps != null) && apps.Any()) { var app = (JObject)apps[0]; if (app[BaseHrefPropertyName] == null) { var knownProperty = app.Property("outDir") ?? app.Property("root"); if (knownProperty != null) { var baseHrefProperty = new JProperty(BaseHrefPropertyName, baseHrefPropertyValue); knownProperty.AddAfterSelf(baseHrefProperty); NgWizardHelper.RewriteFile(filePath, rootObj.ToString()); return(true); } } } } return(false); }
/// <summary> /// Add a "baseHref" property in angular.json (ver.6) /// </summary> /// <param name="projectDirectory"></param> /// <param name="jsonFileName"></param> /// <param name="projectName"></param> /// <returns></returns> private bool ModifyAngularJsonFile(string projectDirectory, string jsonFileName, string projectName) { const string BaseHrefPropertyName = "baseHref"; const string BaseHrefApi = "/"; const string BaseHrefMvc = "/ng/"; var projectIsMvc = Directory.Exists(Path.Combine(projectDirectory, "Views")); var projectIsRazorPages = Directory.Exists(Path.Combine(projectDirectory, "Pages")); var baseHrefPropertyValue = (projectIsMvc || projectIsRazorPages) ? BaseHrefMvc : BaseHrefApi; var filePath = Path.Combine(projectDirectory, jsonFileName); if (File.Exists(filePath)) { var rootObj = JObject.Parse(File.ReadAllText(filePath)); var parentObj = FindInsertPlace2(rootObj, projectName); if (parentObj != null) { if (parentObj[BaseHrefPropertyName] == null) { var baseHrefProperty = new JProperty(BaseHrefPropertyName, baseHrefPropertyValue); parentObj.Add(baseHrefProperty); NgWizardHelper.RewriteFile(filePath, rootObj.ToString()); return(true); } } } return(false); }
public void RunStarted(object automationObject, Dictionary <string, string> replacementsDictionary, WizardRunKind runKind, object[] customParams) { string destinationDirectory = null; string solutionDirectory = null; try { replacementsDictionary.TryGetValue("$safeprojectname$", out string projectName); replacementsDictionary.TryGetValue("$destinationdirectory$", out destinationDirectory); replacementsDictionary.TryGetValue("$solutiondirectory$", out solutionDirectory); // Test if @angular/cli is installed globally. this.isNgFound = NgWizardHelper.IsNgFound(solutionDirectory); // Display the wizard to the user. var viewModel = new NgProjectWizardViewModel(projectName, this.isNgFound); var mainWindow = new NgProjectWizardWindow(viewModel); var accepted = mainWindow.ShowDialog().GetValueOrDefault(); this.skipNpmInstall = viewModel.SkipNpmInstall; // If package.json is included in the project, the npm package manager automatically starts installing packages after project creation. replacementsDictionary.Add("$includepackagejson$", this.skipNpmInstall ? String.Empty : includePackageJsonElement); this.addRouting = viewModel.AddRouting; if (!accepted) { throw new WizardCancelledException("The wizard has been cancelled by the user."); } } catch { DateTime projectDirCreationTime = DateTime.MinValue; if (Directory.Exists(destinationDirectory)) { projectDirCreationTime = Directory.GetCreationTimeUtc(destinationDirectory); Directory.Delete(destinationDirectory, true); } if (Directory.Exists(solutionDirectory)) { // The solution could exist before the template started. // This is a poor man's method of deciding whether the solution dir was created at about the same time as the project dir. var solutionDirCreationTime = Directory.GetCreationTimeUtc(solutionDirectory); if (Math.Abs((projectDirCreationTime - solutionDirCreationTime).TotalSeconds) < 5) { Directory.Delete(solutionDirectory, true); } } throw; } }
public void RunStarted(object automationObject, Dictionary <string, string> replacementsDictionary, WizardRunKind runKind, object[] customParams) { replacementsDictionary.TryGetValue("$solutiondirectory$", out string solutionDirectory); var settings = new NgItemWizardViewModel.NgItemWizardSettings(); // Test if @angular/cli is installed globally. this.isNgFound = NgWizardHelper.IsNgFound(solutionDirectory); settings.IsNgFound = this.isNgFound; var dte = (DTE)automationObject; var activeProjects = (Array)dte.ActiveSolutionProjects; if (activeProjects.Length > 0) { var project = (Project)activeProjects.GetValue(0); // The NuGet package needs netstandard2.0. We don't support ASP.NET Core 1.x projects. settings.IsAspNetCore2 = NgWizardHelper.IsAspNetCore2(project); // Look for an existing .angular-cli.json indicating there has been already an Angular CLI app created. settings.IsAngularCliJsonFound = NgWizardHelper.FindFileInRootDir(project, NgWizardHelper.AngularCliJsonFileName); // Test if a package.json exists. settings.IsOldPackageJsonFound = NgWizardHelper.FindFileInRootDir(project, NgWizardHelper.PackageJsonFileName, out string packageJsonFilePath); // Test if an entry for "@angular/core" exists in package.json. settings.IsNpmAngularFound = NgWizardHelper.IsNpmAngularFound(packageJsonFilePath); // Automatic installation is disabled if .gitignore or package.json or tsconfig.json or Startup.cs is opened in an editor window. settings.IsGitignoreOpened = NgWizardHelper.IsFileOpened(project, NgWizardHelper.GitignoreFileName); settings.IsPackageJsonOpened = NgWizardHelper.IsFileOpened(project, NgWizardHelper.PackageJsonFileName); settings.IsStartupCsOpened = NgWizardHelper.IsFileOpened(project, NgWizardHelper.StartupCsFileName); settings.IsTsconfigJsonOpened = NgWizardHelper.IsFileOpened(project, NgWizardHelper.TsconfigJsonFileName); } // Display the wizard to the user. var viewModel = new NgItemWizardViewModel(settings); var mainWindow = new NgItemWizardWindow(viewModel); var accepted = mainWindow.ShowDialog().GetValueOrDefault(); this.installAutomatically = viewModel.InstallAutomatically; if (!accepted) { throw new WizardCancelledException("The wizard has been cancelled by the user."); } }
// This method is only called for item templates, not for project templates. public void ProjectItemFinishedGenerating(ProjectItem projectItem) { var project = projectItem.ContainingProject; if (this.installAutomatically && (project != null)) { string ngNewOutput = String.Empty; bool? ngNewSucceeded = null; bool? mergedPackageJsonFiles = null; bool? modifiedAngularCliJson = null; bool? modifiedStartupSc = null; bool? mergedGitignoreFiles = null; bool renamedTsconfigJson = false; var projectDirectory = Path.GetDirectoryName(project.FullName); if (Directory.Exists(projectDirectory)) { // Starting from ver.1.4, the CLI creates a ".gitignore" file even if the "--ignore-git" option is specified. So "ng new --ignore-git" fails if there is an existing .gitignore in the directory. // +https://github.com/angular/angular-cli/issues/7686 RenameFileIfExists(projectDirectory, NgWizardHelper.GitignoreFileName, NgWizardHelper.GitignoreTempFileName); RenameFileIfExists(projectDirectory, NgWizardHelper.PackageJsonFileName, NgWizardHelper.PackageJsonOldFileName); renamedTsconfigJson = RenameFileIfExists(projectDirectory, NgWizardHelper.TsconfigJsonFileName, NgWizardHelper.TsconfigJsonOldFileName); // Run "ng new" ngNewOutput = NgWizardHelper.RunNgNew(projectDirectory, project.Name, true, this.isNgFound); // Find the .angular-cli.json created by "ng new". ngNewSucceeded = NgWizardHelper.FindFileInRootDir(project, NgWizardHelper.AngularCliJsonFileName); if (ngNewSucceeded.Value) { mergedPackageJsonFiles = MergePackageJsonFiles(projectDirectory); modifiedAngularCliJson = ModifyAngularCliJsonFile(projectDirectory); modifiedStartupSc = ModifyStartupCsFile(projectDirectory); mergedGitignoreFiles = MergeGitignoreFile(projectDirectory); } else { // Rallback renamed files. RenameFileIfExists(projectDirectory, NgWizardHelper.GitignoreTempFileName, NgWizardHelper.GitignoreFileName); RenameFileIfExists(projectDirectory, NgWizardHelper.PackageJsonOldFileName, NgWizardHelper.PackageJsonFileName); renamedTsconfigJson = renamedTsconfigJson && !RenameFileIfExists(projectDirectory, NgWizardHelper.TsconfigJsonOldFileName, NgWizardHelper.TsconfigJsonFileName); } } // Report success/failure of the steps. var ngNewReport = (ngNewSucceeded.GetValueOrDefault() ? "An Angular CLI application was added to the project using the item template version " + NgWizardHelper.GetVersion().ToString() : "Something went wrong with the creation of an Angular CLI application." + (this.isNgFound ? LineBreak + " Error message: " + ngNewOutput : "") ) + LineBreak; var packageJsonReport = mergedPackageJsonFiles.HasValue ? "Merging the package.json files: " + GetResultText(mergedPackageJsonFiles) + LineBreak : String.Empty; var angularCliJsonReport = modifiedAngularCliJson.HasValue ? "Modifying file .angular-cli.json: " + GetResultText(modifiedAngularCliJson) + LineBreak : String.Empty; var startupCsReport = modifiedStartupSc.HasValue ? "Modifying file Startup.cs: " + GetResultText(modifiedStartupSc) + LineBreak : String.Empty; var gitignoreReport = mergedGitignoreFiles.HasValue ? "Merging the .gitignore files: " + GetResultText(mergedGitignoreFiles) + LineBreak : String.Empty; var tsconfigJsonReport = renamedTsconfigJson ? "Renaming file tsconfig.json to tsconfig.json.old: " + GetResultText(renamedTsconfigJson) + LineBreak : String.Empty; var messageText = ngNewReport + packageJsonReport + angularCliJsonReport + startupCsReport + gitignoreReport + tsconfigJsonReport + LineBreak; // Augment the item file with our message. if (projectItem.FileCount != 0) { var fileName = projectItem.FileNames[1]; // 1-based array if (File.Exists(fileName)) { var oldText = File.ReadAllText(fileName); var newText = messageText + oldText; File.WriteAllText(fileName, newText); } } } }
/// <summary> /// Try to merge and return the operation result. /// </summary> /// <param name="projectDirectory"></param> /// <returns>null/false/true = not-applicable/failure/success</returns> private static bool?MergePackageJsonFiles(string projectDirectory) { const string ScriptsName = "scripts"; const string DependenciesName = "dependencies"; const string DevDependenciesName = "devDependencies"; const string OldNameSuffix = "_old"; var filePath = Path.Combine(projectDirectory, NgWizardHelper.PackageJsonFileName); var oldFilePath = Path.Combine(projectDirectory, NgWizardHelper.PackageJsonOldFileName); if (File.Exists(oldFilePath)) { if (!File.Exists(filePath)) { return(false); } } else { return((bool?)null); } try { var oldObj = JObject.Parse(File.ReadAllText(oldFilePath)); var newObj = JObject.Parse(File.ReadAllText(filePath)); // We will give a higher priority in the three main sections to Ng, but keep the metadata properties from the old file. var resultObj = new JObject(oldObj); // The argument's content (i.e. newObj) wins over the "this" file (i.e. result). resultObj.Merge(newObj); // Clone the old content and delete the three main sections. Leave the metadata properties intact. var oObj = new JObject(oldObj); var propScr = oObj.Property(ScriptsName); if (propScr != null) { propScr.Remove(); } var propDep = oObj.Property(DependenciesName); if (propDep != null) { propDep.Remove(); } var propDev = oObj.Property(DevDependenciesName); if (propDev != null) { propDev.Remove(); } // Restore the old metadata properties. resultObj.Merge(oObj); // Add the three main sections from the old file for reference. var oScr = oldObj[ScriptsName]; var oDep = oldObj[DependenciesName]; var oDev = oldObj[DevDependenciesName]; resultObj.Property(ScriptsName).AddAfterSelf(new JProperty(ScriptsName + OldNameSuffix, oScr ?? new JObject())); resultObj.Property(DependenciesName).AddAfterSelf(new JProperty(DependenciesName + OldNameSuffix, oDep ?? new JObject())); resultObj.Property(DevDependenciesName).AddAfterSelf(new JProperty(DevDependenciesName + OldNameSuffix, oDev ?? new JObject())); NgWizardHelper.RewriteFile(filePath, resultObj.ToString()); return(true); } catch (Exception) { } return(false); }
public void ProjectFinishedGenerating(Project project) { this.project = project; string ngNewOutput = String.Empty; string readmeMdFilePath = null; // We included empty README.md and package.json to make the files discoverable by the IDE from the very beginning. // If the files were marked in the Solution Explorer as missing, opening them would take more time (??? assumption not tested) and cause flicker. // Now we are going to replace them with the real ones. var projectDirectory = Path.GetDirectoryName(project.FullName); if (Directory.Exists(projectDirectory)) { readmeMdFilePath = Path.Combine(projectDirectory, readmeMdFileName); if (File.Exists(readmeMdFilePath)) { File.Delete(readmeMdFilePath); } var packageJsonFilePath = Path.Combine(projectDirectory, packageJsonFileName); if (File.Exists(packageJsonFilePath)) { File.Delete(packageJsonFilePath); } // Starting from ver.1.4, the CLI creates a ".gitignore" file even if the "--ignore-git" option is specified. So "ng new --ignore-git" fails if there is an existing .gitignore in the directory. // +https://github.com/angular/angular-cli/issues/7686 var gitignoreFilePath = Path.Combine(projectDirectory, gitignoreFileName); var gitignoreTempFilePath = Path.Combine(projectDirectory, gitignoreTempFileName); if (File.Exists(gitignoreFilePath)) { File.Move(gitignoreFilePath, gitignoreTempFilePath); } var projectName = project.Name.Replace('.', '-').Replace('_', '-'); // Run "ng new" // ngNewOutput = RunNgNew(projectDirectory, project.Name, this.addRouting); ngNewOutput = NgWizardHelper.RunNgNew(projectDirectory, projectName, this.addRouting, this.isNgFound); if (File.Exists(gitignoreTempFilePath)) { if (File.Exists(gitignoreFilePath)) { File.Delete(gitignoreFilePath); } File.Move(gitignoreTempFilePath, gitignoreFilePath); } } // Find the file created by the "ng new". var ngNewSucceeded = File.Exists(readmeMdFilePath); var messageText = ngNewSucceeded ? String.Format(WizardResources.ReadmeSuccessMessage, project.Name, NgWizardHelper.GetVersion()) : WizardResources.ReadmeFailureMessage + ngNewOutput; ; // The Resource returns backslashes escaped. We cannot use regular 'Shift+Enter' line breakes in the editor, besause they produce "\r\n", whereas Ng-generated text has "\n", and Visual Studio Editor displays a dialog asking to normalize line breakes. messageText = messageText.Replace("\\n", "\n"); // Augment README.md with our message. if (ngNewSucceeded) { var oldText = File.ReadAllText(readmeMdFilePath); var newText = messageText + oldText; File.WriteAllText(readmeMdFilePath, newText); } else { // If the "ng new" failed, create a substitute file to display. if (readmeMdFilePath != null) { File.WriteAllText(readmeMdFilePath, messageText); } } }