1- #: package Microsoft . Build. Locator@1.9 .1
1+ #: package Microsoft . Build. Locator@1.11 .2
2+ #: package Spectre . Console@0.54 .0
23
34using System . Diagnostics ;
45using System . IO . Compression ;
78
89using Microsoft . Build . Locator ;
910
11+ using Spectre . Console ;
12+
1013namespace BuildAgent . Script {
1114 internal class Program {
1215 public static void Main ( string [ ] args ) {
13- Environment . CurrentDirectory = Path . GetDirectoryName ( ( string ) AppContext . GetData ( "EntryPointFilePath" ) ) ;
14- var buildResultDir = Directory . CreateDirectory ( "./BuildResult" ) ;
15- Console . WriteLine ( $ "Using output directory: { buildResultDir . FullName } ") ;
16+ Environment . CurrentDirectory = Path . GetDirectoryName ( ( string ) AppContext . GetData ( "EntryPointFilePath" ) ! ) ! ;
17+ var buildResultDir = new DirectoryInfo ( "./BuildResult" ) ;
18+ AnsiConsole . MarkupLineInterpolated ( $ "[Aqua] Using output directory:[/] [Orange1] { buildResultDir . FullName } [/] ") ;
1619
17- if ( Directory . Exists ( buildResultDir . FullName ) ) {
18- Directory . Delete ( buildResultDir . FullName , true ) ;
20+ if ( buildResultDir . Exists ) {
21+ buildResultDir . Delete ( recursive : true ) ;
1922 }
23+ buildResultDir . Create ( ) ;
24+ buildResultDir . Refresh ( ) ;
25+
26+ DotNetPublisher . PublishProjects ( buildResultDir ) ;
27+ NativePublisher . PublishProjects ( buildResultDir ) ;
28+
29+ AnsiConsole . MarkupLine ( "[Green]Build complete![/]" ) ;
30+ }
31+ }
32+
33+ public abstract class Publisher {
34+ protected string ? outputFolder ;
35+
36+ public void ZipArtifacts ( ) {
37+ _ = outputFolder ?? throw new InvalidOperationException ( $ "{ nameof ( outputFolder ) } must be set in Publish() method.") ;
2038
21- DotNetPublisher . Publish ( buildResultDir . FullName ) ;
22- NativePublisher . Publish ( buildResultDir . FullName ) ;
39+ if ( ! Directory . Exists ( outputFolder ) ) {
40+ AnsiConsole . MarkupLineInterpolated ( $ "[bold Red]Cannot zip, { outputFolder } does not exist![/]") ;
41+ return ;
42+ }
43+
44+ var zipFilePath = $ "{ outputFolder } .zip";
45+ if ( File . Exists ( zipFilePath ) ) {
46+ File . Delete ( zipFilePath ) ;
47+ }
2348
24- Console . WriteLine ( "Done!" ) ;
49+ ZipFile . CreateFromDirectory ( outputFolder , zipFilePath , CompressionLevel . SmallestSize , includeBaseDirectory : false ) ;
2550 }
2651 }
2752
2853 public static class NativePublisher {
29- public static void Publish ( string buildResultDir ) {
54+ public static void PublishProjects ( DirectoryInfo buildResultDir ) {
3055 var nativeProjects = GetNativeProjects ( includeTestProjects : false ) ;
3156 foreach ( var nativeProject in nativeProjects ) {
32- Console . WriteLine ( $ "Publishing project: { nativeProject } ") ;
57+ AnsiConsole . MarkupLineInterpolated ( $ "[Aqua] Publishing project:[/] [Orange1] { nativeProject } [/] ") ;
3358
3459 switch ( Environment . OSVersion . Platform ) {
3560 case PlatformID . Win32S :
3661 case PlatformID . Win32Windows :
3762 case PlatformID . Win32NT :
3863 case PlatformID . WinCE :
39- MSBuildPublisher . Publish ( buildResultDir , nativeProject ) ;
64+ new MSBuildPublisher ( )
65+ . Publish ( buildResultDir , nativeProject )
66+ . ZipArtifacts ( ) ;
4067 break ;
4168 case PlatformID . Unix :
42- GccPublisher . Publish ( buildResultDir , nativeProject ) ;
69+ new GccPublisher ( )
70+ . Publish ( buildResultDir , nativeProject )
71+ . ZipArtifacts ( ) ;
4372 break ;
4473 case PlatformID . MacOSX :
4574 break ;
@@ -53,39 +82,37 @@ private static string[] GetNativeProjects(bool includeTestProjects) {
5382 var dotnetProjects = Directory . GetFiles ( "." , "*.vcxproj" , new EnumerationOptions { RecurseSubdirectories = true , MaxRecursionDepth = 1 } ) ;
5483
5584 if ( ! includeTestProjects ) {
56- dotnetProjects = dotnetProjects . Where ( i => ! i . Contains ( "Test" ) ) . ToArray ( ) ;
85+ dotnetProjects = dotnetProjects . Where ( x => ! x . Contains ( "Test" ) ) . ToArray ( ) ;
5786 }
5887
59- dotnetProjects = dotnetProjects . Select ( i => Path . GetFullPath ( i ) ) . ToArray ( ) ;
88+ dotnetProjects = dotnetProjects . Select ( Path . GetFullPath ) . ToArray ( ) ;
6089
6190 return dotnetProjects ;
6291 }
6392 }
6493
65- public static class GccPublisher {
66- public static void Publish ( string buildResultDir , string project ) {
67- var outputFolder = Path . Combine ( buildResultDir , "linux" , Path . GetFileNameWithoutExtension ( project ) ) ;
94+ public class GccPublisher : Publisher {
95+ public Publisher Publish ( DirectoryInfo buildResultDir , string project ) {
96+ outputFolder = Path . Combine ( buildResultDir . FullName , "linux" , Path . GetFileNameWithoutExtension ( project ) ) ;
6897
69- var buildResult = Shell . Run (
98+ Shell . Run (
7099 "bash" ,
71100 $ "{ project } ",
72- buildResultDir ) ;
101+ buildResultDir . FullName ) ;
73102
74- var zipFilePath = $ "{ outputFolder } .zip";
75- if ( File . Exists ( zipFilePath ) ) {
76- File . Delete ( zipFilePath ) ;
77- }
78-
79- ZipFile . CreateFromDirectory ( outputFolder , zipFilePath , CompressionLevel . Optimal , includeBaseDirectory : true ) ;
103+ return this ;
80104 }
81105 }
82106
83- public static class MSBuildPublisher {
84- public static void Publish ( string buildResultDir , string project ) {
85- var outputFolder = Path . Combine ( buildResultDir , "windows" , Path . GetFileNameWithoutExtension ( project ) ) ;
107+ public class MSBuildPublisher : Publisher {
108+ public Publisher Publish ( DirectoryInfo buildResultDir , string project ) {
109+ outputFolder = Path . Combine ( buildResultDir . FullName , "windows" , Path . GetFileNameWithoutExtension ( project ) ) ;
86110 var mostRecentVsStudio = MSBuildLocator . QueryVisualStudioInstances ( ) . OrderByDescending ( instance => instance . Version ) . First ( ) ;
87111
88- var msBuild = @"C:\Program Files\Microsoft Visual Studio\2022\Enterprise\MSBuild\Current\Bin\amd64\msbuild.exe" ;
112+ const string VS2026_BASE_PATH = @"C:\Program Files\Microsoft Visual Studio\18" ;
113+ const string VS2026_MSBUILD_PATH = @"MSBuild\Current\Bin\amd64\MSBuild.exe" ;
114+ var vsEdition = Directory . GetDirectories ( VS2026_BASE_PATH ) [ 0 ] ;
115+ var msBuild = Path . Combine ( VS2026_BASE_PATH , vsEdition , VS2026_MSBUILD_PATH ) ;
89116
90117 var buildResult = Shell . Run (
91118 msBuild ,
@@ -94,35 +121,46 @@ public static void Publish(string buildResultDir, string project) {
94121 "/p:Configuration=Release" ,
95122 "/p:Platform=x64" ,
96123 $ "/p:OutDir={ outputFolder } ") ;
97-
98- var zipFilePath = $ "{ outputFolder } .zip";
99- if ( File . Exists ( zipFilePath ) ) {
100- File . Delete ( zipFilePath ) ;
101- }
102-
103- ZipFile . CreateFromDirectory ( outputFolder , zipFilePath , CompressionLevel . Optimal , includeBaseDirectory : true ) ;
124+
125+ return this ;
104126 }
105127 }
106128
107- public static class DotNetPublisher {
108- public static void Publish ( string buildResultDir ) {
109- Console . WriteLine ( "Running restore ") ;
129+ public class DotNetPublisher : Publisher {
130+ public static void PublishProjects ( DirectoryInfo buildResultDir ) {
131+ AnsiConsole . MarkupLine ( "[Aqua]Restoring .NET projects[/] ") ;
110132 Shell . Run ( "dotnet" , "restore" ) ;
111133
112134 var dotnetProjects = GetDotnetProjects ( includeTestProjects : false ) ;
113135 foreach ( var dotnetProject in dotnetProjects ) {
114- Console . WriteLine ( $ "Publishing project: { dotnetProject } ") ;
136+ AnsiConsole . MarkupLineInterpolated ( $ "[Aqua]Publishing project:[/] [Orange1]{ dotnetProject } [/]") ;
137+
138+ new DotNetPublisher ( )
139+ . PublishPlatform ( OSPlatform . Windows , buildResultDir , dotnetProject )
140+ . ZipArtifacts ( ) ;
141+ new DotNetPublisher ( )
142+ . PublishPlatform ( OSPlatform . Linux , buildResultDir , dotnetProject )
143+ . ZipArtifacts ( ) ;
144+ }
145+ }
146+
147+ private static string [ ] GetDotnetProjects ( bool includeTestProjects ) {
148+ var dotnetProjects = Directory . GetFiles ( "." , "*.csproj" , new EnumerationOptions { RecurseSubdirectories = true , MaxRecursionDepth = 1 } ) ;
115149
116- PublishPlatform ( OSPlatform . Windows , buildResultDir , dotnetProject ) ;
117- PublishPlatform ( OSPlatform . Linux , buildResultDir , dotnetProject ) ;
150+ if ( ! includeTestProjects ) {
151+ dotnetProjects = dotnetProjects . Where ( x => ! x . Contains ( "Test" ) ) . ToArray ( ) ;
118152 }
153+
154+ dotnetProjects = dotnetProjects . Select ( Path . GetFullPath ) . ToArray ( ) ;
155+
156+ return dotnetProjects ;
119157 }
120158
121- private static void PublishPlatform ( OSPlatform platform , string buildResultDir , string dotnetProject ) {
122- var outputFolder = Path . Combine ( buildResultDir , platform . ToString ( ) . ToLower ( ) , Path . GetFileNameWithoutExtension ( dotnetProject ) ) ;
159+ private Publisher PublishPlatform ( OSPlatform platform , DirectoryInfo buildResultDir , string dotnetProject ) {
160+ outputFolder = Path . Combine ( buildResultDir . FullName , platform . ToString ( ) . ToLower ( ) , Path . GetFileNameWithoutExtension ( dotnetProject ) ) ;
123161 var runtimeIdentifier = platform == OSPlatform . Windows ? "win-x64" : "linux-x64" ;
124162
125- var buildResult = Shell . Run (
163+ Shell . Run (
126164 "dotnet" ,
127165 "publish" ,
128166 "-c" , "Release" ,
@@ -131,30 +169,18 @@ private static void PublishPlatform(OSPlatform platform, string buildResultDir,
131169 "-r" , runtimeIdentifier ,
132170 dotnetProject ) ;
133171
134- var zipFilePath = $ "{ outputFolder } .zip";
135- if ( File . Exists ( zipFilePath ) ) {
136- File . Delete ( zipFilePath ) ;
137- }
138-
139- ZipFile . CreateFromDirectory ( outputFolder , zipFilePath , CompressionLevel . Optimal , includeBaseDirectory : true ) ;
140- }
141-
142- private static string [ ] GetDotnetProjects ( bool includeTestProjects ) {
143- var dotnetProjects = Directory . GetFiles ( "." , "*.csproj" , new EnumerationOptions { RecurseSubdirectories = true , MaxRecursionDepth = 1 } ) ;
144-
145- if ( ! includeTestProjects ) {
146- dotnetProjects = dotnetProjects . Where ( i => ! i . Contains ( "Test" ) ) . ToArray ( ) ;
147- }
148-
149- dotnetProjects = dotnetProjects . Select ( i => Path . GetFullPath ( i ) ) . ToArray ( ) ;
150-
151- return dotnetProjects ;
172+ return this ;
152173 }
153174 }
154175
155176 public static class Shell {
177+ /// <summary>Runs a program with the specified arguments.</summary>
178+ /// <returns>The standard output from the started process.</returns>
156179 public static string Run ( string program , params string [ ] arguments ) => RunInternal ( program , arguments , false ) ;
157180
181+ /// <summary>Runs a program with the specified arguments.</summary>
182+ /// <returns>The standard output from the started process.</returns>
183+ /// <remarks>Does not log the arguments to the console.</remarks>
158184 public static string RunSensitive ( string program , params string [ ] arguments ) => RunInternal ( program , arguments , true ) ;
159185
160186 private static string RunInternal ( string program , string [ ] arguments , bool sensitive ) {
@@ -169,10 +195,10 @@ private static string RunInternal(string program, string[] arguments, bool sensi
169195 }
170196
171197 if ( ! sensitive ) {
172- Console . WriteLine ( $ "Running { programPath } with args: { CombineArguments ( arguments ) } ") ;
198+ AnsiConsole . MarkupLineInterpolated ( $ "[Aqua] Running[/] [Orange1] { programPath } [/] [Aqua] with args:[/] [Orange1] { CombineArguments ( arguments ) } [/] ") ;
173199 }
174200 else {
175- Console . WriteLine ( $ "Running { programPath } with sensitive args") ;
201+ AnsiConsole . MarkupLineInterpolated ( $ "[Aqua] Running[/] [Orange1] { programPath } [/] [Aqua] with[/] [Orange1] sensitive args[/] ") ;
176202 }
177203
178204 var outputBuilder = new StringBuilder ( ) ;
@@ -232,5 +258,4 @@ static string CombineArguments(IEnumerable<string> args) {
232258 return null ;
233259 }
234260 }
235-
236261}
0 commit comments