private async Task <bool> PrepEnableBuildTimeConfigTransformationsForBin()
        {
            // create missing web.config and related transforms to config folder
            // also make sure that the project has the proper usingtask added (as with the case of app.config non-clickonce)

            var appcfgtype             = ProjectProperties.AppCfgType;
            var cfgfilename            = appcfgtype + ".config";
            var baseConfigFileFullPath = Path.Combine(Project.GetDirectory(), cfgfilename);
            var baseConfigFileRelPath  = FileUtilities.GetRelativePath(Project.GetDirectory(), baseConfigFileFullPath);

            if (string.IsNullOrEmpty(Project.GetConfigFile()))
            {
                baseConfigFileFullPath = Path.Combine(Project.GetDirectory(), ProjectProperties.AppCfgType + ".config");
                FileUtilities.WriteFileFromAssemblyResourceManifest(@"Transforms\{0}.config", appcfgtype, "App", baseConfigFileFullPath);
                if (await _io.ItemIsUnderSourceControl(Project.FullName))
                {
                    await _io.Add(baseConfigFileFullPath);
                }
                AddItemToProject("None", baseConfigFileRelPath);
            }
            await AddMissingTransforms(baseConfigFileFullPath);

            return(true);
        }
        private async Task <EnvDTE.Project> InjectPowerShellScriptSupport()
        {
            _logger.LogInfo("Injecting PowerShell rich execution support to project");
            if (!Project.Saved || !Project.DTE.Solution.Saved ||
                string.IsNullOrEmpty(Project.FullName) || string.IsNullOrEmpty(Project.DTE.Solution.FullName))
            {
                var saveDialogResult = MessageBox.Show(_ownerWindow, "Save pending changes to solution?",
                                                       "Save pending changes", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
                if (saveDialogResult == DialogResult.OK || saveDialogResult == DialogResult.Yes)
                {
                    _dte.SaveAll();
                }
            }
            if (!Project.Saved || !Project.DTE.Solution.Saved ||
                string.IsNullOrEmpty(Project.FullName) || string.IsNullOrEmpty(Project.DTE.Solution.FullName))
            {
                var saveDialogResult = MessageBox.Show(_ownerWindow,
                                                       "Pending changes need to be saved. Please save the project and solution before adding PowerShell build scripts, then retry.",
                                                       "Aborted", MessageBoxButtons.OKCancel, MessageBoxIcon.Asterisk);
                if (saveDialogResult != DialogResult.Cancel)
                {
                    _dte.SaveAll();
                }
                _logger.LogInfo("Project or solution is not saved. Aborting.");
                return(null);
            }

            var projRoot = Project.GetProjectRoot();

            if (projRoot.UsingTasks.Any(ut => ut.TaskName == "InvokePowerShell"))
            {
                return(Project);
            }
            var inlineTaskVersionDep_group = projRoot.AddPropertyGroup();
            var inlineTaskVersionDep_v12   = inlineTaskVersionDep_group.AddProperty("InlineTaskVersionDep", "v$(MSBuildToolsVersion)");

            inlineTaskVersionDep_v12.Condition = "'$(MSBuildToolsVersion)' == '12'";
            var inlineTaskVersionDep_v14 = inlineTaskVersionDep_group.AddProperty("InlineTaskVersionDep", "Core");

            inlineTaskVersionDep_v14.Condition = "'$(MSBuildToolsVersion)' == '14'";
            var usingTask = projRoot.AddUsingTask("InvokePowerShell",
                                                  @"$(MSBuildToolsPath)\Microsoft.Build.Tasks.$(InlineTaskVersionDep).dll", null);

            usingTask.TaskFactory = "CodeTaskFactory";
            var utParameters = usingTask.AddParameterGroup();

            var utParamsScriptFile = utParameters.AddParameter("ScriptFile");

            utParamsScriptFile.ParameterType = "System.String";
            utParamsScriptFile.Required      = "true";
            if (!projRoot.PropertyGroups.Any(pg => pg.Label == "InvokeBeforeAfter"))
            {
                var invokeBeforeAfterGroup = projRoot.AddItemGroup();
                invokeBeforeAfterGroup.Label = "InvokeBeforeAfter";
                var invokeBefore = invokeBeforeAfterGroup.AddItem("AvailableItemName", "InvokeBefore");
                invokeBefore.AddMetadata("Visible", "false");
                var invokeAfter = invokeBeforeAfterGroup.AddItem("AvailableItemName", "InvokeAfter");
                invokeAfter.AddMetadata("Visible", "false");
            }
            var psScriptsBefore = projRoot.AddTarget("PSScriptsBefore");

            psScriptsBefore.BeforeTargets = "Build";
            var invokeBeforeExec = psScriptsBefore.AddTask("InvokePowerShell");

            invokeBeforeExec.SetParameter("ScriptFile", "%(InvokeBefore.Identity)");
            invokeBeforeExec.Condition = "'@(InvokeBefore)' != ''";
            var psScriptsAfter = projRoot.AddTarget("PSScriptsAfter");

            psScriptsAfter.AfterTargets = "Build";
            var invokeAfterExec = psScriptsAfter.AddTask("InvokePowerShell");

            invokeAfterExec.SetParameter("ScriptFile", "%(InvokeAfter.Identity)");
            invokeAfterExec.Condition = "'@(InvokeAfter)' != ''";

            _projectProperties.PowerShellBuildEnabled = true;
            var projectRootPath = Project.FullName;

            Project = await Project.SaveProjectRoot();

            VsEnvironment.Dte.UnloadProject(Project);

            var projXml = File.ReadAllText(projectRootPath);
            // ReSharper disable StringIndexOfIsCultureSpecific.1
            // ReSharper disable StringIndexOfIsCultureSpecific.2
            var injectLocation = projXml.IndexOf("</UsingTask",
                                                 projXml.IndexOf("<UsingTask TaskName=\"InvokePowerShell\""));

            projXml = projXml.Substring(0, injectLocation)
                      + @"
        <Task>
        <Reference Include=""Microsoft.Build"" />
        <Reference Include=""System.Management.Automation"" />
        <Reference Include=""System.Xml"" />
        <Using Namespace=""System.Management.Automation"" />
        <Using Namespace=""System.Management.Automation.Runspaces"" />
        <Using Namespace=""Microsoft.Build.Evaluation"" />
        <Code Type=""Fragment"" Language=""cs""><![CDATA[
        if (!ScriptFile.ToLower().EndsWith("".ps1"")) return true;
        var envdir = Environment.CurrentDirectory;
        BuildEngine.LogMessageEvent(new BuildMessageEventArgs(""Executing with PowerShell: "" + ScriptFile, """", """", MessageImportance.High));
        Project project = ProjectCollection.GlobalProjectCollection.GetLoadedProjects(BuildEngine.ProjectFileOfTaskNode).FirstOrDefault()
            ?? new Project(BuildEngine.ProjectFileOfTaskNode);
        if (!ScriptFile.Contains("":"") && !ScriptFile.StartsWith(""\\\\""))
            ScriptFile = project.DirectoryPath + ""\\"" + ScriptFile;
        var pwd = Directory.GetParent(ScriptFile).FullName;
        var runspaceConfig = RunspaceConfiguration.Create();
        using (Runspace runspace = RunspaceFactory.CreateRunspace(runspaceConfig)) 
        { 
            runspace.Open();
            var vars = new System.Text.StringBuilder();
            foreach (ProjectProperty evaluatedProperty in project.AllEvaluatedProperties)
            {
                var name = evaluatedProperty.Name;
                var value = evaluatedProperty.EvaluatedValue;
                if (!string.IsNullOrWhiteSpace(name) && !string.IsNullOrWhiteSpace(value))
                {
                    if (value.ToLower() == ""true"" || value.ToLower() == ""false"") {
                        vars.AppendLine(""$"" + name + "" = $"" + value);
                    } else {
                        vars.AppendLine(""$"" + name + "" = @\""\r\n"" + value.Replace(""\"""", ""\""\"""") + ""\r\n\""@"");
                    }
                }
            }
            using (RunspaceInvoke scriptInvoker = new RunspaceInvoke(runspace)) 
            { 
                using (Pipeline pipeline = runspace.CreatePipeline()) {
                    scriptInvoker.Invoke(vars.ToString()); 
                    scriptInvoker.Invoke(""cd \"""" + pwd + ""\"""");
                    var fileName = ScriptFile.Substring(project.DirectoryPath.Length + 1);
                    pipeline.Commands.AddScript(""& \"""" + ScriptFile + ""\""""); 
                    try {
                        var results = pipeline.Invoke();
                        var sbout = new StringBuilder();
                        foreach (var result in results)
                        {
                            sbout.AppendLine(result.ToString());
                        }
                        BuildEngine.LogMessageEvent(new BuildMessageEventArgs(sbout.ToString(), """", """", MessageImportance.High));
                    } catch (Exception e) {
                        BuildEngine.LogErrorEvent(new BuildErrorEventArgs("""", """", ScriptFile, 0, 0, 0, 0, e.ToString(), """", """", DateTime.Now));
                        throw;
                    }
                }
            } 
        }
        Environment.CurrentDirectory = envdir;
        return true;
    ]]></Code>
        </Task>"
                      + projXml.Substring(injectLocation);
            if (await _io.ItemIsUnderSourceControl(projectRootPath))
            {
                await _io.Checkout(projectRootPath);
            }
            File.WriteAllText(projectRootPath, projXml);
            _logger.LogInfo("Project file is now updated.");
            VsEnvironment.Dte.ReloadJustUnloadedProject();
            return(VsEnvironment.Dte.GetProjectByFullName(projectRootPath));
        }
示例#3
0
        private async Task <EnvDTE.Project> InjectNodeJSScriptSupport()
        {
            _logger.LogInfo("Injecting NodeJS rich execution support to project");
            if (!Project.Saved || !Project.DTE.Solution.Saved ||
                string.IsNullOrEmpty(Project.FullName) || string.IsNullOrEmpty(Project.DTE.Solution.FullName))
            {
                var saveDialogResult = MessageBox.Show(_ownerWindow, "Save pending changes to solution?",
                                                       "Save pending changes", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
                if (saveDialogResult == DialogResult.OK || saveDialogResult == DialogResult.Yes)
                {
                    _dte.SaveAll();
                }
            }
            if (!Project.Saved || !Project.DTE.Solution.Saved ||
                string.IsNullOrEmpty(Project.FullName) || string.IsNullOrEmpty(Project.DTE.Solution.FullName))
            {
                var saveDialogResult = MessageBox.Show(_ownerWindow,
                                                       "Pending changes need to be saved. Please save the project and solution before adding NodeJS build scripts, then retry.",
                                                       "Aborted", MessageBoxButtons.OKCancel, MessageBoxIcon.Asterisk);
                if (saveDialogResult != DialogResult.Cancel)
                {
                    _dte.SaveAll();
                }
                _logger.LogInfo("Project or solution is not saved. Aborting.");
                return(null);
            }

            var projRoot = Project.GetProjectRoot();

            if (projRoot.UsingTasks.Any(ut => ut.TaskName == "InvokeNodeJS"))
            {
                return(Project);
            }
            var inlineTaskVersionDep_group = projRoot.AddPropertyGroup();
            var inlineTaskVersionDep_v12   = inlineTaskVersionDep_group.AddProperty("InlineTaskVersionDep", "v$(MSBuildToolsVersion)");

            inlineTaskVersionDep_v12.Condition = "'$(MSBuildToolsVersion)' == '12'";
            var inlineTaskVersionDep_v14 = inlineTaskVersionDep_group.AddProperty("InlineTaskVersionDep", "Core");

            inlineTaskVersionDep_v14.Condition = "'$(MSBuildToolsVersion)' == '14'";
            var usingTask = projRoot.AddUsingTask("InvokeNodeJS",
                                                  @"$(MSBuildToolsPath)\Microsoft.Build.Tasks.$(InlineTaskVersionDep).dll", null);

            usingTask.TaskFactory = "CodeTaskFactory";
            var utParameters = usingTask.AddParameterGroup();

            var utParamsScriptFile = utParameters.AddParameter("ScriptFile");

            utParamsScriptFile.ParameterType = "System.String";
            utParamsScriptFile.Required      = "true";
            if (!projRoot.PropertyGroups.Any(pg => pg.Label == "InvokeBeforeAfter"))
            {
                var invokeBeforeAfterGroup = projRoot.AddItemGroup();
                invokeBeforeAfterGroup.Label = "InvokeBeforeAfter";
                var invokeBefore = invokeBeforeAfterGroup.AddItem("AvailableItemName", "InvokeBefore");
                invokeBefore.AddMetadata("Visible", "false");
                var invokeAfter = invokeBeforeAfterGroup.AddItem("AvailableItemName", "InvokeAfter");
                invokeAfter.AddMetadata("Visible", "false");
            }
            var psScriptsBefore = projRoot.AddTarget("NodeJSScriptsBefore");

            psScriptsBefore.BeforeTargets = "Build";
            var invokeBeforeExec = psScriptsBefore.AddTask("InvokeNodeJS");

            invokeBeforeExec.SetParameter("ScriptFile", "%(InvokeBefore.Identity)");
            invokeBeforeExec.Condition = "'@(InvokeBefore)' != ''";
            var psScriptsAfter = projRoot.AddTarget("NodeJSScriptsAfter");

            psScriptsAfter.AfterTargets = "Build";
            var invokeAfterExec = psScriptsAfter.AddTask("InvokeNodeJS");

            invokeAfterExec.SetParameter("ScriptFile", "%(InvokeAfter.Identity)");
            invokeAfterExec.Condition = "'@(InvokeAfter)' != ''";

            _projectProperties.NodeJSBuildEnabled = true;
            var projectRootPath = Project.FullName;

            Project = await Project.SaveProjectRoot();

            VsEnvironment.Dte.UnloadProject(Project);

            var projXml = File.ReadAllText(projectRootPath);
            // ReSharper disable StringIndexOfIsCultureSpecific.1
            // ReSharper disable StringIndexOfIsCultureSpecific.2
            var injectLocation = projXml.IndexOf("</UsingTask",
                                                 projXml.IndexOf("<UsingTask TaskName=\"InvokeNodeJS\""));

            projXml = projXml.Substring(0, injectLocation)
                      + @"
        <Task>
          <Reference Include=""Microsoft.Build"" />
          <Reference Include=""System.Xml"" />
          <Using Namespace=""Microsoft.Build.Evaluation"" />
          <Using Namespace=""System.Text"" />
          <Using Namespace=""System.Text.RegularExpressions"" />
          <Using Namespace=""System.Threading"" />
          <Using Namespace=""System.IO"" />
          <Using Namespace=""System.Diagnostics"" />
          <Code Type=""Fragment"" Language=""cs""><![CDATA[

        if (!ScriptFile.ToLower().EndsWith("".js"")) return true;
        var envdir = Environment.CurrentDirectory;
        var runSuccess = true;
        BuildEngine.LogMessageEvent(new BuildMessageEventArgs(""Executing as NodeJS REPL: "" + ScriptFile, """", """", MessageImportance.High));
        Project project = ProjectCollection.GlobalProjectCollection.GetLoadedProjects(BuildEngine.ProjectFileOfTaskNode).FirstOrDefault()
            ?? new Project(BuildEngine.ProjectFileOfTaskNode);
        if (!ScriptFile.Contains("":"") && !ScriptFile.StartsWith(""\\\\""))
        ScriptFile = project.DirectoryPath + ""\\"" + ScriptFile;
        var pwd = Directory.GetParent(ScriptFile).FullName;
        var vars = new System.Text.StringBuilder();
        vars.AppendLine(""var msbuild = { properties: {} };"");
        foreach (ProjectProperty evaluatedProperty in project.AllEvaluatedProperties)
        {
            var name = evaluatedProperty.Name;
            var value = evaluatedProperty.EvaluatedValue;
            if (!string.IsNullOrWhiteSpace(name) && !string.IsNullOrWhiteSpace(value))
            {
                if (value.ToLower() == ""true"" || value.ToLower() == ""false"") {
                    vars.AppendLine(""msbuild.properties[\"""" + name + ""\""] = "" + value + "";"");
                } else {
                    vars.AppendLine(""msbuild.properties[\"""" + name + ""\""] = \"""" 
                        + value.Replace(""\\"", ""\\\\"")
                               .Replace(""\"""", ""\\\"""")
                               .Replace(""\r"", """")
                               .Replace(""\n"", ""\\n"")
                        + ""\"";"");
                }
            }
        }
        var process = new Process
        {
            StartInfo = new ProcessStartInfo
            {
                FileName = ""node.exe"",
                UseShellExecute = false,
                CreateNoWindow = true,
                RedirectStandardInput = true,
                RedirectStandardOutput = true,
                RedirectStandardError = true,
                Arguments = ""-i"",
                WorkingDirectory = pwd
            }
        };

        var loadingScript = false;
        process.OutputDataReceived += (sender, args) =>
        {
            if (!string.IsNullOrWhiteSpace(args.Data) && args.Data != ""> "" && args.Data != ""undefined"" && loadingScript)
            {
                var data = args.Data.Replace(""\r"","""").Replace(""\n"", ""\r\n"");
                while (data.StartsWith(""> "") || Regex.IsMatch(data, @""\.+ "")) {
                    if (data.StartsWith(""> "")) data = data.Substring(2);
                    if (Regex.IsMatch(data, @""\.+ "")) data = data.Substring(Regex.Match(data, @""\.+ "").ToString().Length);
                }
                if (data == ""undefined"") return;
                if (Regex.IsMatch(data, ""\\w*Error: "")) {
                    BuildEngine.LogErrorEvent(new BuildErrorEventArgs("""", """", ScriptFile, 0, 0, 0, 0, data, """", """", DateTime.Now));
                    process.EnableRaisingEvents = false; // block stack trace; sorry, no support for JS stack trace when using REPL
                    runSuccess = false;
                } else {
                    if (runSuccess) { // block stack trace; sorry, no support for JS stack trace when using REPL

                        BuildEngine.LogMessageEvent(new BuildMessageEventArgs(data, """", """", MessageImportance.High));
                    }
                }
            }
        };
        process.ErrorDataReceived += (sender, args) =>
        {
            var data = args.Data;
            if (string.IsNullOrWhiteSpace(data)) return;
            BuildEngine.LogErrorEvent(new BuildErrorEventArgs("""", """", ScriptFile, 0, 0, 0, 0, data, """", """", DateTime.Now));
            runSuccess = false;
        };
        
        process.Start();
        process.EnableRaisingEvents = true;
        process.BeginOutputReadLine();		
        process.StandardInput.WriteLine(vars.ToString());
        Thread.Sleep(250);
        loadingScript = true;
        process.StandardInput.WriteLine("".load "" + ScriptFile.Replace(""\\"", ""\\\\""));
        process.StandardInput.WriteLine(""process.exit()"");
        process.WaitForExit();

        Environment.CurrentDirectory = envdir;
        
        return runSuccess;
    ]]></Code>
        </Task>"
                      + projXml.Substring(injectLocation);
            if (await _io.ItemIsUnderSourceControl(projectRootPath))
            {
                await _io.Checkout(projectRootPath);
            }
            File.WriteAllText(projectRootPath, projXml);
            _logger.LogInfo("Project file is now updated.");
            VsEnvironment.Dte.ReloadJustUnloadedProject();
            Project = VsEnvironment.Dte.GetProjectByFullName(projectRootPath);
            return(Project);
        }