aboutsummaryrefslogtreecommitdiff
path: root/src/internal/WixBuildTools.TestSupport/MsbuildRunner.cs
blob: ac7caf0ea0b95e14a329a12a63e494ca2d9a3f72 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.

namespace WixBuildTools.TestSupport
{
    using System;
    using System.Collections.Generic;
    using System.IO;

    public class MsbuildRunner : ExternalExecutable
    {
        private static readonly string VswhereFindArguments = "-property installationPath -version [17.0,18.0)";
        private static readonly string MsbuildCurrentRelativePath = @"MSBuild\Current\Bin\MSBuild.exe";
        private static readonly string MsbuildCurrentRelativePath64 = @"MSBuild\Current\Bin\amd64\MSBuild.exe";

        private static readonly object InitLock = new object();

        private static bool Initialized;
        private static MsbuildRunner MsbuildCurrentRunner;
        private static MsbuildRunner MsbuildCurrentRunner64;

        public static MsbuildRunnerResult Execute(string projectPath, string[] arguments = null, bool x64 = false) =>
            InitAndExecute(String.Empty, projectPath, arguments, x64);

        public static MsbuildRunnerResult ExecuteWithMsbuildCurrent(string projectPath, string[] arguments = null, bool x64 = false) =>
            InitAndExecute("Current", projectPath, arguments, x64);

        private static MsbuildRunnerResult InitAndExecute(string msbuildVersion, string projectPath, string[] arguments, bool x64)
        {
            lock (InitLock)
            {
                if (!Initialized)
                {
                    Initialized = true;
                    var vswhereResult = VswhereRunner.Execute(VswhereFindArguments, true);
                    if (vswhereResult.ExitCode != 0)
                    {
                        throw new InvalidOperationException($"Failed to execute vswhere.exe, exit code: {vswhereResult.ExitCode}. Output:\r\n{String.Join("\r\n", vswhereResult.StandardOutput)}");
                    }

                    string msbuildCurrentPath = null;
                    string msbuildCurrentPath64 = null;

                    foreach (var installPath in vswhereResult.StandardOutput)
                    {
                        if (msbuildCurrentPath == null)
                        {
                            var path = Path.Combine(installPath, MsbuildCurrentRelativePath);
                            if (File.Exists(path))
                            {
                                msbuildCurrentPath = path;
                            }
                        }

                        if (msbuildCurrentPath64 == null)
                        {
                            var path = Path.Combine(installPath, MsbuildCurrentRelativePath64);
                            if (File.Exists(path))
                            {
                                msbuildCurrentPath64 = path;
                            }
                        }
                    }

                    if (msbuildCurrentPath != null)
                    {
                        MsbuildCurrentRunner = new MsbuildRunner(msbuildCurrentPath);
                    }

                    if (msbuildCurrentPath64 != null)
                    {
                        MsbuildCurrentRunner64 = new MsbuildRunner(msbuildCurrentPath64);
                    }
                }
            }

            MsbuildRunner runner = x64 ? MsbuildCurrentRunner64 : MsbuildCurrentRunner;

            if (runner == null)
            {
                throw new InvalidOperationException($"Failed to find an installed{(x64 ? " 64-bit" : String.Empty)} MSBuild{msbuildVersion}");
            }

            return runner.ExecuteCore(projectPath, arguments);
        }

        private MsbuildRunner(string exePath) : base(exePath) { }

        private MsbuildRunnerResult ExecuteCore(string projectPath, string[] arguments)
        {
            var total = new List<string>
            {
                projectPath,
            };

            if (arguments != null)
            {
                total.AddRange(arguments);
            }

            var args = CombineArguments(total);
            var mergeErrorIntoOutput = true;
            var workingFolder = Path.GetDirectoryName(projectPath);
            var result = this.Run(args, mergeErrorIntoOutput, workingFolder);

            return new MsbuildRunnerResult
            {
                ExitCode = result.ExitCode,
                Output = result.StandardOutput,
            };
        }
    }
}