2222using Zafiro . FileSystem . Core ;
2323using DotnetPackaging . Exe ;
2424using System . Threading ;
25+ using RuntimeArchitecture = System . Runtime . InteropServices . Architecture ;
2526
2627namespace DotnetPackaging . Tool ;
2728
@@ -171,9 +172,9 @@ await ExecuteWithLogging("dmg-verify", file.FullName, async logger =>
171172 {
172173 Description = "Path to the prebuilt stub (WinExe) to concatenate (optional if repo layout is present)"
173174 } ;
174- var exRidTop = new Option < string ? > ( "--rid " )
175+ var exArchTop = new Option < string ? > ( "--arch " )
175176 {
176- Description = "Runtime identifier for the stub (win- x64, win- arm64)"
177+ Description = "Target architecture for the stub (x64, arm64)"
177178 } ;
178179
179180 // Reuse metadata options
@@ -247,7 +248,7 @@ await ExecuteWithLogging("dmg-verify", file.FullName, async logger =>
247248 exeCommand . Add ( exAppId ) ;
248249 exeCommand . Add ( exVendor ) ;
249250 exeCommand . Add ( exExecutableName ) ;
250- exeCommand . Add ( exRidTop ) ;
251+ exeCommand . Add ( exArchTop ) ;
251252
252253 exeCommand . SetAction ( async parseResult =>
253254 {
@@ -256,11 +257,18 @@ await ExecuteWithLogging("dmg-verify", file.FullName, async logger =>
256257 var stub = parseResult . GetValue ( stubPath ) ;
257258 var opt = optionsBinder . Bind ( parseResult ) ;
258259 var vendorOpt = parseResult . GetValue ( exVendor ) ;
259- var ridOpt = parseResult . GetValue ( exRidTop ) ;
260+ var archOpt = parseResult . GetValue ( exArchTop ) ;
261+ var ridResult = ResolveWindowsRid ( archOpt , "EXE packaging" ) ;
262+ if ( ridResult . IsFailure )
263+ {
264+ Console . Error . WriteLine ( ridResult . Error ) ;
265+ Environment . ExitCode = 1 ;
266+ return ;
267+ }
260268 await ExecuteWithLogging ( "exe" , outFile . FullName , async logger =>
261269 {
262270 var exeService = new ExePackagingService ( logger ) ;
263- var result = await exeService . BuildFromDirectory ( inDir , outFile , opt , vendorOpt , ridOpt , stub ) ;
271+ var result = await exeService . BuildFromDirectory ( inDir , outFile , opt , vendorOpt , ridResult . Value , stub ) ;
264272 if ( result . IsFailure )
265273 {
266274 logger . Error ( "EXE packaging failed: {Error}" , result . Error ) ;
@@ -279,9 +287,9 @@ await ExecuteWithLogging("exe", outFile.FullName, async logger =>
279287 Description = "Path to the .csproj file" ,
280288 Required = true
281289 } ;
282- var exRid = new Option < string ? > ( "--rid " )
290+ var exArch = new Option < string ? > ( "--arch " )
283291 {
284- Description = "Runtime identifier (e.g. win- x64, win- arm64)"
292+ Description = "Target architecture ( x64, arm64)"
285293 } ;
286294 var exSelfContained = new Option < bool > ( "--self-contained" )
287295 {
@@ -313,7 +321,7 @@ await ExecuteWithLogging("exe", outFile.FullName, async logger =>
313321
314322 var exFromProject = new Command ( "from-project" ) { Description = "Publish a .NET project and build a Windows self-extracting installer (.exe). If --stub is not provided, the tool downloads the appropriate stub from GitHub Releases." } ;
315323 exFromProject . Add ( exProject ) ;
316- exFromProject . Add ( exRid ) ;
324+ exFromProject . Add ( exArch ) ;
317325 exFromProject . Add ( exSelfContained ) ;
318326 exFromProject . Add ( exConfiguration ) ;
319327 exFromProject . Add ( exSingleFile ) ;
@@ -324,7 +332,14 @@ await ExecuteWithLogging("exe", outFile.FullName, async logger =>
324332 exFromProject . SetAction ( async parseResult =>
325333 {
326334 var prj = parseResult . GetValue ( exProject ) ! ;
327- var ridVal = parseResult . GetValue ( exRid ) ;
335+ var archVal = parseResult . GetValue ( exArch ) ;
336+ var ridResult = ResolveWindowsRid ( archVal , "EXE packaging" ) ;
337+ if ( ridResult . IsFailure )
338+ {
339+ Console . Error . WriteLine ( ridResult . Error ) ;
340+ Environment . ExitCode = 1 ;
341+ return ;
342+ }
328343 var sc = parseResult . GetValue ( exSelfContained ) ;
329344 var cfg = parseResult . GetValue ( exConfiguration ) ! ;
330345 var sf = parseResult . GetValue ( exSingleFile ) ;
@@ -336,7 +351,7 @@ await ExecuteWithLogging("exe", outFile.FullName, async logger =>
336351 await ExecuteWithLogging ( "exe-from-project" , extrasOutput . FullName , async logger =>
337352 {
338353 var exeService = new ExePackagingService ( logger ) ;
339- var result = await exeService . BuildFromProject ( prj , ridVal , sc , cfg , sf , tr , extrasOutput , opt , vendorOpt , extrasStub ) ;
354+ var result = await exeService . BuildFromProject ( prj , ridResult . Value , sc , cfg , sf , tr , extrasOutput , opt , vendorOpt , extrasStub ) ;
340355 if ( result . IsFailure )
341356 {
342357 logger . Error ( "EXE from project packaging failed: {Error}" , result . Error ) ;
@@ -1493,13 +1508,13 @@ private static void AddRpmFromProjectSubcommand(Command rpmCommand)
14931508 fromProject . SetAction ( async parseResult =>
14941509 {
14951510 var prj = parseResult . GetValue ( project ) ! ;
1496- var ridVal = parseResult . GetValue ( rid ) ;
14971511 var sc = parseResult . GetValue ( selfContained ) ;
14981512 var cfg = parseResult . GetValue ( configuration ) ! ;
14991513 var sf = parseResult . GetValue ( singleFile ) ;
15001514 var tr = parseResult . GetValue ( trimmed ) ;
15011515 var outFile = parseResult . GetValue ( output ) ! ;
15021516 var opt = optionsBinder . Bind ( parseResult ) ;
1517+ var ridVal = parseResult . GetValue ( rid ) ;
15031518
15041519 if ( string . IsNullOrWhiteSpace ( ridVal ) && ! RuntimeInformation . IsOSPlatform ( OSPlatform . Linux ) )
15051520 {
@@ -1606,13 +1621,13 @@ private static void AddDebFromProjectSubcommand(Command debCommand)
16061621 fromProject . SetAction ( async parseResult =>
16071622 {
16081623 var prj = parseResult . GetValue ( project ) ! ;
1609- var ridVal = parseResult . GetValue ( rid ) ;
16101624 var sc = parseResult . GetValue ( selfContained ) ;
16111625 var cfg = parseResult . GetValue ( configuration ) ! ;
16121626 var sf = parseResult . GetValue ( singleFile ) ;
16131627 var tr = parseResult . GetValue ( trimmed ) ;
16141628 var outFile = parseResult . GetValue ( output ) ! ;
16151629 var opt = optionsBinder . Bind ( parseResult ) ;
1630+ var ridVal = parseResult . GetValue ( rid ) ;
16161631
16171632 if ( string . IsNullOrWhiteSpace ( ridVal ) && ! RuntimeInformation . IsOSPlatform ( OSPlatform . Linux ) )
16181633 {
@@ -1701,12 +1716,12 @@ await DotnetPackaging.Msix.Msix.FromDirectory(container, Maybe<Serilog.ILogger>.
17011716 fromProject . SetAction ( async parseResult =>
17021717 {
17031718 var prj = parseResult . GetValue ( project ) ! ;
1704- var ridVal = parseResult . GetValue ( rid ) ;
17051719 var sc = parseResult . GetValue ( selfContained ) ;
17061720 var cfg = parseResult . GetValue ( configuration ) ! ;
17071721 var sf = parseResult . GetValue ( singleFile ) ;
17081722 var tr = parseResult . GetValue ( trimmed ) ;
17091723 var outFile = parseResult . GetValue ( outMsix ) ! ;
1724+ var ridVal = parseResult . GetValue ( rid ) ;
17101725
17111726 if ( string . IsNullOrWhiteSpace ( ridVal ) && ! RuntimeInformation . IsOSPlatform ( OSPlatform . Windows ) )
17121727 {
@@ -1798,13 +1813,13 @@ private static void AddAppImageFromProjectSubcommand(Command appImageCommand)
17981813 fromProject . SetAction ( async parseResult =>
17991814 {
18001815 var prj = parseResult . GetValue ( project ) ! ;
1801- var ridVal = parseResult . GetValue ( rid ) ;
18021816 var sc = parseResult . GetValue ( selfContained ) ;
18031817 var cfg = parseResult . GetValue ( configuration ) ! ;
18041818 var sf = parseResult . GetValue ( singleFile ) ;
18051819 var tr = parseResult . GetValue ( trimmed ) ;
18061820 var outFile = parseResult . GetValue ( output ) ! ;
18071821 var opt = optionsBinder . Bind ( parseResult ) ;
1822+ var ridVal = parseResult . GetValue ( rid ) ;
18081823
18091824 if ( string . IsNullOrWhiteSpace ( ridVal ) && ! RuntimeInformation . IsOSPlatform ( OSPlatform . Linux ) )
18101825 {
@@ -1874,10 +1889,78 @@ private static Task CreateDmg(DirectoryInfo inputDir, FileInfo outputFile, Optio
18741889 return DotnetPackaging . Dmg . DmgIsoBuilder . Create ( inputDir . FullName , outputFile . FullName , name ) ;
18751890 }
18761891
1892+ private static Result < string > ResolveWindowsRid ( string ? architecture , string context )
1893+ {
1894+ return ResolveRidForPlatform ( architecture , OSPlatform . Windows , "Windows" , "win" , context ) ;
1895+ }
1896+
1897+ private static Result < string > ResolveMacRid ( string ? architecture )
1898+ {
1899+ return ResolveRidForPlatform ( architecture , OSPlatform . OSX , "macOS" , "osx" , "DMG packaging" ) ;
1900+ }
1901+
1902+ private static Result < string > ResolveRidForPlatform ( string ? architecture , OSPlatform targetPlatform , string targetName , string ridPrefix , string context )
1903+ {
1904+ var architectureResult = DetermineArchitecture ( architecture , targetPlatform , targetName , context ) ;
1905+ if ( architectureResult . IsFailure )
1906+ {
1907+ return Result . Failure < string > ( architectureResult . Error ) ;
1908+ }
1909+
1910+ return MapArchitectureToRid ( architectureResult . Value , ridPrefix , context ) ;
1911+ }
1912+
1913+ private static Result < RuntimeArchitecture > DetermineArchitecture ( string ? requested , OSPlatform targetPlatform , string targetName , string context )
1914+ {
1915+ if ( ! string . IsNullOrWhiteSpace ( requested ) )
1916+ {
1917+ var parsed = ParseRuntimeArchitecture ( requested ) ;
1918+ if ( parsed is RuntimeArchitecture . X64 or RuntimeArchitecture . Arm64 )
1919+ {
1920+ return Result . Success ( parsed . Value ) ;
1921+ }
1922+
1923+ return Result . Failure < RuntimeArchitecture > ( $ "Unsupported architecture '{ requested } '. Use x64 or arm64.") ;
1924+ }
1925+
1926+ if ( RuntimeInformation . IsOSPlatform ( targetPlatform ) )
1927+ {
1928+ if ( RuntimeInformation . OSArchitecture is RuntimeArchitecture . X64 or RuntimeArchitecture . Arm64 )
1929+ {
1930+ return Result . Success ( RuntimeInformation . OSArchitecture ) ;
1931+ }
1932+
1933+ return Result . Failure < RuntimeArchitecture > ( $ "{ context } supports x64 or arm64. Detected architecture '{ RuntimeInformation . OSArchitecture } ' is not supported.") ;
1934+ }
1935+
1936+ return Result . Failure < RuntimeArchitecture > ( $ "--arch is required when building { context } on non-{ targetName } hosts (x64/arm64).") ;
1937+ }
1938+
1939+ private static Result < string > MapArchitectureToRid ( RuntimeArchitecture architecture , string ridPrefix , string context )
1940+ {
1941+ return architecture switch
1942+ {
1943+ RuntimeArchitecture . X64 => Result . Success ( $ "{ ridPrefix } -x64") ,
1944+ RuntimeArchitecture . Arm64 => Result . Success ( $ "{ ridPrefix } -arm64") ,
1945+ _ => Result . Failure < string > ( $ "{ context } supports x64 or arm64 architectures only.")
1946+ } ;
1947+ }
1948+
1949+ private static RuntimeArchitecture ? ParseRuntimeArchitecture ( string value )
1950+ {
1951+ var v = value . Trim ( ) . ToLowerInvariant ( ) ;
1952+ return v switch
1953+ {
1954+ "x86_64" or "amd64" or "x64" => RuntimeArchitecture . X64 ,
1955+ "aarch64" or "arm64" => RuntimeArchitecture . Arm64 ,
1956+ _ => null
1957+ } ;
1958+ }
1959+
18771960 private static void AddDmgFromProjectSubcommand ( Command dmgCommand )
18781961 {
18791962 var project = new Option < FileInfo > ( "--project" ) { Description = "Path to the .csproj file" , Required = true } ;
1880- var rid = new Option < string ? > ( "--rid " ) { Description = "Runtime identifier (e.g. osx- x64, osx- arm64)" , Required = true } ;
1963+ var arch = new Option < string ? > ( "--arch " ) { Description = "Target architecture ( x64, arm64)" } ;
18811964 var selfContained = new Option < bool > ( "--self-contained" ) { Description = "Publish self-contained" } ;
18821965 selfContained . DefaultValueFactory = _ => true ;
18831966 var configuration = new Option < string > ( "--configuration" ) { Description = "Build configuration" } ;
@@ -1909,7 +1992,7 @@ private static void AddDmgFromProjectSubcommand(Command dmgCommand)
19091992
19101993 var fromProject = new Command ( "from-project" ) { Description = "Publish a .NET project and build a .dmg from the published output (.app bundle auto-generated if missing). Experimental." } ;
19111994 fromProject . Add ( project ) ;
1912- fromProject . Add ( rid ) ;
1995+ fromProject . Add ( arch ) ;
19131996 fromProject . Add ( selfContained ) ;
19141997 fromProject . Add ( configuration ) ;
19151998 fromProject . Add ( singleFile ) ;
@@ -1920,18 +2003,24 @@ private static void AddDmgFromProjectSubcommand(Command dmgCommand)
19202003 fromProject . SetAction ( async parseResult =>
19212004 {
19222005 var prj = parseResult . GetValue ( project ) ! ;
1923- var ridVal = parseResult . GetValue ( rid ) ;
19242006 var sc = parseResult . GetValue ( selfContained ) ;
19252007 var cfg = parseResult . GetValue ( configuration ) ! ;
19262008 var sf = parseResult . GetValue ( singleFile ) ;
19272009 var tr = parseResult . GetValue ( trimmed ) ;
19282010 var outFile = parseResult . GetValue ( output ) ! ;
19292011 var opt = optionsBinder . Bind ( parseResult ) ;
2012+ var ridResult = ResolveMacRid ( parseResult . GetValue ( arch ) ) ;
2013+ if ( ridResult . IsFailure )
2014+ {
2015+ Console . Error . WriteLine ( ridResult . Error ) ;
2016+ Environment . ExitCode = 1 ;
2017+ return ;
2018+ }
19302019
19312020 var publisher = new DotnetPackaging . Publish . DotnetPublisher ( ) ;
19322021 var req = new DotnetPackaging . Publish . ProjectPublishRequest ( prj . FullName )
19332022 {
1934- Rid = string . IsNullOrWhiteSpace ( ridVal ) ? Maybe < string > . None : Maybe < string > . From ( ridVal ! ) ,
2023+ Rid = Maybe < string > . From ( ridResult . Value ) ,
19352024 SelfContained = sc ,
19362025 Configuration = cfg ,
19372026 SingleFile = sf ,
0 commit comments