From a515de580737ca1a50e2ce458126c4bcc66a1fbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Domeradzki?= Date: Sun, 3 Jun 2018 07:51:20 +0200 Subject: [PATCH] Implement support for mono (#806) * Initial buggy mono support * Start building generic-netf variant * Fix CIs * Disable ILLink.Tasks for generic-netf * Make generic-netf *special* * Keep fixing Don't ask me why reverse order works, this is next-gen msbuild magic * Mono compat * Mono compat * Misc * Update to .NET Framework 4.7.2 * .NET 4.7.2 compat * Misc --- .travis.yml | 9 ++- ArchiSteamFarm/ASF.cs | 2 +- ArchiSteamFarm/ArchiLogger.cs | 4 +- ArchiSteamFarm/ArchiSteamFarm.csproj | 16 +++- ArchiSteamFarm/Bot.cs | 6 +- ArchiSteamFarm/BotConfig.cs | 4 +- ArchiSteamFarm/BotDatabase.cs | 4 +- ArchiSteamFarm/GlobalConfig.cs | 4 +- ArchiSteamFarm/GlobalDatabase.cs | 4 +- ArchiSteamFarm/IPC.cs | 4 +- ArchiSteamFarm/RuntimeCompatibility.cs | 101 +++++++++++++++++++++++++ ArchiSteamFarm/SharedInfo.cs | 3 + ArchiSteamFarm/WebBrowser.cs | 9 ++- appveyor.yml | 40 +++++++--- 14 files changed, 174 insertions(+), 36 deletions(-) create mode 100644 ArchiSteamFarm/RuntimeCompatibility.cs diff --git a/.travis.yml b/.travis.yml index 160a1e394..38831e5b5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -24,6 +24,7 @@ env: - CONFIGURATION: Release - DOTNET_CLI_TELEMETRY_OPTOUT: 1 - DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1 + - NET_CORE_VERSION: netcoreapp2.0 - VARIANTS="generic linux-arm linux-x64 osx-x64 win-x64" # NOTE: When modifying variants, don't forget to update ASF_VARIANT definitions in SharedInfo.cs! before_script: @@ -40,14 +41,14 @@ script: - | set -e - dotnet build ArchiSteamFarm -c "$CONFIGURATION" -o 'out/source' /nologo - dotnet test ArchiSteamFarm.Tests -c "$CONFIGURATION" -o 'out/source' /nologo + dotnet build ArchiSteamFarm -c "$CONFIGURATION" -f "$NET_CORE_VERSION" -o 'out/source' /nologo + dotnet test ArchiSteamFarm.Tests -c "$CONFIGURATION" -f "$NET_CORE_VERSION" -o 'out/source' /nologo publish() { if [ "$1" = 'generic' ]; then - dotnet publish ArchiSteamFarm -c "$CONFIGURATION" -o "out/${1}" /nologo "/p:ASFVariant=$1" + dotnet publish ArchiSteamFarm -c "$CONFIGURATION" -f "$NET_CORE_VERSION" -o "out/${1}" /nologo "/p:ASFVariant=$1" else - dotnet publish ArchiSteamFarm -c "$CONFIGURATION" -o "out/${1}" -r "$1" /nologo "/p:ASFVariant=$1" "/p:CrossGenDuringPublish=false" + dotnet publish ArchiSteamFarm -c "$CONFIGURATION" -f "$NET_CORE_VERSION" -o "out/${1}" -r "$1" /nologo "/p:ASFVariant=$1" "/p:CrossGenDuringPublish=false" fi # If we include any helper scripts for this variant, copy them to output directory diff --git a/ArchiSteamFarm/ASF.cs b/ArchiSteamFarm/ASF.cs index 83dda9804..7bcab779d 100644 --- a/ArchiSteamFarm/ASF.cs +++ b/ArchiSteamFarm/ASF.cs @@ -548,7 +548,7 @@ namespace ArchiSteamFarm { string runtimesDirectory = Path.Combine(targetDirectory, "runtimes"); if (Directory.Exists(runtimesDirectory)) { foreach (string file in Directory.EnumerateFiles(runtimesDirectory, "*", SearchOption.AllDirectories)) { - string directory = Path.Combine(backupDirectory, Path.GetDirectoryName(Path.GetRelativePath(targetDirectory, file))); + string directory = Path.Combine(backupDirectory, Path.GetDirectoryName(RuntimeCompatibility.Path.GetRelativePath(targetDirectory, file))); Directory.CreateDirectory(directory); string target = Path.Combine(directory, Path.GetFileName(file)); diff --git a/ArchiSteamFarm/ArchiLogger.cs b/ArchiSteamFarm/ArchiLogger.cs index 7213087f8..0db5b8d88 100644 --- a/ArchiSteamFarm/ArchiLogger.cs +++ b/ArchiSteamFarm/ArchiLogger.cs @@ -56,7 +56,7 @@ namespace ArchiSteamFarm { string message = string.Format(DateTime.Now + " " + Strings.ErrorEarlyFatalExceptionInfo + Environment.NewLine, SharedInfo.Version); try { - await File.WriteAllTextAsync(SharedInfo.LogFile, message).ConfigureAwait(false); + await RuntimeCompatibility.File.WriteAllTextAsync(SharedInfo.LogFile, message).ConfigureAwait(false); } catch { // Ignored, we can't do anything with this } @@ -71,7 +71,7 @@ namespace ArchiSteamFarm { message = string.Format(Strings.ErrorEarlyFatalExceptionPrint, previousMethodName, exception.Message, exception.StackTrace); try { - await File.AppendAllTextAsync(SharedInfo.LogFile, message).ConfigureAwait(false); + await RuntimeCompatibility.File.AppendAllTextAsync(SharedInfo.LogFile, message).ConfigureAwait(false); } catch { // Ignored, we can't do anything with this } diff --git a/ArchiSteamFarm/ArchiSteamFarm.csproj b/ArchiSteamFarm/ArchiSteamFarm.csproj index fb7fbbdc3..3d0aec4cd 100644 --- a/ArchiSteamFarm/ArchiSteamFarm.csproj +++ b/ArchiSteamFarm/ArchiSteamFarm.csproj @@ -20,7 +20,7 @@ https://github.com/JustArchi/ArchiSteamFarm.git linux-arm;linux-x64;osx-x64;win-x64 false - netcoreapp2.0 + netcoreapp2.0;net472 @@ -38,13 +38,25 @@ - + + + + + + + C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2\System.Net.Http.dll + + + C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2\System.Security.dll + + + diff --git a/ArchiSteamFarm/Bot.cs b/ArchiSteamFarm/Bot.cs index 624783249..f8fa29a36 100755 --- a/ArchiSteamFarm/Bot.cs +++ b/ArchiSteamFarm/Bot.cs @@ -1414,7 +1414,7 @@ namespace ArchiSteamFarm { ArchiLogger.LogGenericInfo(Strings.BotAuthenticatorConverting); try { - MobileAuthenticator authenticator = JsonConvert.DeserializeObject(await File.ReadAllTextAsync(maFilePath).ConfigureAwait(false)); + MobileAuthenticator authenticator = JsonConvert.DeserializeObject(await RuntimeCompatibility.File.ReadAllTextAsync(maFilePath).ConfigureAwait(false)); await BotDatabase.SetMobileAuthenticator(authenticator).ConfigureAwait(false); File.Delete(maFilePath); } catch (Exception e) { @@ -1716,7 +1716,7 @@ namespace ArchiSteamFarm { if (File.Exists(SentryFilePath)) { try { - byte[] sentryFileContent = await File.ReadAllBytesAsync(SentryFilePath).ConfigureAwait(false); + byte[] sentryFileContent = await RuntimeCompatibility.File.ReadAllBytesAsync(SentryFilePath).ConfigureAwait(false); sentryFileHash = SteamKit2.CryptoHelper.SHAHash(sentryFileContent); } catch (Exception e) { ArchiLogger.LogGenericException(e); @@ -2459,7 +2459,7 @@ namespace ArchiSteamFarm { string logEntry = name + DefaultBackgroundKeysRedeemerSeparator + "[" + result.PurchaseResultDetail + "]" + ((result.Items != null) && (result.Items.Count > 0) ? DefaultBackgroundKeysRedeemerSeparator + string.Join("", result.Items) : "") + DefaultBackgroundKeysRedeemerSeparator + key; try { - await File.AppendAllTextAsync(redeemed ? KeysToRedeemUsedFilePath : KeysToRedeemUnusedFilePath, logEntry + Environment.NewLine).ConfigureAwait(false); + await RuntimeCompatibility.File.AppendAllTextAsync(redeemed ? KeysToRedeemUsedFilePath : KeysToRedeemUnusedFilePath, logEntry + Environment.NewLine).ConfigureAwait(false); } catch (Exception e) { ArchiLogger.LogGenericException(e); ArchiLogger.LogGenericError(string.Format(Strings.Content, logEntry)); diff --git a/ArchiSteamFarm/BotConfig.cs b/ArchiSteamFarm/BotConfig.cs index a3a93c1cd..b9728bef9 100644 --- a/ArchiSteamFarm/BotConfig.cs +++ b/ArchiSteamFarm/BotConfig.cs @@ -161,7 +161,7 @@ namespace ArchiSteamFarm { BotConfig botConfig; try { - botConfig = JsonConvert.DeserializeObject(await File.ReadAllTextAsync(filePath).ConfigureAwait(false)); + botConfig = JsonConvert.DeserializeObject(await RuntimeCompatibility.File.ReadAllTextAsync(filePath).ConfigureAwait(false)); } catch (Exception e) { ASF.ArchiLogger.LogGenericException(e); return null; @@ -207,7 +207,7 @@ namespace ArchiSteamFarm { await WriteSemaphore.WaitAsync().ConfigureAwait(false); try { - await File.WriteAllTextAsync(newFilePath, json).ConfigureAwait(false); + await RuntimeCompatibility.File.WriteAllTextAsync(newFilePath, json).ConfigureAwait(false); if (File.Exists(filePath)) { File.Replace(newFilePath, filePath, null); diff --git a/ArchiSteamFarm/BotDatabase.cs b/ArchiSteamFarm/BotDatabase.cs index fb97d1ef0..c54876902 100644 --- a/ArchiSteamFarm/BotDatabase.cs +++ b/ArchiSteamFarm/BotDatabase.cs @@ -198,7 +198,7 @@ namespace ArchiSteamFarm { BotDatabase botDatabase; try { - botDatabase = JsonConvert.DeserializeObject(await File.ReadAllTextAsync(filePath).ConfigureAwait(false)); + botDatabase = JsonConvert.DeserializeObject(await RuntimeCompatibility.File.ReadAllTextAsync(filePath).ConfigureAwait(false)); } catch (Exception e) { ASF.ArchiLogger.LogGenericException(e); return null; @@ -320,7 +320,7 @@ namespace ArchiSteamFarm { } // We always want to write entire content to temporary file first, in order to never load corrupted data, also when target file doesn't exist - await File.WriteAllTextAsync(newFilePath, json).ConfigureAwait(false); + await RuntimeCompatibility.File.WriteAllTextAsync(newFilePath, json).ConfigureAwait(false); if (File.Exists(FilePath)) { File.Replace(newFilePath, FilePath, null); diff --git a/ArchiSteamFarm/GlobalConfig.cs b/ArchiSteamFarm/GlobalConfig.cs index 8593bed89..4b7f7be91 100644 --- a/ArchiSteamFarm/GlobalConfig.cs +++ b/ArchiSteamFarm/GlobalConfig.cs @@ -257,7 +257,7 @@ namespace ArchiSteamFarm { GlobalConfig globalConfig; try { - globalConfig = JsonConvert.DeserializeObject(await File.ReadAllTextAsync(filePath).ConfigureAwait(false)); + globalConfig = JsonConvert.DeserializeObject(await RuntimeCompatibility.File.ReadAllTextAsync(filePath).ConfigureAwait(false)); } catch (Exception e) { ASF.ArchiLogger.LogGenericException(e); return null; @@ -314,7 +314,7 @@ namespace ArchiSteamFarm { await WriteSemaphore.WaitAsync().ConfigureAwait(false); try { - await File.WriteAllTextAsync(newFilePath, json).ConfigureAwait(false); + await RuntimeCompatibility.File.WriteAllTextAsync(newFilePath, json).ConfigureAwait(false); if (File.Exists(filePath)) { File.Replace(newFilePath, filePath, null); diff --git a/ArchiSteamFarm/GlobalDatabase.cs b/ArchiSteamFarm/GlobalDatabase.cs index 2ba57a4fd..c61c77cad 100644 --- a/ArchiSteamFarm/GlobalDatabase.cs +++ b/ArchiSteamFarm/GlobalDatabase.cs @@ -90,7 +90,7 @@ namespace ArchiSteamFarm { GlobalDatabase globalDatabase; try { - globalDatabase = JsonConvert.DeserializeObject(await File.ReadAllTextAsync(filePath).ConfigureAwait(false)); + globalDatabase = JsonConvert.DeserializeObject(await RuntimeCompatibility.File.ReadAllTextAsync(filePath).ConfigureAwait(false)); } catch (Exception e) { ASF.ArchiLogger.LogGenericException(e); return null; @@ -159,7 +159,7 @@ namespace ArchiSteamFarm { try { // We always want to write entire content to temporary file first, in order to never load corrupted data, also when target file doesn't exist - await File.WriteAllTextAsync(newFilePath, json).ConfigureAwait(false); + await RuntimeCompatibility.File.WriteAllTextAsync(newFilePath, json).ConfigureAwait(false); if (File.Exists(FilePath)) { File.Replace(newFilePath, FilePath, null); diff --git a/ArchiSteamFarm/IPC.cs b/ArchiSteamFarm/IPC.cs index 3fd92e73c..cd65cef4f 100644 --- a/ArchiSteamFarm/IPC.cs +++ b/ArchiSteamFarm/IPC.cs @@ -951,7 +951,7 @@ namespace ArchiSteamFarm { authorized = password == Program.GlobalConfig.IPCPassword; if (authorized) { - FailedAuthorizations.Remove(ipAddress, out _); + FailedAuthorizations.TryRemove(ipAddress, out _); } else { if (FailedAuthorizations.TryGetValue(ipAddress, out attempts)) { FailedAuthorizations[ipAddress] = ++attempts; @@ -1095,7 +1095,7 @@ namespace ArchiSteamFarm { try { response.ContentType = MimeTypes.TryGetValue(Path.GetExtension(filePath), out string mimeType) ? mimeType : "application/octet-stream"; - byte[] content = await File.ReadAllBytesAsync(filePath).ConfigureAwait(false); + byte[] content = await RuntimeCompatibility.File.ReadAllBytesAsync(filePath).ConfigureAwait(false); await ResponseBase(request, response, content).ConfigureAwait(false); } catch (FileNotFoundException) { await ResponseStatusCode(request, response, HttpStatusCode.NotFound).ConfigureAwait(false); diff --git a/ArchiSteamFarm/RuntimeCompatibility.cs b/ArchiSteamFarm/RuntimeCompatibility.cs new file mode 100644 index 000000000..afaccdede --- /dev/null +++ b/ArchiSteamFarm/RuntimeCompatibility.cs @@ -0,0 +1,101 @@ +// _ _ _ ____ _ _____ +// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___ +// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \ +// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | | +// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_| +// +// Copyright 2015-2018 Łukasz "JustArchi" Domeradzki +// Contact: JustArchi@JustArchi.net +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using System; +using System.Threading.Tasks; + +#if NET472 +using System.Net.WebSockets; +using System.Threading; +#endif + +namespace ArchiSteamFarm { + internal static class RuntimeCompatibility { + internal static bool IsRunningOnMono => Type.GetType("Mono.Runtime") != null; + +#if NET472 + internal static async Task ReceiveAsync(this WebSocket webSocket, byte[] buffer, CancellationToken cancellationToken) => await webSocket.ReceiveAsync(new ArraySegment(buffer), cancellationToken).ConfigureAwait(false); + + internal static async Task SendAsync(this WebSocket webSocket, byte[] buffer, WebSocketMessageType messageType, bool endOfMessage, CancellationToken cancellationToken) { + await webSocket.SendAsync(new ArraySegment(buffer), messageType, endOfMessage, cancellationToken).ConfigureAwait(false); + } + + internal static string[] Split(this string text, char separator, StringSplitOptions options = StringSplitOptions.None) => text.Split(new[] { separator }, options); +#endif + + internal static class File { +#pragma warning disable 1998 + internal static async Task AppendAllTextAsync(string path, string contents) { +#if NET472 + System.IO.File.AppendAllText(path, contents); +#else + await System.IO.File.AppendAllTextAsync(path, contents).ConfigureAwait(false); +#endif + } + + internal static async Task ReadAllBytesAsync(string path) { +#if NET472 + return System.IO.File.ReadAllBytes(path); +#else + return await System.IO.File.ReadAllBytesAsync(path).ConfigureAwait(false); +#endif + } + + internal static async Task ReadAllTextAsync(string path) { +#if NET472 + return System.IO.File.ReadAllText(path); +#else + return await System.IO.File.ReadAllTextAsync(path).ConfigureAwait(false); +#endif + } + + internal static async Task WriteAllTextAsync(string path, string contents) { +#if NET472 + System.IO.File.WriteAllText(path, contents); +#else + await System.IO.File.WriteAllTextAsync(path, contents).ConfigureAwait(false); +#endif + } +#pragma warning restore 1998 + } + + internal static class Path { + internal static string GetRelativePath(string relativeTo, string path) { +#if NET472 + // This is a very silly implementation + if (!path.StartsWith(relativeTo, StringComparison.OrdinalIgnoreCase)) { + throw new NotImplementedException(); + } + + string result = path.Substring(relativeTo.Length); + + if ((result[0] == System.IO.Path.DirectorySeparatorChar) || (result[0] == System.IO.Path.AltDirectorySeparatorChar)) { + return result.Substring(1); + } + + return result; +#else + return System.IO.Path.GetRelativePath(relativeTo, path); +#endif + } + } + } +} \ No newline at end of file diff --git a/ArchiSteamFarm/SharedInfo.cs b/ArchiSteamFarm/SharedInfo.cs index 11f8b1186..6ea472706 100644 --- a/ArchiSteamFarm/SharedInfo.cs +++ b/ArchiSteamFarm/SharedInfo.cs @@ -62,6 +62,9 @@ namespace ArchiSteamFarm { #elif ASF_VARIANT_GENERIC internal static readonly bool CanUpdate = true; internal static readonly string Variant = "generic"; +#elif ASF_VARIANT_GENERIC_NETF + internal static readonly bool CanUpdate = true; + internal static readonly string Variant = "generic-netf"; #elif ASF_VARIANT_LINUX_ARM internal static readonly bool CanUpdate = true; internal static readonly string Variant = "linux-arm"; diff --git a/ArchiSteamFarm/WebBrowser.cs b/ArchiSteamFarm/WebBrowser.cs index d9a52541c..07d728b03 100644 --- a/ArchiSteamFarm/WebBrowser.cs +++ b/ArchiSteamFarm/WebBrowser.cs @@ -52,11 +52,14 @@ namespace ArchiSteamFarm { AllowAutoRedirect = false, // This must be false if we want to handle custom redirection schemes such as "steammobile" AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip, CookieContainer = CookieContainer, - MaxConnectionsPerServer = MaxConnections, Proxy = webProxy, UseProxy = webProxy != null }; + if (!RuntimeCompatibility.IsRunningOnMono) { + httpClientHandler.MaxConnectionsPerServer = MaxConnections; + } + HttpClient = new HttpClient(httpClientHandler) { Timeout = TimeSpan.FromSeconds(extendedTimeout ? ExtendedTimeoutMultiplier * Program.GlobalConfig.ConnectionTimeout : Program.GlobalConfig.ConnectionTimeout) }; // Most web services expect that UserAgent is set, so we declare it globally @@ -76,7 +79,9 @@ namespace ArchiSteamFarm { ServicePointManager.Expect100Continue = false; // Reuse ports if possible - ServicePointManager.ReusePort = true; + if (!RuntimeCompatibility.IsRunningOnMono) { + ServicePointManager.ReusePort = true; + } } internal static HtmlDocument StringToHtmlDocument(string html) { diff --git a/appveyor.yml b/appveyor.yml index 81ab5c64d..e6faf9b1e 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -14,6 +14,9 @@ clone_depth: 10 environment: DOTNET_CLI_TELEMETRY_OPTOUT: true DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true + NET_CORE_VERSION: netcoreapp2.0 + NET_FRAMEWORK_VERSION: net472 + SINGLE_VARIANTS: generic-netf # NOTE: When modifying variants, don't forget to update ASF_VARIANT definitions in SharedInfo.cs! VARIANTS: generic linux-arm linux-x64 osx-x64 win-x64 # NOTE: When modifying variants, don't forget to update ASF_VARIANT definitions in SharedInfo.cs! matrix: allow_failures: @@ -42,7 +45,7 @@ build_script: $ProgressPreference = 'SilentlyContinue' - dotnet build ArchiSteamFarm -c "$env:CONFIGURATION" -o 'out\source' /nologo + dotnet build ArchiSteamFarm -c "$env:CONFIGURATION" -f "$env:NET_CORE_VERSION" -o 'out\source' /nologo if ($LastExitCode -ne 0) { throw "Last command failed." @@ -56,7 +59,7 @@ test_script: $ProgressPreference = 'SilentlyContinue' - dotnet test ArchiSteamFarm.Tests -c "$env:CONFIGURATION" -o 'out\source' /nologo + dotnet test ArchiSteamFarm.Tests -c "$env:CONFIGURATION" -f "$env:NET_CORE_VERSION" -o 'out\source' /nologo if ($LastExitCode -ne 0) { throw "Last command failed." @@ -79,10 +82,16 @@ after_test: Set-Location -Path "$env:APPVEYOR_BUILD_FOLDER" - if ($Variant -eq 'generic') { - dotnet publish ArchiSteamFarm -c "$env:CONFIGURATION" -o "out\$Variant" /nologo "/p:ASFVariant=$Variant" + if ($Variant -like '*-netf') { + $TargetFramework = $env:NET_FRAMEWORK_VERSION } else { - dotnet publish ArchiSteamFarm -c "$env:CONFIGURATION" -o "out\$Variant" -r "$Variant" /nologo "/p:ASFVariant=$Variant" "/p:CrossGenDuringPublish=false" + $TargetFramework = $env:NET_CORE_VERSION + } + + if ($Variant -like 'generic*') { + dotnet publish ArchiSteamFarm -c "$env:CONFIGURATION" -f "$TargetFramework" -o "out\$Variant" /nologo "/p:ASFVariant=$Variant" + } else { + dotnet publish ArchiSteamFarm -c "$env:CONFIGURATION" -f "$TargetFramework" -o "out\$Variant" -r "$Variant" /nologo "/p:ASFVariant=$Variant" "/p:CrossGenDuringPublish=false" } if ($LastExitCode -ne 0) { @@ -94,15 +103,17 @@ after_test: Copy-Item "ArchiSteamFarm\scripts\$Variant\*" -Destination "ArchiSteamFarm\out\$Variant" } - # Until https://github.com/dotnet/cli/issues/3267 happens, we'll hack dotnet binary icon on Windows and include .ico file on other platforms - if (Test-Path -Path "ArchiSteamFarm\out\$Variant\ArchiSteamFarm.exe" -PathType Leaf) { - tools\rcedit\rcedit-x64.exe "ArchiSteamFarm\out\$Variant\ArchiSteamFarm.exe" --set-icon 'resources\ASF.ico' + if ($TargetFramework -eq "$env:NET_CORE_VERSION") { + # Until https://github.com/dotnet/cli/issues/3267 happens, we'll hack dotnet binary icon on Windows and include .ico file on other platforms + if (Test-Path -Path "ArchiSteamFarm\out\$Variant\ArchiSteamFarm.exe" -PathType Leaf) { + tools\rcedit\rcedit-x64.exe "ArchiSteamFarm\out\$Variant\ArchiSteamFarm.exe" --set-icon 'resources\ASF.ico' - if ($LastExitCode -ne 0) { - throw "Last command failed." + if ($LastExitCode -ne 0) { + throw "Last command failed." + } + } else { + Copy-Item 'resources\ASF.ico' -Destination "ArchiSteamFarm\out\$Variant\ArchiSteamFarm.ico" } - } else { - Copy-Item 'resources\ASF.ico' -Destination "ArchiSteamFarm\out\$Variant\ArchiSteamFarm.ico" } $zipArgs = '-mx=1' @@ -132,6 +143,11 @@ after_test: } } + foreach ($variant in $env:SINGLE_VARIANTS.Split([char[]] $null, [System.StringSplitOptions]::RemoveEmptyEntries)) { + Start-Job -Name "$variant" -ScriptBlock $PublishBlock -ArgumentList "$variant" + Get-Job | Receive-Job -AutoRemoveJob -Wait + } + foreach ($variant in $env:VARIANTS.Split([char[]] $null, [System.StringSplitOptions]::RemoveEmptyEntries)) { Start-Job -Name "$variant" -ScriptBlock $PublishBlock -ArgumentList "$variant" }