├── images └── icon.png ├── NuGet ├── package.cmd └── VsIdeBuild.nuspec ├── VsIdeBuild.sln ├── VsIdeBuild ├── VsBuilderResults.cs ├── VsBuilderOptions.cs ├── MessageFilter.cs └── VsBuilder.cs ├── Properties └── AssemblyInfo.cs ├── Program.cs ├── .gitignore ├── VsIdeBuild.csproj ├── readme.md └── AVSP.ConsoleSupport ├── ConsoleHelper.cs ├── SimpleArguments.cs └── SimpleArgumentsReader.cs /images/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ninjaoxygen/VsIdeBuild/HEAD/images/icon.png -------------------------------------------------------------------------------- /NuGet/package.cmd: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | ECHO Deleting old packages... 4 | 5 | DEL /F *.nupkg 6 | 7 | SETLOCAL enabledelayedexpansion 8 | 9 | ECHO Creating packages 10 | FOR %%I IN (*.nuspec) DO ( 11 | nuget pack "%%I" 12 | IF NOT "!errorlevel!"=="0" SET ERROR=Failed to nuget pack "%%~fI" && GOTO :fail 13 | ) 14 | 15 | ECHO Success 16 | 17 | ECHO To publish to nuget use 18 | ECHO nuget push *.nupkg -Source https://api.nuget.org/v3/index.json 19 | 20 | EXIT /B 0 21 | 22 | :fail 23 | 24 | ECHO ****** Build failed! ****** 25 | ECHO %ERROR% 26 | EXIT /B 1 27 | -------------------------------------------------------------------------------- /NuGet/VsIdeBuild.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | VsIdeBuild 5 | 1.0.1 6 | ChrisPoole 7 | ChrisPoole 8 | MIT 9 | https://github.com/ninjaoxygen/VsIdeBuild 10 | images\icon.png 11 | false 12 | VsIdeBuild is a command line tool to automate the Visual Studio 2008 IDE to build solutions. 13 | Initial release 14 | Copyright 2017 - 2020 AVSP Ltd 15 | VsIdeBuild crestron simpl# simpl#pro avsp 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /VsIdeBuild.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 10.00 3 | # Visual Studio 2008 4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VsIdeBuild", "VsIdeBuild.csproj", "{4791B3F0-B02E-4F24-A33E-3C5C31E5B472}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Any CPU = Debug|Any CPU 9 | Release|Any CPU = Release|Any CPU 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {4791B3F0-B02E-4F24-A33E-3C5C31E5B472}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 13 | {4791B3F0-B02E-4F24-A33E-3C5C31E5B472}.Debug|Any CPU.Build.0 = Debug|Any CPU 14 | {4791B3F0-B02E-4F24-A33E-3C5C31E5B472}.Release|Any CPU.ActiveCfg = Release|Any CPU 15 | {4791B3F0-B02E-4F24-A33E-3C5C31E5B472}.Release|Any CPU.Build.0 = Release|Any CPU 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | EndGlobal 21 | -------------------------------------------------------------------------------- /VsIdeBuild/VsBuilderResults.cs: -------------------------------------------------------------------------------- 1 | #region License 2 | 3 | /* 4 | * File: Program.cs 5 | * 6 | * The MIT License 7 | * 8 | * Copyright © 2017 AVSP Ltd 9 | * 10 | * Permission is hereby granted, free of charge, to any person obtaining a copy 11 | * of this software and associated documentation files (the "Software"), to deal 12 | * in the Software without restriction, including without limitation the rights 13 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | * copies of the Software, and to permit persons to whom the Software is 15 | * furnished to do so, subject to the following conditions: 16 | * 17 | * The above copyright notice and this permission notice shall be included in 18 | * all copies or substantial portions of the Software. 19 | * 20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26 | * THE SOFTWARE. 27 | */ 28 | 29 | #endregion License 30 | 31 | namespace VsIdeBuild.VsBuilderLibrary 32 | { 33 | public class VsBuilderResults 34 | { 35 | public int TotalBuilds; 36 | public bool Failed; 37 | } 38 | } -------------------------------------------------------------------------------- /Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyTitle("VsIdeBuild")] 8 | [assembly: AssemblyDescription("Visual Studio 2008 Solution Builder")] 9 | [assembly: AssemblyConfiguration("")] 10 | [assembly: AssemblyCompany("AVSP Ltd")] 11 | [assembly: AssemblyProduct("VsIdeBuild")] 12 | [assembly: AssemblyCopyright("Copyright © 2017 - 2020 Chris Poole")] 13 | [assembly: AssemblyTrademark("")] 14 | [assembly: AssemblyCulture("")] 15 | 16 | // Setting ComVisible to false makes the types in this assembly not visible 17 | // to COM components. If you need to access a type in this assembly from 18 | // COM, set the ComVisible attribute to true on that type. 19 | [assembly: ComVisible(false)] 20 | 21 | // The following GUID is for the ID of the typelib if this project is exposed to COM 22 | [assembly: Guid("bb967cbb-33f0-4095-9477-0899528d0c63")] 23 | 24 | // Version information for an assembly consists of the following four values: 25 | // 26 | // Major Version 27 | // Minor Version 28 | // Build Number 29 | // Revision 30 | // 31 | // You can specify all the values or you can default the Build and Revision Numbers 32 | // by using the '*' as shown below: 33 | // [assembly: AssemblyVersion("1.0.*")] 34 | [assembly: AssemblyVersion("1.0.*")] 35 | 36 | // when AssemblyFileVersion is ommitted, it will default to the AssemblyVersion 37 | //[assembly: AssemblyFileVersion("1.0.0.0")] -------------------------------------------------------------------------------- /Program.cs: -------------------------------------------------------------------------------- 1 | #region License 2 | 3 | /* 4 | * File: Program.cs 5 | * 6 | * The MIT License 7 | * 8 | * Copyright © 2017 - 2020 AVSP Ltd 9 | * 10 | * Permission is hereby granted, free of charge, to any person obtaining a copy 11 | * of this software and associated documentation files (the "Software"), to deal 12 | * in the Software without restriction, including without limitation the rights 13 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | * copies of the Software, and to permit persons to whom the Software is 15 | * furnished to do so, subject to the following conditions: 16 | * 17 | * The above copyright notice and this permission notice shall be included in 18 | * all copies or substantial portions of the Software. 19 | * 20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26 | * THE SOFTWARE. 27 | */ 28 | 29 | #endregion License 30 | 31 | using System; 32 | using System.Diagnostics; 33 | using AVSP.ConsoleSupport; 34 | using VsIdeBuild.VsBuilderLibrary; 35 | 36 | namespace VsIdeBuild 37 | { 38 | internal class Program 39 | { 40 | private static int Run(SimpleArguments arguments) 41 | { 42 | VsBuilderOptions options = new VsBuilderOptions(); 43 | 44 | // parse command line arguments into options 45 | SimpleArgumentsReader.ArgumentsToObject(arguments, options); 46 | 47 | if (options.Solution == null || options.Solution.Length == 0) 48 | { 49 | Console.Error.WriteLine(@"ERROR: solution must be specified with -solution c:\path\to\solution.sln"); 50 | return 1; 51 | } 52 | 53 | VsBuilder builder = new VsBuilder(); 54 | 55 | int result = builder.Run(options); 56 | 57 | if ((result != 0) || builder.Results.Failed) 58 | { 59 | Console.Error.WriteLine("ERROR: some builds failed, check output"); 60 | return 1; 61 | } 62 | 63 | Console.WriteLine("Success: all okay"); 64 | return 0; 65 | } 66 | 67 | // STAThread needed for COM 68 | [STAThread] 69 | private static int Main(string[] args) 70 | { 71 | return ConsoleHelper.RunProgram(args, Run); 72 | } 73 | } 74 | } -------------------------------------------------------------------------------- /VsIdeBuild/VsBuilderOptions.cs: -------------------------------------------------------------------------------- 1 | #region License 2 | 3 | /* 4 | * File: VsBuilderOptions.cs 5 | * 6 | * The MIT License 7 | * 8 | * Copyright © 2017 - 2020 AVSP Ltd 9 | * Copyright © 2020 Oliver Hall, Ultamation Ltd 10 | * 11 | * Permission is hereby granted, free of charge, to any person obtaining a copy 12 | * of this software and associated documentation files (the "Software"), to deal 13 | * in the Software without restriction, including without limitation the rights 14 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | * copies of the Software, and to permit persons to whom the Software is 16 | * furnished to do so, subject to the following conditions: 17 | * 18 | * The above copyright notice and this permission notice shall be included in 19 | * all copies or substantial portions of the Software. 20 | * 21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | * THE SOFTWARE. 28 | */ 29 | 30 | #endregion License 31 | 32 | namespace VsIdeBuild.VsBuilderLibrary 33 | { 34 | /// 35 | /// Configuration options POCO for the VsBuilder build process 36 | /// 37 | public class VsBuilderOptions 38 | { 39 | /// 40 | /// Show the VS gui in the opened project, allow user control 41 | /// 42 | public bool Debug { get; set; } 43 | 44 | /// 45 | /// Clean is only available for the entire solution 46 | /// 47 | public bool Clean { get; set; } 48 | 49 | /// 50 | /// Perform additional checks to ensure the Crestron SDK plugin loaded and completed 51 | /// 52 | public bool Crestron { get; set; } 53 | 54 | /// 55 | /// Build Solution in every available configuration 56 | /// 57 | public bool BuildAll { get; set; } 58 | 59 | /// 60 | /// Limit build to a single solution configuration, e.g. Debug, Release 61 | /// 62 | public string BuildSolutionConfiguration { get; set; } 63 | 64 | /// 65 | /// Limit build to a single project - BuildSolutionConfiguration MUST also be specified 66 | /// 67 | public string BuildProject { get; set; } 68 | 69 | /// 70 | /// Output ProjectContexts, useful to get necessary command lines for build 71 | /// 72 | public bool ShowProjectContexts { get; set; } 73 | 74 | /// 75 | /// Output ProjectOutputs, useful to get configuration information 76 | /// 77 | public bool ShowProjectOutputs { get; set; } 78 | 79 | /// 80 | /// Give detailed build output 81 | /// 82 | public bool ShowBuild { get; set; } 83 | 84 | /// 85 | /// Filepath of Visual Studio 2008 solution file 86 | /// 87 | public string Solution { get; set; } 88 | } 89 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.sln.docstates 8 | 9 | # Build results 10 | [Dd]ebug/ 11 | [Dd]ebugPublic/ 12 | [Rr]elease/ 13 | [Rr]eleases/ 14 | x64/ 15 | x86/ 16 | build/ 17 | bld/ 18 | [Bb]in/ 19 | [Oo]bj/ 20 | 21 | # Roslyn cache directories 22 | *.ide/ 23 | 24 | # MSTest test Results 25 | [Tt]est[Rr]esult*/ 26 | [Bb]uild[Ll]og.* 27 | 28 | #NUNIT 29 | *.VisualState.xml 30 | TestResult.xml 31 | 32 | # Build Results of an ATL Project 33 | [Dd]ebugPS/ 34 | [Rr]eleasePS/ 35 | dlldata.c 36 | 37 | *_i.c 38 | *_p.c 39 | *_i.h 40 | *.ilk 41 | *.meta 42 | *.obj 43 | *.pch 44 | *.pdb 45 | *.pgc 46 | *.pgd 47 | *.rsp 48 | *.sbr 49 | *.tlb 50 | *.tli 51 | *.tlh 52 | *.tmp 53 | *.tmp_proj 54 | *.log 55 | *.vspscc 56 | *.vssscc 57 | .builds 58 | *.pidb 59 | *.svclog 60 | *.scc 61 | 62 | # Chutzpah Test files 63 | _Chutzpah* 64 | 65 | # Visual C++ cache files 66 | ipch/ 67 | *.aps 68 | *.ncb 69 | *.opensdf 70 | *.sdf 71 | *.cachefile 72 | 73 | # Visual Studio profiler 74 | *.psess 75 | *.vsp 76 | *.vspx 77 | 78 | # TFS 2012 Local Workspace 79 | $tf/ 80 | 81 | # Guidance Automation Toolkit 82 | *.gpState 83 | 84 | # ReSharper is a .NET coding add-in 85 | _ReSharper*/ 86 | *.[Rr]e[Ss]harper 87 | *.DotSettings.user 88 | 89 | # JustCode is a .NET coding addin-in 90 | .JustCode 91 | 92 | # TeamCity is a build add-in 93 | _TeamCity* 94 | 95 | # DotCover is a Code Coverage Tool 96 | *.dotCover 97 | 98 | # NCrunch 99 | _NCrunch_* 100 | .*crunch*.local.xml 101 | 102 | # MightyMoose 103 | *.mm.* 104 | AutoTest.Net/ 105 | 106 | # Web workbench (sass) 107 | .sass-cache/ 108 | 109 | # Installshield output folder 110 | [Ee]xpress/ 111 | 112 | # DocProject is a documentation generator add-in 113 | DocProject/buildhelp/ 114 | DocProject/Help/*.HxT 115 | DocProject/Help/*.HxC 116 | DocProject/Help/*.hhc 117 | DocProject/Help/*.hhk 118 | DocProject/Help/*.hhp 119 | DocProject/Help/Html2 120 | DocProject/Help/html 121 | 122 | # Click-Once directory 123 | publish/ 124 | 125 | # Publish Web Output 126 | *.[Pp]ublish.xml 127 | *.azurePubxml 128 | # TODO: Comment out the next line if you want to keep your passwords hidden 129 | *.pubxml 130 | 131 | # NuGet Packages 132 | *.nupkg 133 | # The packages folder can be ignored because of Package Restore 134 | **/packages/* 135 | # except build/, which is used as an MSBuild target. 136 | !**/packages/build/ 137 | # If using the old MSBuild-Integrated Package Restore, uncomment this: 138 | #!**/packages/repositories.config 139 | 140 | # Windows Azure Build Output 141 | csx/ 142 | *.build.csdef 143 | 144 | # Windows Store app package directory 145 | AppPackages/ 146 | 147 | # Others 148 | sql/ 149 | *.Cache 150 | ClientBin/ 151 | [Ss]tyle[Cc]op.* 152 | ~$* 153 | *~ 154 | *.dbmdl 155 | *.dbproj.schemaview 156 | *.pfx 157 | *.publishsettings 158 | node_modules/ 159 | 160 | # RIA/Silverlight projects 161 | Generated_Code/ 162 | 163 | # Backup & report files from converting an old project file 164 | # to a newer Visual Studio version. Backup files are not needed, 165 | # because we have git ;-) 166 | _UpgradeReport_Files/ 167 | Backup*/ 168 | UpgradeLog*.XML 169 | UpgradeLog*.htm 170 | 171 | # SQL Server files 172 | *.mdf 173 | *.ldf 174 | 175 | # Business Intelligence projects 176 | *.rdl.data 177 | *.bim.layout 178 | *.bim_*.settings 179 | 180 | # Microsoft Fakes 181 | FakesAssemblies/ 182 | -------------------------------------------------------------------------------- /VsIdeBuild/MessageFilter.cs: -------------------------------------------------------------------------------- 1 | #region License 2 | 3 | /* 4 | * File: MessageFilter.cs 5 | * 6 | * Derived from Microsoft sample code, see below for source 7 | * 8 | * Used under MICROSOFT LIMITED PUBLIC LICENSE 9 | * 10 | */ 11 | 12 | #endregion License 13 | 14 | using System; 15 | using System.Runtime.InteropServices; 16 | 17 | namespace VsIdeBuild.VsBuilderLibrary 18 | { 19 | /// 20 | /// See "How to: Fix 'Application is Busy' and 'Call was Rejected By Callee' Errors" 21 | /// https://msdn.microsoft.com/en-us/library/ms228772.aspx 22 | /// 23 | 24 | internal class MessageFilter : IOleMessageFilter 25 | { 26 | // 27 | // Class containing the IOleMessageFilter 28 | // thread error-handling functions. 29 | 30 | // Start the filter. 31 | public static void Register() 32 | { 33 | IOleMessageFilter newFilter = new MessageFilter(); 34 | IOleMessageFilter oldFilter = null; 35 | CoRegisterMessageFilter(newFilter, out oldFilter); 36 | } 37 | 38 | // Done with the filter, close it. 39 | public static void Revoke() 40 | { 41 | IOleMessageFilter oldFilter = null; 42 | CoRegisterMessageFilter(null, out oldFilter); 43 | } 44 | 45 | // 46 | // IOleMessageFilter functions. 47 | // Handle incoming thread requests. 48 | int IOleMessageFilter.HandleInComingCall(int dwCallType, 49 | System.IntPtr hTaskCaller, int dwTickCount, System.IntPtr 50 | lpInterfaceInfo) 51 | { 52 | //Return the flag SERVERCALL_ISHANDLED. 53 | return 0; 54 | } 55 | 56 | // Thread call was rejected, so try again. 57 | int IOleMessageFilter.RetryRejectedCall(System.IntPtr 58 | hTaskCallee, int dwTickCount, int dwRejectType) 59 | { 60 | if (dwRejectType == 2) 61 | // flag = SERVERCALL_RETRYLATER. 62 | { 63 | // Retry the thread call immediately if return >=0 & 64 | // <100. 65 | return 99; 66 | } 67 | // Too busy; cancel call. 68 | return -1; 69 | } 70 | 71 | int IOleMessageFilter.MessagePending(System.IntPtr hTaskCallee, 72 | int dwTickCount, int dwPendingType) 73 | { 74 | //Return the flag PENDINGMSG_WAITDEFPROCESS. 75 | return 2; 76 | } 77 | 78 | // Implement the IOleMessageFilter interface. 79 | [DllImport("Ole32.dll")] 80 | private static extern int 81 | CoRegisterMessageFilter(IOleMessageFilter newFilter, out 82 | IOleMessageFilter oldFilter); 83 | } 84 | 85 | [ComImport(), Guid("00000016-0000-0000-C000-000000000046"), 86 | InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)] 87 | internal interface IOleMessageFilter 88 | { 89 | [PreserveSig] 90 | int HandleInComingCall( 91 | int dwCallType, 92 | IntPtr hTaskCaller, 93 | int dwTickCount, 94 | IntPtr lpInterfaceInfo); 95 | 96 | [PreserveSig] 97 | int RetryRejectedCall( 98 | IntPtr hTaskCallee, 99 | int dwTickCount, 100 | int dwRejectType); 101 | 102 | [PreserveSig] 103 | int MessagePending( 104 | IntPtr hTaskCallee, 105 | int dwTickCount, 106 | int dwPendingType); 107 | } 108 | } -------------------------------------------------------------------------------- /VsIdeBuild.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Debug 5 | AnyCPU 6 | 9.0.30729 7 | 2.0 8 | {4791B3F0-B02E-4F24-A33E-3C5C31E5B472} 9 | Exe 10 | Properties 11 | VsIdeBuild 12 | VsIdeBuild 13 | v3.5 14 | 512 15 | 16 | 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | pdbonly 27 | true 28 | bin\Release\ 29 | TRACE 30 | prompt 31 | 4 32 | 33 | 34 | 35 | False 36 | ..\..\..\..\..\Program Files (x86)\Microsoft Visual Studio 9.0\Common7\IDE\PublicAssemblies\EnvDTE.dll 37 | 38 | 39 | False 40 | ..\..\..\..\..\Program Files (x86)\Microsoft Visual Studio 9.0\Common7\IDE\PublicAssemblies\EnvDTE80.dll 41 | 42 | 43 | False 44 | ..\..\..\..\..\Program Files (x86)\Microsoft Visual Studio 9.0\Common7\IDE\PublicAssemblies\EnvDTE90.dll 45 | 46 | 47 | 48 | 3.5 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 73 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # VsIdeBuild 2 | 3 | ## About 4 | 5 | VsIdeBuild is a command line tool to automate the Visual Studio 2008 IDE to build solutions. 6 | This is necessary when GUI IDE plugins are required for the build process, for example when using Crestron's SDK. 7 | 8 | ## Downloads 9 | 10 | The latest binary release is available as a nuget package from https://www.nuget.org/packages/VsIdeBuild/ 11 | 12 | Other release binaries are available from https://github.com/ninjaoxygen/VsIdeBuild/releases 13 | 14 | ## Contact 15 | 16 | E-mail: chris@avsp.co.uk 17 | 18 | ## Copyright 19 | 20 | VsIdeBuild is Copyright (C) 2017 - 2020 AVSP Ltd 21 | 22 | ## Contributors 23 | 24 | Many thanks for contributions from: 25 | 26 | Oliver Hall, Ultamation Ltd 27 | 28 | ## Command line parameters: 29 | 30 | ~~~ 31 | -Solution 32 | Specify Visual Studio 2008 .sln file to work on. Relative or absolute paths are acceptable, the .sln can be omitted. 33 | 34 | -Clean 35 | Cleans before build. This does not work with BuildProject - VS2008 only supports simple cleaning of enitre solution configurations. 36 | 37 | -BuildAll 38 | Builds all solution configurations, using their project build settings for each configuration. 39 | 40 | -BuildSolutionConfiguration 41 | Build a single solution configuration, e.g. Debug or Release. 42 | 43 | -BuildProject 44 | Build a single project, also needs -BuildSolutionConfiguration to be specified. 45 | 46 | -ShowProjectContexts 47 | Outputs all available project names and configurations. 48 | 49 | -ShowProjectOutputs 50 | Outputs all properties of all projects in the solution 51 | 52 | -ShowBuild 53 | Returns all build output from VS2008 and the Crestron SDK plugin, sandbox failures will show up here 54 | 55 | -Debug 56 | Will not hide the Visual Studio window that is opened, will allow user interaction with that window. 57 | 58 | -Crestron 59 | Enable checks to ensure the Crestron SDK plugin intialised and completed. Without this option, only Crestron sandbox failures will be detected. 60 | ~~~ 61 | 62 | ## Examples 63 | 64 | Build only the Debug configuration of project ConsoleApp in Sample.sln 65 | ~~~ 66 | VsIdeBuild -Solution "C:\Test\Sample.sln" -BuildSolutionConfiguration "Debug" -BuildProject "ConsoleApp" 67 | ~~~ 68 | 69 | Clean then build all configurations of all projects in Sample.sln 70 | ~~~ 71 | VsIdeBuild -Solution "C:\Test\Sample.sln" -Clean -BuildAll 72 | ~~~ 73 | 74 | ## Return value 75 | 76 | 0 on success 77 | 78 | >=1 on failure 79 | 80 | ## License 81 | 82 | The MIT License 83 | 84 | Copyright (C) 2017 - 2020 AVSP Ltd 85 | 86 | Permission is hereby granted, free of charge, to any person obtaining a copy 87 | of this software and associated documentation files (the "Software"), to deal 88 | in the Software without restriction, including without limitation the rights 89 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 90 | copies of the Software, and to permit persons to whom the Software is 91 | furnished to do so, subject to the following conditions: 92 | 93 | The above copyright notice and this permission notice shall be included in 94 | all copies or substantial portions of the Software. 95 | 96 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 97 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 98 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 99 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 100 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 101 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 102 | THE SOFTWARE. 103 | -------------------------------------------------------------------------------- /AVSP.ConsoleSupport/ConsoleHelper.cs: -------------------------------------------------------------------------------- 1 | #region License 2 | 3 | /* 4 | * File: ConsoleHelper.cs 5 | * 6 | * The MIT License 7 | * 8 | * Copyright © 2017 AVSP Ltd 9 | * 10 | * Permission is hereby granted, free of charge, to any person obtaining a copy 11 | * of this software and associated documentation files (the "Software"), to deal 12 | * in the Software without restriction, including without limitation the rights 13 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | * copies of the Software, and to permit persons to whom the Software is 15 | * furnished to do so, subject to the following conditions: 16 | * 17 | * The above copyright notice and this permission notice shall be included in 18 | * all copies or substantial portions of the Software. 19 | * 20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26 | * THE SOFTWARE. 27 | */ 28 | 29 | #endregion License 30 | 31 | using System; 32 | using System.Collections.Generic; 33 | using System.Diagnostics; 34 | using System.Reflection; 35 | 36 | namespace AVSP.ConsoleSupport 37 | { 38 | /// 39 | /// Console support library for banner, copyright, version, command line arguments 40 | /// 41 | internal static class ConsoleHelper 42 | { 43 | public delegate int RunFunction(SimpleArguments arguments); 44 | 45 | public static SimpleArguments Arguments { get; private set; } 46 | 47 | /// 48 | /// Runs a console app with parsed options, sensible exit codes, exception handler 49 | /// 50 | /// Example: 51 | /// private static int Main(string[] args) 52 | /// { 53 | /// return ConsoleHelper.RunProgram(args, Run); 54 | /// } 55 | /// 56 | /// arguments from Main() 57 | /// delegate to run app 58 | /// program exit code 59 | public static int RunProgram(IList args, RunFunction run) 60 | { 61 | try 62 | { 63 | ConsoleHelper.Startup(args); 64 | ConsoleHelper.WriteBanner(); 65 | 66 | int returnValue = run(ConsoleHelper.Arguments); 67 | 68 | return (Environment.ExitCode == 0) ? returnValue : Environment.ExitCode; 69 | } 70 | catch (Exception e) 71 | { 72 | Console.Error.WriteLine(e.Message); 73 | Trace.TraceError(e.ToString()); 74 | 75 | return Environment.ExitCode != 0 76 | ? Environment.ExitCode : 100; 77 | } 78 | } 79 | 80 | public static void Startup(IList args) 81 | { 82 | Arguments = new SimpleArguments(args); 83 | 84 | // enable trace with v parameter 85 | if (Arguments.GetFlag("v")) 86 | { 87 | Trace.Listeners.Add(new ConsoleTraceListener(true)); 88 | } 89 | } 90 | 91 | public static string GetProductVersion() 92 | { 93 | return Assembly.GetExecutingAssembly().GetName().Version.ToString(); 94 | } 95 | 96 | public static string GetProductName() 97 | { 98 | return Assembly.GetExecutingAssembly().GetName().Name; 99 | } 100 | 101 | public static string GetDescription() 102 | { 103 | //Type of attribute that is desired 104 | Type type = typeof(AssemblyDescriptionAttribute); 105 | 106 | //Is there an attribute of this type already defined? 107 | if (AssemblyDescriptionAttribute.IsDefined(Assembly.GetExecutingAssembly(), type)) 108 | { 109 | //if there is, get attribute of desired type 110 | AssemblyDescriptionAttribute assemblyDescriptionAttribute = (AssemblyDescriptionAttribute)AssemblyDescriptionAttribute.GetCustomAttribute(Assembly.GetExecutingAssembly(), type); 111 | 112 | return assemblyDescriptionAttribute.Description; 113 | } 114 | 115 | return null; 116 | } 117 | 118 | public static string GetCopyright() 119 | { 120 | //Type of attribute that is desired 121 | Type type = typeof(AssemblyCopyrightAttribute); 122 | 123 | //Is there an attribute of this type already defined? 124 | if (AssemblyCopyrightAttribute.IsDefined(Assembly.GetExecutingAssembly(), type)) 125 | { 126 | //if there is, get attribute of desired type 127 | AssemblyCopyrightAttribute assemblyCopyrightAttribute = (AssemblyCopyrightAttribute)AssemblyCopyrightAttribute.GetCustomAttribute(Assembly.GetExecutingAssembly(), type); 128 | 129 | return assemblyCopyrightAttribute.Copyright; 130 | } 131 | 132 | return null; 133 | } 134 | 135 | public static void WriteBanner() 136 | { 137 | Console.WriteLine(GetProductName() + " v" + GetProductVersion()); 138 | Console.WriteLine(GetCopyright()); 139 | Console.WriteLine(); 140 | } 141 | } 142 | } -------------------------------------------------------------------------------- /AVSP.ConsoleSupport/SimpleArguments.cs: -------------------------------------------------------------------------------- 1 | #region License 2 | 3 | /* 4 | * File: SimpleArguments.cs 5 | * 6 | * The MIT License 7 | * 8 | * Copyright © 2017 AVSP Ltd 9 | * 10 | * Permission is hereby granted, free of charge, to any person obtaining a copy 11 | * of this software and associated documentation files (the "Software"), to deal 12 | * in the Software without restriction, including without limitation the rights 13 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | * copies of the Software, and to permit persons to whom the Software is 15 | * furnished to do so, subject to the following conditions: 16 | * 17 | * The above copyright notice and this permission notice shall be included in 18 | * all copies or substantial portions of the Software. 19 | * 20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26 | * THE SOFTWARE. 27 | */ 28 | 29 | #endregion License 30 | 31 | using System; 32 | using System.Collections.Generic; 33 | using System.Collections.ObjectModel; 34 | using System.Linq; 35 | 36 | namespace AVSP.ConsoleSupport 37 | { 38 | /// 39 | /// Handles sets of arguments specified with a - and an optional parameter for each argument when no dash given 40 | /// 41 | public class SimpleArguments 42 | { 43 | protected Dictionary argumentValues = new Dictionary(); 44 | protected Dictionary flags = new Dictionary(); 45 | 46 | public ReadOnlyCollection Arguments { get; protected set; } 47 | 48 | public SimpleArguments() 49 | { 50 | Arguments = new List().AsReadOnly(); 51 | } 52 | 53 | /// 54 | /// Constructor which parses command line arguments 55 | /// 56 | /// Args array from Program.Main() 57 | public SimpleArguments(IList args) 58 | { 59 | Parse(args); 60 | } 61 | 62 | /// 63 | /// Set default value for an argument, will not create a flag 64 | /// 65 | /// Name of argument to set value for 66 | /// Value to set argument to 67 | public void SetDefault(string argumentName, string value) 68 | { 69 | if (!argumentValues.ContainsKey(argumentName)) 70 | { 71 | argumentValues[argumentName] = value; 72 | } 73 | } 74 | 75 | /// 76 | /// Parse a list of argument values, e.g. { "-argumentname", "argumentvalue", "-flagtoset" } 77 | /// 78 | /// List of arguments to parse 79 | public void Parse(IList args) 80 | { 81 | // list of non-option arguments 82 | List arguments = new List(); 83 | 84 | string lastArgumentName = null; 85 | 86 | foreach (string arg in args) 87 | { 88 | if (arg.StartsWith("-")) 89 | { 90 | lastArgumentName = arg.Substring(1).ToLower(); 91 | flags[lastArgumentName] = true; 92 | } 93 | else 94 | { 95 | if (lastArgumentName != null && lastArgumentName.Length > 0) 96 | { 97 | argumentValues[lastArgumentName] = arg; 98 | lastArgumentName = null; 99 | } 100 | else 101 | { 102 | arguments.Add(arg); 103 | } 104 | } 105 | } 106 | 107 | Arguments = arguments.AsReadOnly(); 108 | } 109 | 110 | /// 111 | /// Get the value of a passed argument, or the default 112 | /// 113 | /// Name of argument to set value for 114 | /// string value of argument 115 | public string GetValue(string argumentName) 116 | { 117 | string value; 118 | 119 | argumentValues.TryGetValue(argumentName.ToLower(), out value); 120 | 121 | return value; 122 | } 123 | 124 | /// 125 | /// Get whether a flag was passed 126 | /// 127 | /// Name of argument to check for 128 | /// true when argument was passed 129 | public bool GetFlag(string argumentName) 130 | { 131 | return flags.ContainsKey(argumentName.ToLower()); 132 | } 133 | 134 | /// 135 | /// Get list of values in a comma-separated option 136 | /// 137 | /// argument to retrieve 138 | /// list of string contained in argument 139 | public IEnumerable GetList(string argumentName) 140 | { 141 | string value; 142 | char[] charSplit = new char[] { ',' }; 143 | 144 | if (argumentValues.TryGetValue(argumentName.ToLower(), out value)) 145 | { 146 | return value.Split(charSplit, StringSplitOptions.RemoveEmptyEntries); 147 | } 148 | 149 | return Enumerable.Empty(); 150 | } 151 | } 152 | } -------------------------------------------------------------------------------- /AVSP.ConsoleSupport/SimpleArgumentsReader.cs: -------------------------------------------------------------------------------- 1 | #region License 2 | 3 | /* 4 | * File: SimpleArgumentsReader.cs 5 | * 6 | * The MIT License 7 | * 8 | * Copyright © 2017 AVSP Ltd 9 | * 10 | * Permission is hereby granted, free of charge, to any person obtaining a copy 11 | * of this software and associated documentation files (the "Software"), to deal 12 | * in the Software without restriction, including without limitation the rights 13 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | * copies of the Software, and to permit persons to whom the Software is 15 | * furnished to do so, subject to the following conditions: 16 | * 17 | * The above copyright notice and this permission notice shall be included in 18 | * all copies or substantial portions of the Software. 19 | * 20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26 | * THE SOFTWARE. 27 | */ 28 | 29 | #endregion License 30 | 31 | using System; 32 | using System.Collections.Generic; 33 | using System.Diagnostics; 34 | using System.Reflection; 35 | 36 | namespace AVSP.ConsoleSupport 37 | { 38 | /// 39 | /// Reads arguments into POCOs, supports fields or properties of int, string, int[], string[], other type may work too 40 | /// 41 | public static class SimpleArgumentsReader 42 | { 43 | private static Type boolType = typeof(bool); 44 | 45 | /// 46 | /// Read a set of command line arguments into the properties or fields in a POCO 47 | /// 48 | /// source list of command line arguments, like the array from Main() 49 | /// destination POCO to set values in 50 | public static void ArgumentsToObject(IList args, object value) 51 | { 52 | SimpleArguments arguments = new SimpleArguments(args); 53 | ArgumentsToObject(arguments, value); 54 | } 55 | 56 | /// 57 | /// Read set of parsed SimpleArguments into the properties or fields in a POCO 58 | /// 59 | /// SimpleArguments objects with source values 60 | /// 61 | public static void ArgumentsToObject(SimpleArguments arguments, object value) 62 | { 63 | char[] commaSplit = new char[] { ',' }; 64 | 65 | Type t = value.GetType(); 66 | 67 | FieldInfo[] fields = t.GetFields(BindingFlags.Public | BindingFlags.Instance); 68 | 69 | foreach (FieldInfo field in fields) 70 | { 71 | MemberInfo m = field; 72 | 73 | try 74 | { 75 | if (field.FieldType == boolType) 76 | { 77 | field.SetValue(value, arguments.GetFlag(field.Name)); 78 | } 79 | else 80 | { 81 | string valueString = arguments.GetValue(field.Name); 82 | 83 | if (valueString != null) 84 | { 85 | field.SetValue(value, Convert.ChangeType(valueString, field.FieldType)); 86 | } 87 | } 88 | } 89 | catch (Exception ex) 90 | { 91 | throw new ArgumentException("ERROR: exception occurred whilst parsing argument " + field.Name, ex); 92 | } 93 | } 94 | 95 | PropertyInfo[] properties = t.GetProperties(BindingFlags.Public | BindingFlags.Instance); 96 | 97 | foreach (PropertyInfo property in properties) 98 | { 99 | try 100 | { 101 | if (property.PropertyType == boolType) 102 | { 103 | // handle a normal bool, if the flag was passed, set it to true, if not, false 104 | property.SetValue(value, arguments.GetFlag(property.Name), null); 105 | } 106 | else if (property.PropertyType.BaseType.FullName == "System.Array") 107 | { 108 | // handle comma separated arrays 109 | string valueString = arguments.GetValue(property.Name); 110 | 111 | if (valueString != null) 112 | { 113 | string[] valueStringArray = valueString.Split(commaSplit); 114 | 115 | int arrayLength = valueStringArray.Length; 116 | 117 | Type elementType = property.PropertyType.GetElementType(); 118 | 119 | // build the array 120 | Array y = Array.CreateInstance(elementType, arrayLength); 121 | 122 | for (int i = 0; i < arrayLength; i++) 123 | { 124 | // set an element 125 | y.SetValue(Convert.ChangeType(valueStringArray[i], elementType), i); 126 | } 127 | 128 | // put the array into the property 129 | property.SetValue(value, y, null); 130 | } 131 | } 132 | else 133 | { 134 | string valueString = arguments.GetValue(property.Name); 135 | 136 | if (valueString != null) 137 | { 138 | property.SetValue(value, Convert.ChangeType(valueString, property.PropertyType), null); 139 | } 140 | } 141 | } 142 | catch (Exception ex) 143 | { 144 | throw new ArgumentException("ERROR: exception occurred whilst parsing argument " + property.Name, ex); 145 | } 146 | } 147 | } 148 | } 149 | } -------------------------------------------------------------------------------- /VsIdeBuild/VsBuilder.cs: -------------------------------------------------------------------------------- 1 | #region License 2 | 3 | /* 4 | * File: VsBuilder.cs 5 | * 6 | * The MIT License 7 | * 8 | * Copyright © 2017 - 2020 AVSP Ltd 9 | * Copyright © 2020 Oliver Hall, Ultamation Ltd 10 | * 11 | * Permission is hereby granted, free of charge, to any person obtaining a copy 12 | * of this software and associated documentation files (the "Software"), to deal 13 | * in the Software without restriction, including without limitation the rights 14 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | * copies of the Software, and to permit persons to whom the Software is 16 | * furnished to do so, subject to the following conditions: 17 | * 18 | * The above copyright notice and this permission notice shall be included in 19 | * all copies or substantial portions of the Software. 20 | * 21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | * THE SOFTWARE. 28 | */ 29 | 30 | #endregion License 31 | 32 | using System; 33 | using System.IO; 34 | using EnvDTE; 35 | using EnvDTE80; 36 | 37 | namespace VsIdeBuild.VsBuilderLibrary 38 | { 39 | public class VsBuilder 40 | { 41 | /// 42 | /// Build log message we look for to indicate sandbox failure 43 | /// 44 | private const string crestronSandboxFailureMessage = "was not prepared"; 45 | private const string crestronPluginStart = "Preparing SIMPL # Project"; 46 | private const string crestronPluginSuccess = "Prepared for use on a Crestron control system"; 47 | 48 | private object visualStudio; 49 | private DTE dte; 50 | private DTE2 dte2; 51 | private Solution sln; 52 | private VsBuilderOptions options; 53 | 54 | /// 55 | /// After calling Run, Results will contain build counts and fail counts 56 | /// 57 | public VsBuilderResults Results { get; private set; } 58 | 59 | /// 60 | /// Build solution as specified in options 61 | /// 62 | /// Build configuration options 63 | /// 64 | public int Run(VsBuilderOptions options) 65 | { 66 | int returnValue = 0; 67 | 68 | this.options = options; 69 | this.Results = new VsBuilderResults(); 70 | 71 | Console.WriteLine("Opening Visual Studio 2008..."); 72 | OpenVS(); 73 | 74 | dte.SuppressUI = !options.Debug; 75 | dte.UserControl = options.Debug; 76 | 77 | // Resolve the solution absolute filepath 78 | string absSolutionFilePath = ResolveSolutionName(options.Solution); 79 | 80 | if (!File.Exists(absSolutionFilePath)) 81 | { 82 | Console.WriteLine("Solution file not found"); 83 | return 1; 84 | } 85 | 86 | Console.WriteLine("Opening Solution..."); 87 | if (!OpenSolution(absSolutionFilePath)) 88 | { 89 | Console.WriteLine("Solution could not be opened"); 90 | return 2; 91 | } 92 | 93 | #if DEBUG 94 | Console.WriteLine("Solution.Count = " + sln.Count); 95 | 96 | Console.WriteLine("Projects Names..."); 97 | foreach (Project project in dte.Solution.Projects) 98 | { 99 | Console.WriteLine("Project: " + project.Name); 100 | } 101 | #endif 102 | 103 | if (options.ShowProjectContexts) 104 | { 105 | Console.WriteLine("Showing project contexts..."); 106 | Console.WriteLine(GetProjectContexts()); 107 | } 108 | 109 | if (options.ShowProjectOutputs) 110 | { 111 | Console.WriteLine("Showing project outputs..."); 112 | ShowProjectOutputs(); 113 | } 114 | 115 | if (options.BuildAll) 116 | { 117 | BuildAll(); 118 | } 119 | else 120 | { 121 | if (options.BuildSolutionConfiguration != null) 122 | { 123 | if (options.BuildProject != null) 124 | { 125 | string projUniqueName = GetProjectUniqueName(options.BuildProject); 126 | 127 | if (string.IsNullOrEmpty(projUniqueName)) 128 | { 129 | Console.WriteLine("ERROR: The specified project was not found in the solution."); 130 | returnValue = 1; 131 | } 132 | else 133 | BuildProject(options.BuildSolutionConfiguration, projUniqueName); 134 | } 135 | else 136 | { 137 | BuildSolutionConfiguration(options.BuildSolutionConfiguration); 138 | } 139 | } 140 | else 141 | { 142 | Console.WriteLine("ERROR: neither BuildAll or BuildSolutionConfiguration was specified"); 143 | returnValue = 1; 144 | } 145 | } 146 | 147 | if (options.ShowBuild) 148 | { 149 | string buildOutput = GetOutputWindowText("Build"); 150 | 151 | if (!string.IsNullOrEmpty(buildOutput)) 152 | { 153 | Console.WriteLine("Build Output:"); 154 | 155 | string[] buildLines = buildOutput.Split('\n'); 156 | 157 | foreach (string line in buildLines) 158 | { 159 | Console.WriteLine(line); 160 | } 161 | } 162 | else 163 | { 164 | Console.WriteLine("Build Output: None"); 165 | } 166 | } 167 | 168 | Console.WriteLine("Closing Solution..."); 169 | CloseSolution(); 170 | 171 | Console.WriteLine("Closing Visual Studio..."); 172 | CloseVS(); 173 | 174 | return returnValue; 175 | } 176 | 177 | private void PostBuildChecks() 178 | { 179 | if (sln.SolutionBuild.LastBuildInfo != 0) 180 | { 181 | Console.WriteLine("ERROR: some projects failed to build!"); 182 | Results.Failed = true; 183 | return; 184 | } 185 | 186 | // Crestron SDK does not report sandbox failure as a failed build, because it is in a post-build step, so detect it separately 187 | string buildOutput = GetOutputWindowText("Build"); 188 | 189 | if (buildOutput != null) 190 | { 191 | if (buildOutput.IndexOf(crestronSandboxFailureMessage) != -1) 192 | { 193 | Console.WriteLine("ERROR: Crestron sandbox failures in build!"); 194 | Results.Failed = true; 195 | } 196 | else if (options.Crestron && (buildOutput.IndexOf(crestronPluginStart) == -1)) 197 | { 198 | Console.WriteLine("ERROR: Crestron plugin did not run!"); 199 | Results.Failed = true; 200 | } 201 | else if (options.Crestron && (buildOutput.IndexOf(crestronPluginSuccess) == -1)) 202 | { 203 | Console.WriteLine("ERROR: Crestron plugin build failed!"); 204 | Results.Failed = true; 205 | } 206 | } 207 | else 208 | { 209 | if (options.Crestron) 210 | { 211 | Console.WriteLine("ERROR: Crestron plugin output not found!"); 212 | Results.Failed = true; 213 | } 214 | } 215 | } 216 | 217 | private void BuildSolutionConfiguration(EnvDTE80.SolutionConfiguration2 solutionConfiguration2) 218 | { 219 | Console.WriteLine("Activating solution configuration '" + solutionConfiguration2.Name + "' platform '" + solutionConfiguration2.PlatformName + "'"); 220 | solutionConfiguration2.Activate(); 221 | 222 | if (options.Clean) 223 | { 224 | Console.WriteLine("Cleaning solution configuration '" + solutionConfiguration2.Name + "' platform '" + solutionConfiguration2.PlatformName + "'"); 225 | sln.SolutionBuild.Clean(true); 226 | System.Threading.Thread.Sleep(1000); 227 | } 228 | 229 | Console.WriteLine("Building " + solutionConfiguration2.Name + ":" + solutionConfiguration2.PlatformName); 230 | sln.SolutionBuild.Build(true); 231 | System.Threading.Thread.Sleep(1000); 232 | 233 | PostBuildChecks(); 234 | } 235 | 236 | /// 237 | /// Return the unique name for the given project name 238 | /// This is required for single project builds 239 | /// 240 | /// The common project name 241 | /// The corresponding unique project name, or the empty string if not found. 242 | private string GetProjectUniqueName(string projectName) 243 | { 244 | #if DEBUG 245 | Console.WriteLine("Looking for project: {0}", projectName); 246 | #endif 247 | foreach (Project project in dte.Solution.Projects) 248 | { 249 | string uniqueName = GetProjectUniqueName(projectName, project); 250 | if (!string.IsNullOrEmpty(uniqueName)) 251 | return uniqueName; 252 | } 253 | return string.Empty; 254 | } 255 | 256 | /// 257 | /// This is a recursive form of GetProjectUniqueName which checks for sub projects - which is encountered when projects are organised into folders! 258 | /// 259 | /// The project name to look for 260 | /// The project collection to search, recursively 261 | /// A project unique name or the empty string 262 | private string GetProjectUniqueName(string projectName, Project project) 263 | { 264 | #if DEBUG 265 | Console.WriteLine("Checking project: {0} => {1}", project.Name, project.UniqueName); 266 | #endif 267 | if (project.Name.ToLower() == projectName.ToLower()) 268 | return project.UniqueName; 269 | else 270 | { 271 | if ((project.ProjectItems != null) && (project.ProjectItems.Count > 0)) 272 | { 273 | foreach (ProjectItem projItem in project.ProjectItems) 274 | { 275 | if (projItem.SubProject != null) 276 | { 277 | string uniqueName = GetProjectUniqueName(projectName, projItem.SubProject); 278 | if (!string.IsNullOrEmpty(uniqueName)) 279 | return uniqueName; 280 | #if DEBUG 281 | else 282 | { 283 | Console.WriteLine("Skipping item..."); 284 | } 285 | #endif 286 | } 287 | } 288 | } 289 | } 290 | return string.Empty; 291 | } 292 | 293 | /// 294 | /// Refactored solution matching 295 | /// 296 | /// The solution config passed as an option 297 | /// A matching solution config, or null if no matches 298 | private EnvDTE80.SolutionConfiguration2 IdentifyMatchingSolution(string solutionConfigurationName) 299 | { 300 | EnvDTE.SolutionConfigurations solutionConfigurations; 301 | 302 | solutionConfigurations = sln.SolutionBuild.SolutionConfigurations; 303 | 304 | foreach (EnvDTE80.SolutionConfiguration2 solutionConfiguration2 in solutionConfigurations) 305 | { 306 | Console.WriteLine("BuildSolutionConfiguration considering solution configuration '" + solutionConfiguration2.Name + "' platform '" + solutionConfiguration2.PlatformName + "'"); 307 | 308 | if (solutionConfiguration2.Name == solutionConfigurationName) 309 | { 310 | Console.WriteLine("Matches, building..."); 311 | return solutionConfiguration2; 312 | } 313 | else 314 | { 315 | Console.WriteLine("Does not match, skipping"); 316 | } 317 | } 318 | return null; 319 | } 320 | 321 | private void BuildProject(string solutionConfigurationName, string projectUniqueName) 322 | { 323 | SolutionConfiguration2 slnCfg = IdentifyMatchingSolution(solutionConfigurationName); 324 | if (slnCfg == null) 325 | { 326 | Console.WriteLine("No configurations matching " + solutionConfigurationName + " found."); 327 | return; 328 | } 329 | 330 | string buildConfig = slnCfg.Name + "|" + slnCfg.PlatformName; 331 | Console.WriteLine("Activating solution configuration '" + buildConfig + "'"); 332 | slnCfg.Activate(); 333 | 334 | if (options.Clean) 335 | { 336 | Console.WriteLine("Cleaning solution configuration '" + buildConfig + "'"); 337 | sln.SolutionBuild.Clean(true); 338 | System.Threading.Thread.Sleep(1000); 339 | } 340 | 341 | Console.WriteLine("Building " + buildConfig + ":" + projectUniqueName); 342 | sln.SolutionBuild.BuildProject(buildConfig, projectUniqueName, true); 343 | System.Threading.Thread.Sleep(1000); 344 | 345 | PostBuildChecks(); 346 | } 347 | 348 | private void BuildSolutionConfiguration(string solutionConfigurationName) 349 | { 350 | SolutionConfiguration2 slnCfg = IdentifyMatchingSolution(solutionConfigurationName); 351 | if (slnCfg == null) 352 | { 353 | Console.WriteLine("No configurations matching " + solutionConfigurationName + " found."); 354 | return; 355 | } 356 | 357 | BuildSolutionConfiguration(slnCfg); 358 | } 359 | 360 | private void BuildAll() 361 | { 362 | EnvDTE.SolutionConfigurations solutionConfigurations; 363 | 364 | solutionConfigurations = sln.SolutionBuild.SolutionConfigurations; 365 | 366 | foreach (EnvDTE80.SolutionConfiguration2 solutionConfiguration2 in solutionConfigurations) 367 | { 368 | Console.WriteLine("BuildAll starting solution configuration '" + solutionConfiguration2.Name + "' platform '" + solutionConfiguration2.PlatformName + "'"); 369 | BuildSolutionConfiguration(solutionConfiguration2); 370 | } 371 | } 372 | 373 | private void SaveAllOutputWindowPanes(string basePath, string projectName) 374 | { 375 | OutputWindow outputWindow = dte2.ToolWindows.OutputWindow; 376 | OutputWindowPanes panes = outputWindow.OutputWindowPanes; 377 | 378 | foreach (OutputWindowPane pane in panes) 379 | { 380 | string filename = Path.Combine(basePath, "build." + projectName + "-" + pane.Name + ".log"); 381 | 382 | string text = GetOutputWindowPaneText(pane); 383 | File.WriteAllText(filename, text); 384 | } 385 | } 386 | 387 | private string GetOutputWindowPaneText(OutputWindowPane outputWindowPane) 388 | { 389 | TextDocument doc = outputWindowPane.TextDocument; 390 | TextSelection sel = doc.Selection; 391 | 392 | sel.SelectAll(); 393 | string txt = sel.Text; 394 | 395 | return txt; 396 | } 397 | 398 | /// 399 | /// Get the full text from an output pane 400 | /// 401 | /// 402 | /// text from chosen output pane or null if pane does not exist or an error occurs 403 | private string GetOutputWindowText(string fromPane) 404 | { 405 | try 406 | { 407 | OutputWindow outputWindow = dte2.ToolWindows.OutputWindow; 408 | OutputWindowPane outputWindowPane = outputWindow.OutputWindowPanes.Item(fromPane); 409 | 410 | return GetOutputWindowPaneText(outputWindowPane); 411 | } 412 | catch (Exception) 413 | { 414 | return null; 415 | } 416 | } 417 | 418 | private void ChangeProjectContexts(EnvDTE.Project project, string configurationName) 419 | { 420 | EnvDTE.SolutionConfigurations solutionConfigurations; 421 | 422 | solutionConfigurations = sln.SolutionBuild.SolutionConfigurations; 423 | 424 | foreach (EnvDTE80.SolutionConfiguration2 solutionConfiguration2 in solutionConfigurations) 425 | { 426 | foreach (EnvDTE.SolutionContext solutionContext in solutionConfiguration2.SolutionContexts) 427 | { 428 | if (solutionContext.ProjectName == project.UniqueName) 429 | { 430 | solutionContext.ConfigurationName = configurationName; 431 | } 432 | } 433 | } 434 | } 435 | 436 | private void ShowProjectOutputs() 437 | { 438 | foreach (Project project in dte.Solution.Projects) 439 | { 440 | Console.WriteLine("Project: " + project.Name); 441 | 442 | var dir = System.IO.Path.Combine( 443 | project.FullName, 444 | project.ConfigurationManager.ActiveConfiguration.Properties.Item("OutputPath").Value.ToString()); 445 | 446 | foreach (Property prop in project.ConfigurationManager.ActiveConfiguration.Properties) 447 | { 448 | Console.WriteLine(" - " + prop.Name + " = " + prop.Value); 449 | } 450 | 451 | string outputFileName = null; 452 | 453 | try 454 | { 455 | // and combine it with the OutputFilename to get the assembly 456 | // or skip this and grab all files in the output directory 457 | outputFileName = System.IO.Path.Combine( 458 | dir, 459 | project.ConfigurationManager.ActiveConfiguration.Properties.Item("OutputFilename").Value.ToString()); 460 | } 461 | catch (ArgumentException) 462 | { 463 | // projects in VS2008 do not seem to define this property, oh well 464 | outputFileName = System.IO.Path.Combine(dir, "???.???"); 465 | } 466 | 467 | Console.WriteLine(outputFileName); 468 | } 469 | } 470 | 471 | private string GetProjectContexts() 472 | { 473 | System.Text.StringBuilder sb = new System.Text.StringBuilder(); 474 | EnvDTE80.Solution2 solution2; 475 | EnvDTE80.SolutionBuild2 solutionBuild2; 476 | EnvDTE.SolutionContexts solutionContexts; 477 | 478 | solution2 = (EnvDTE80.Solution2)sln; 479 | solutionBuild2 = (EnvDTE80.SolutionBuild2)solution2.SolutionBuild; 480 | 481 | // Solution configurations/platforms 482 | sb.AppendLine(); 483 | sb.AppendLine("-----------------------------------------------"); 484 | sb.AppendLine("Project contexts for each solution configuration/platform:"); 485 | 486 | foreach (SolutionConfiguration2 solutionConfiguration2 in solutionBuild2.SolutionConfigurations) 487 | { 488 | sb.AppendLine(); 489 | 490 | sb.AppendLine(" - Solution configuration: " + solutionConfiguration2.Name); 491 | sb.AppendLine(" - Solution platform: " + solutionConfiguration2.PlatformName); 492 | 493 | solutionContexts = solutionConfiguration2.SolutionContexts; 494 | 495 | foreach (EnvDTE.SolutionContext solutionContext in solutionContexts) 496 | { 497 | sb.AppendLine(); 498 | sb.AppendLine(" Project unique name: " + solutionContext.ProjectName); 499 | sb.AppendLine(" Project configuration: " + solutionContext.ConfigurationName); 500 | sb.AppendLine(" Project platform: " + solutionContext.PlatformName); 501 | sb.AppendLine(); 502 | } 503 | } 504 | 505 | return sb.ToString(); 506 | } 507 | 508 | private void ChangeActiveConfigurationAndPlatform(string configurationName, string platformName) 509 | { 510 | EnvDTE80.SolutionConfiguration2 solutionConfiguration2 = null; 511 | 512 | solutionConfiguration2 = (EnvDTE80.SolutionConfiguration2)sln.SolutionBuild.ActiveConfiguration; 513 | 514 | Console.WriteLine("The old configuration was: Configuration Name: " + solutionConfiguration2.Name + ", Platform Name: " + solutionConfiguration2.PlatformName); 515 | 516 | foreach (EnvDTE80.SolutionConfiguration2 solConfiguration2 in sln.SolutionBuild.SolutionConfigurations) 517 | { 518 | if (solConfiguration2.Name == configurationName && solConfiguration2.PlatformName == platformName) 519 | { 520 | solConfiguration2.Activate(); 521 | break; 522 | } 523 | } 524 | 525 | solutionConfiguration2 = (EnvDTE80.SolutionConfiguration2)sln.SolutionBuild.ActiveConfiguration; 526 | 527 | Console.WriteLine("The new configuration is: Configuration Name: " + solutionConfiguration2.Name + ", Platform Name: " + solutionConfiguration2.PlatformName); 528 | } 529 | 530 | public void ShowSolutionConfigurations() 531 | { 532 | EnvDTE.SolutionConfigurations solutionConfigurations; 533 | 534 | solutionConfigurations = sln.SolutionBuild.SolutionConfigurations; 535 | 536 | foreach (EnvDTE80.SolutionConfiguration2 solutionConfiguration2 in solutionConfigurations) 537 | { 538 | Console.WriteLine(" SolutionConfigurationName: " + solutionConfiguration2.Name); 539 | foreach (EnvDTE.SolutionContext solutionContext in solutionConfiguration2.SolutionContexts) 540 | { 541 | Console.WriteLine(" SolutionConfigurationContext"); 542 | Console.WriteLine(" ProjectName = " + solutionContext.ProjectName); // will match project.UniqueName 543 | Console.WriteLine(" ConfigurationName = " + solutionContext.ConfigurationName); // you can write this too 544 | } 545 | } 546 | } 547 | 548 | /// 549 | /// Convert the given solution name to an absolute path, and add the .sln extension 550 | /// 551 | /// The solution filename from the arguments 552 | /// The absolute path to the full solution 553 | private string ResolveSolutionName(string solutionFile) 554 | { 555 | string absPath = Path.GetDirectoryName(Path.GetFullPath(solutionFile)); 556 | string slnFileName = Path.GetFileNameWithoutExtension(solutionFile); 557 | return Path.Combine(absPath, slnFileName + ".sln"); 558 | } 559 | 560 | public bool OpenSolution(string solutionFile) 561 | { 562 | sln = dte.Solution; 563 | sln.Open(solutionFile); 564 | #if DEBUG 565 | Console.WriteLine("sln.IsOpen = " + sln.IsOpen); 566 | #endif 567 | return sln.IsOpen; 568 | } 569 | 570 | public void CloseSolution() 571 | { 572 | sln.Close(false); 573 | } 574 | 575 | /// 576 | /// Open Visual Studio 2008 577 | /// 578 | public void OpenVS() 579 | { 580 | #if DEBUG 581 | Console.WriteLine("Getting Type of Visual Studio..."); 582 | #endif 583 | Type type = Type.GetTypeFromProgID("VisualStudio.DTE.9.0"); 584 | 585 | #if DEBUG 586 | Console.WriteLine("Opening Visual Studio..."); 587 | #endif 588 | visualStudio = Activator.CreateInstance(type, true); 589 | 590 | // See http://msdn.microsoft.com/en-us/library/ms228772.aspx 591 | MessageFilter.Register(); 592 | 593 | #if DEBUG 594 | Console.WriteLine("Casting to DTE..."); 595 | #endif 596 | dte = (DTE)visualStudio; 597 | 598 | #if DEBUG 599 | Console.WriteLine("Casting to DTE2..."); 600 | #endif 601 | dte2 = (DTE2)visualStudio; 602 | } 603 | 604 | /// 605 | /// Close Visual Studio 2008 606 | /// 607 | public void CloseVS() 608 | { 609 | dte.Quit(); 610 | 611 | MessageFilter.Revoke(); 612 | } 613 | } 614 | } --------------------------------------------------------------------------------