diff --git a/.gitattributes b/.gitattributes index 333ad1d9..a57a77c7 100644 --- a/.gitattributes +++ b/.gitattributes @@ -29,6 +29,8 @@ *.docx binary *.pptx binary *.bin binary +*.exe binary +test/Verifiable.FuzzTests/libfuzzer-dotnet-ubuntu binary *.gz filter=lfs diff=lfs merge=lfs -text *.jffs2 filter=lfs diff=lfs merge=lfs -text *.zip filter=lfs diff=lfs merge=lfs -text @@ -47,3 +49,6 @@ *.wav filter=lfs diff=lfs merge=lfs -text *.myo filter=lfs diff=lfs merge=lfs -text *.vsmdi filter=lfs diff=lfs merge=lfs -text +*.vsmdi filter=lfs diff=lfs merge=lfs -text + + diff --git a/Directory.Packages.props b/Directory.Packages.props index 1d558f69..e96b8609 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -22,8 +22,7 @@ - - + diff --git a/Verifiable.sln b/Verifiable.sln index 6889f63c..89d78a05 100644 --- a/Verifiable.sln +++ b/Verifiable.sln @@ -70,6 +70,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".vscode", ".vscode", "{BE64 .vscode\tasks.json = .vscode\tasks.json EndProjectSection EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Verifiable.FuzzTests", "test\Verifiable.FuzzTests\Verifiable.FuzzTests.csproj", "{A50E91E9-51A8-490D-B92B-97C547B98539}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -120,6 +122,10 @@ Global {FF947DEC-29E7-4700-94A4-0E84B2917BF5}.Debug|Any CPU.Build.0 = Debug|Any CPU {FF947DEC-29E7-4700-94A4-0E84B2917BF5}.Release|Any CPU.ActiveCfg = Release|Any CPU {FF947DEC-29E7-4700-94A4-0E84B2917BF5}.Release|Any CPU.Build.0 = Release|Any CPU + {A50E91E9-51A8-490D-B92B-97C547B98539}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A50E91E9-51A8-490D-B92B-97C547B98539}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A50E91E9-51A8-490D-B92B-97C547B98539}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A50E91E9-51A8-490D-B92B-97C547B98539}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -140,6 +146,7 @@ Global {1B79A5A8-0754-4F72-AD32-E791F9A8ED23} = {737B175F-5A06-480C-B93F-42B31EF4EFA7} {CD06BE0E-287F-4A01-B500-CD92465F1E2D} = {35CAB8A9-7332-4D46-BBD3-83A37A747F5E} {BE64721C-A756-4078-B683-34AC9B639E28} = {35CAB8A9-7332-4D46-BBD3-83A37A747F5E} + {A50E91E9-51A8-490D-B92B-97C547B98539} = {942BE00F-D1A2-405C-80F3-D854D373E1FF} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {B3AC63DE-C110-4924-B7DB-FFAC4704246F} diff --git a/test/Verifiable.FuzzTests/Program.cs b/test/Verifiable.FuzzTests/Program.cs new file mode 100644 index 00000000..035f80c4 --- /dev/null +++ b/test/Verifiable.FuzzTests/Program.cs @@ -0,0 +1,40 @@ +using SharpFuzz; +using System; +using System.Diagnostics; +using System.Text; +using System.Text.Json; +using static System.Runtime.InteropServices.JavaScript.JSType; + + +namespace Verifiable.FuzzTests +{ + public class Program + { + public static void Main(string[] args) + { + Fuzzer.LibFuzzer.Run(json => + { + try + { + Console.WriteLine("Start"); + Debug.WriteLine("Start"); + string jsonString = Encoding.UTF8.GetString(json); + if(jsonString is null) + { + Console.WriteLine("Fuzzer provided a null input."); + return; + } + + _ = JsonSerializer.Deserialize(jsonString); + } + catch(JsonException) + { + } + catch(Exception ex) + { + Console.WriteLine($"Unexpected exception occurred: {ex.Message}"); + } + }); + } + } +} diff --git a/test/Verifiable.FuzzTests/Verifiable.FuzzTests.csproj b/test/Verifiable.FuzzTests/Verifiable.FuzzTests.csproj new file mode 100644 index 00000000..6ece23b4 --- /dev/null +++ b/test/Verifiable.FuzzTests/Verifiable.FuzzTests.csproj @@ -0,0 +1,13 @@ + + + + Exe + net9.0 + disable + + + + + + + diff --git a/test/Verifiable.FuzzTests/dictionaries/json.dict b/test/Verifiable.FuzzTests/dictionaries/json.dict new file mode 100644 index 00000000..0d10f58b --- /dev/null +++ b/test/Verifiable.FuzzTests/dictionaries/json.dict @@ -0,0 +1,73 @@ +"0" +"7" +"," +":" +"2.1e24" + +"true" +"false" +"null" + +"\"\"" +"\"\":" + +"{}" +",{}" +":{}" +"{\"\":0}" +"{{}}" + +"[]" +",[]" +":[]" +"[0]" +"[[]]" + +"''" +"\\" +"\\b" +"\\f" +"\\n" +"\\r" +"\\t" +"\\u0000" +"\\x00" +"\\0" +"\\uD800\\uDC00" +"\\uDBFF\\uDFFF" + +"\"\":0" +"//" +"/**/" + + +# Things like geojson, json-ld, ... +"$ref" +"type" +"coordinates" +"@context" +"@id" +"@type" + +# Strings with truncated special values +"{\"foo\":fa" +"{\"foo\":t" +"{\"foo\":nul" + +"{" +"}" +"\"qty\": 1, \"qty\": -1" +"\"qty\": 1, \"qty\\ud800\": -1" +"\"qty\": 1, \"qt\\y\": -1" +"/*" +"*/" +"\"" +"1.7976931348623157e+308" +"5e-324" +"9007199254740991" +"-9007199254740991" + +"}=" + +",," +"{\"\":" \ No newline at end of file diff --git a/test/Verifiable.FuzzTests/direct-crash-fuzz-sample.ps1 b/test/Verifiable.FuzzTests/direct-crash-fuzz-sample.ps1 new file mode 100644 index 00000000..58afbed1 --- /dev/null +++ b/test/Verifiable.FuzzTests/direct-crash-fuzz-sample.ps1 @@ -0,0 +1 @@ +./libfuzzer-dotnet-windows.exe --target_path=bin/release/net9.0/Verifiable.FuzzTests.exe ./crash- -timeout=10 -minimize_crash=1 \ No newline at end of file diff --git a/test/Verifiable.FuzzTests/do-fuzzing.ps1 b/test/Verifiable.FuzzTests/do-fuzzing.ps1 new file mode 100644 index 00000000..bc1df184 --- /dev/null +++ b/test/Verifiable.FuzzTests/do-fuzzing.ps1 @@ -0,0 +1 @@ +.\fuzz.ps1 -libFuzzer ".\libfuzzer-dotnet-windows.exe" -project ".\Verifiable.FuzzTests.csproj" -corpus .\testcases\test-1.json -dict .\dictionaries\json.dict -timeout 10 \ No newline at end of file diff --git a/test/Verifiable.FuzzTests/fuzz.ps1 b/test/Verifiable.FuzzTests/fuzz.ps1 new file mode 100644 index 00000000..e8224d19 --- /dev/null +++ b/test/Verifiable.FuzzTests/fuzz.ps1 @@ -0,0 +1,72 @@ +param ( + [Parameter(Mandatory = $true)] + [string]$libFuzzer, + [Parameter(Mandatory = $true)] + [string]$project, + [Parameter(Mandatory = $true)] + [string]$corpus, + [string]$dict = $null, + [int]$timeout = 10, + [int]$fork = 0, + [int]$ignore_crashes = 0, + [string]$command = "sharpfuzz" +) + +Set-StrictMode -Version Latest + +$outputDir = "bin" + +if (Test-Path $outputDir) { + Remove-Item -Recurse -Force $outputDir +} + +dotnet publish $project -c release -o $outputDir + +$projectName = (Get-Item $project).BaseName +$projectDll = "$projectName.dll" +$project = Join-Path $outputDir $projectDll + +$exclusions = @( + "dnlib.dll", + "SharpFuzz.dll", + "SharpFuzz.Common.dll" +) + +Write-Output "Exclusions: $($exclusions -join ', ')" + +$allDlls = Get-ChildItem $outputDir -Filter *.dll +Write-Output "All DLLs: $($allDlls.Name -join ', ')" + +$fuzzingTargets = $allDlls ` +| Where-Object { $_.Name -notin $exclusions } ` +| Where-Object { $_.Name -notlike "System.*.dll" } + +Write-Output "Fuzzing Targets: $($fuzzingTargets.Name -join ', ')" + +if (($fuzzingTargets | Measure-Object).Count -eq 0) { + Write-Error "No fuzzing targets found" + exit 1 +} + +foreach ($fuzzingTarget in $fuzzingTargets) { + Write-Output "Instrumenting $fuzzingTarget" + & $command $fuzzingTarget.FullName + + if ($LastExitCode -ne 0) { + Write-Error "An error occurred while instrumenting $fuzzingTarget" + exit 1 + } +} + +# Construct the final command string +$finalCommand = "$libFuzzer --target_path=dotnet --target_arg=$project" + +if ($dict) { + $finalCommand += " -dict=$dict" +} + +# Print the final command +Write-Output "Final Command: $finalCommand" + +# Execute the final command +Invoke-Expression $finalCommand diff --git a/test/Verifiable.FuzzTests/libfuzzer-dotnet-ubuntu b/test/Verifiable.FuzzTests/libfuzzer-dotnet-ubuntu new file mode 100644 index 00000000..1ce4ba12 Binary files /dev/null and b/test/Verifiable.FuzzTests/libfuzzer-dotnet-ubuntu differ diff --git a/test/Verifiable.FuzzTests/libfuzzer-dotnet-windows.exe b/test/Verifiable.FuzzTests/libfuzzer-dotnet-windows.exe new file mode 100644 index 00000000..605081ec --- /dev/null +++ b/test/Verifiable.FuzzTests/libfuzzer-dotnet-windows.exe @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5b3c811c2317b51fa47ba4d1ffb14a7b42039f228fdd382ad46e6bdb3110468d +size 1399296 diff --git a/test/Verifiable.FuzzTests/packages.lock.json b/test/Verifiable.FuzzTests/packages.lock.json new file mode 100644 index 00000000..1a347dc7 --- /dev/null +++ b/test/Verifiable.FuzzTests/packages.lock.json @@ -0,0 +1,61 @@ +{ + "version": 2, + "dependencies": { + "net9.0": { + "SharpFuzz": { + "type": "Direct", + "requested": "[2.1.1, )", + "resolved": "2.1.1", + "contentHash": "Xw5nP8CSxa6eK0gTaI2xbKhfP7VyQDdLYsfFBV6QeT9xyOzJ0a1Z3rJrmu3FTMl4DaRoMpBjFHppH+75QccddA==", + "dependencies": { + "SharpFuzz.Common": "2.2.0", + "System.Memory": "4.5.5", + "dnlib": "3.6.0" + } + }, + "SIL.ReleaseTasks": { + "type": "Direct", + "requested": "[2.6.0-beta0030, )", + "resolved": "2.6.0-beta0030", + "contentHash": "iytkRVZ7tEBY00kzB55Qs0/TyfYBJ0GyvRnDPKw2AfakBWrBBTkTCdBSAGmCFoL4Wf6asRFOrenRJ6VGGhCuUQ==", + "dependencies": { + "Markdig.Signed": "0.30.2" + } + }, + "dnlib": { + "type": "Transitive", + "resolved": "3.6.0", + "contentHash": "kFegKA+GR8a2mEzYH02TueIF1nNQ5lULAd9hgNwt6VBY2qNNZDYSwr63tMpKN0Lg+goDaZnaZczmP0/pDz2gaA==", + "dependencies": { + "System.Reflection.Emit": "4.7.0", + "System.Reflection.Emit.Lightweight": "4.7.0" + } + }, + "Markdig.Signed": { + "type": "Transitive", + "resolved": "0.30.2", + "contentHash": "nQlUtPbp9pQFoArFSp/CZb699W6pqBG/DSpnWHgKbIuQjAu3KNjTZHaIir2vSCPJZuSMGii7tbI6K+nalh4X7w==" + }, + "SharpFuzz.Common": { + "type": "Transitive", + "resolved": "2.2.0", + "contentHash": "biITWpwnMR7HUp43lAGU97DWq/4LfyXqqhuOK0Z4IuRP97KjQMOe/GKq3wE1KY21gNrc7OPO9HbAtQUvMKTImA==" + }, + "System.Memory": { + "type": "Transitive", + "resolved": "4.5.5", + "contentHash": "XIWiDvKPXaTveaB7HVganDlOCRoj03l+jrwNvcge/t8vhGYKvqV+dMv6G4SAX2NoNmN0wZfVPTAlFwZcZvVOUw==" + }, + "System.Reflection.Emit": { + "type": "Transitive", + "resolved": "4.7.0", + "contentHash": "VR4kk8XLKebQ4MZuKuIni/7oh+QGFmZW3qORd1GvBq/8026OpW501SzT/oypwiQl4TvT8ErnReh/NzY9u+C6wQ==" + }, + "System.Reflection.Emit.Lightweight": { + "type": "Transitive", + "resolved": "4.7.0", + "contentHash": "a4OLB4IITxAXJeV74MDx49Oq2+PsF6Sml54XAFv+2RyWwtDBcabzoxiiJRhdhx+gaohLh4hEGCLQyBozXoQPqA==" + } + } + } +} \ No newline at end of file diff --git a/test/Verifiable.FuzzTests/testcases/test-1.json b/test/Verifiable.FuzzTests/testcases/test-1.json new file mode 100644 index 00000000..2eb997b0 --- /dev/null +++ b/test/Verifiable.FuzzTests/testcases/test-1.json @@ -0,0 +1 @@ +{"menu":{"id":1,"val":"X","pop":{"a":[{"click":"Open()"},{"click":"Close()"}]}}} \ No newline at end of file diff --git a/test/Verifiable.Tests/Verifiable.Tests.csproj b/test/Verifiable.Tests/Verifiable.Tests.csproj index 0caee040..dc90aa66 100644 --- a/test/Verifiable.Tests/Verifiable.Tests.csproj +++ b/test/Verifiable.Tests/Verifiable.Tests.csproj @@ -13,9 +13,7 @@ - - - + diff --git a/test/Verifiable.Tests/packages.lock.json b/test/Verifiable.Tests/packages.lock.json index faf21fd9..8f3892b8 100644 --- a/test/Verifiable.Tests/packages.lock.json +++ b/test/Verifiable.Tests/packages.lock.json @@ -66,17 +66,6 @@ "Microsoft.TestPlatform.TestHost": "17.10.0" } }, - "SharpFuzz": { - "type": "Direct", - "requested": "[2.1.1, )", - "resolved": "2.1.1", - "contentHash": "Xw5nP8CSxa6eK0gTaI2xbKhfP7VyQDdLYsfFBV6QeT9xyOzJ0a1Z3rJrmu3FTMl4DaRoMpBjFHppH+75QccddA==", - "dependencies": { - "SharpFuzz.Common": "2.2.0", - "System.Memory": "4.5.5", - "dnlib": "3.6.0" - } - }, "SIL.ReleaseTasks": { "type": "Direct", "requested": "[2.6.0-beta0030, )", @@ -101,17 +90,6 @@ "resolved": "8.0.0", "contentHash": "+TUFINV2q2ifyXauQXRwy4CiBhqvDEDZeVJU7qfxya4aRYOKzVBpN+4acx25VcPB9ywUN6C0n8drWl110PhZEg==" }, - "WinSharpFuzz": { - "type": "Direct", - "requested": "[1.0.0, )", - "resolved": "1.0.0", - "contentHash": "cOmFMLha3eH8j5CLWu+n/1UkhydAMBg/4O01XqQGNUQe1L5Jy+uNz1D3Lh62UhEb3HUWhV4sl1B4vyihqkuTtA==", - "dependencies": { - "System.Memory": "4.5.4", - "WinSharpFuzz.Common": "1.0.0", - "dnlib": "3.3.1" - } - }, "xunit": { "type": "Direct", "requested": "[2.9.0, )", @@ -152,15 +130,6 @@ "System.Text.Encoding.CodePages": "8.0.0" } }, - "dnlib": { - "type": "Transitive", - "resolved": "3.6.0", - "contentHash": "kFegKA+GR8a2mEzYH02TueIF1nNQ5lULAd9hgNwt6VBY2qNNZDYSwr63tMpKN0Lg+goDaZnaZczmP0/pDz2gaA==", - "dependencies": { - "System.Reflection.Emit": "4.7.0", - "System.Reflection.Emit.Lightweight": "4.7.0" - } - }, "DotLiquid": { "type": "Transitive", "resolved": "2.1.405", @@ -511,11 +480,6 @@ "resolved": "4.3.2", "contentHash": "leXiwfiIkW7Gmn7cgnNcdtNAU70SjmKW3jxGj1iKHOvdn0zRWsgv/l2OJUO5zdGdiv2VRFnAsxxhDgMzofPdWg==" }, - "SharpFuzz.Common": { - "type": "Transitive", - "resolved": "2.2.0", - "contentHash": "biITWpwnMR7HUp43lAGU97DWq/4LfyXqqhuOK0Z4IuRP97KjQMOe/GKq3wE1KY21gNrc7OPO9HbAtQUvMKTImA==" - }, "SharpZipLib": { "type": "Transitive", "resolved": "1.4.2", @@ -808,16 +772,6 @@ "System.Runtime": "4.3.0" } }, - "System.Reflection.Emit": { - "type": "Transitive", - "resolved": "4.7.0", - "contentHash": "VR4kk8XLKebQ4MZuKuIni/7oh+QGFmZW3qORd1GvBq/8026OpW501SzT/oypwiQl4TvT8ErnReh/NzY9u+C6wQ==" - }, - "System.Reflection.Emit.Lightweight": { - "type": "Transitive", - "resolved": "4.7.0", - "contentHash": "a4OLB4IITxAXJeV74MDx49Oq2+PsF6Sml54XAFv+2RyWwtDBcabzoxiiJRhdhx+gaohLh4hEGCLQyBozXoQPqA==" - }, "System.Reflection.Extensions": { "type": "Transitive", "resolved": "4.3.0", @@ -1129,11 +1083,6 @@ "resolved": "2.0.0", "contentHash": "ogBkGWAZl4We1zBivoHcE41BM0ovlJ8OKwUhBDi+4aKoxWeUTtihdt9RZh4N2Y532e364vt4YgWiyq9Ne4KCZA==" }, - "WinSharpFuzz.Common": { - "type": "Transitive", - "resolved": "1.0.0", - "contentHash": "kTjAotNbHbI1c7Y18GHIzWnWF7j5EFTVaKieT3sGeTzfyoSvx0egKMMfwRFqxGCySD1r/Quv2zJ+YdXzT72O6g==" - }, "xunit.abstractions": { "type": "Transitive", "resolved": "2.0.3", diff --git a/workload-install.ps1 b/workload-install.ps1 new file mode 100644 index 00000000..cb38ab0c --- /dev/null +++ b/workload-install.ps1 @@ -0,0 +1,328 @@ +# +# Copyright (c) Samsung Electronics. All rights reserved. +# Licensed under the MIT license. See LICENSE file in the project root for full license information. +# + +<# +.SYNOPSIS +Installs Tizen workload manifest. +.DESCRIPTION +Installs the WorkloadManifest.json and WorkloadManifest.targets files for Tizen to the dotnet sdk. +.PARAMETER Version +Use specific VERSION +.PARAMETER DotnetInstallDir +Dotnet SDK Location installed +#> + +[cmdletbinding()] +param( + [Alias('v')][string]$Version="", + [Alias('d')][string]$DotnetInstallDir="", + [Alias('t')][string]$DotnetTargetVersionBand="", + [Alias('u')][switch]$UpdateAllWorkloads +) + +Set-StrictMode -Version Latest +$ErrorActionPreference = "Stop" +$ProgressPreference = "SilentlyContinue" + +$ManifestBaseName = "Samsung.NET.Sdk.Tizen.Manifest" +$global:FallbackId = "" + +$LatestVersionMap = [ordered]@{ + "$ManifestBaseName-6.0.100" = "7.0.101"; + "$ManifestBaseName-6.0.200" = "7.0.100-preview.13.6"; + "$ManifestBaseName-6.0.300" = "8.0.133"; + "$ManifestBaseName-6.0.400" = "8.0.140"; + "$ManifestBaseName-7.0.100-preview.6" = "7.0.100-preview.6.14"; + "$ManifestBaseName-7.0.100-preview.7" = "7.0.100-preview.7.20"; + "$ManifestBaseName-7.0.100-rc.1" = "7.0.100-rc.1.22"; + "$ManifestBaseName-7.0.100-rc.2" = "7.0.100-rc.2.24"; + "$ManifestBaseName-7.0.100" = "7.0.103"; + "$ManifestBaseName-7.0.200" = "7.0.105"; + "$ManifestBaseName-7.0.300" = "7.0.120"; + "$ManifestBaseName-7.0.400" = "8.0.141"; + "$ManifestBaseName-8.0.100-alpha.1" = "7.0.104"; + "$ManifestBaseName-8.0.100-preview.2" = "7.0.106"; + "$ManifestBaseName-8.0.100-preview.3" = "7.0.107"; + "$ManifestBaseName-8.0.100-preview.4" = "7.0.108"; + "$ManifestBaseName-8.0.100-preview.5" = "7.0.110"; + "$ManifestBaseName-8.0.100-preview.6" = "7.0.121"; + "$ManifestBaseName-8.0.100-preview.7" = "7.0.122"; + "$ManifestBaseName-8.0.100-rc.1" = "7.0.124"; + "$ManifestBaseName-8.0.100-rc.2" = "7.0.125"; + "$ManifestBaseName-8.0.100-rtm" = "7.0.127"; + "$ManifestBaseName-8.0.100" = "8.0.144"; + "$ManifestBaseName-8.0.200" = "8.0.145"; + "$ManifestBaseName-8.0.300" = "8.0.149"; + "$ManifestBaseName-9.0.100-alpha.1" = "8.0.134"; + "$ManifestBaseName-9.0.100-preview.1" = "8.0.135"; + "$ManifestBaseName-9.0.100-preview.2" = "8.0.137"; +} + +function New-TemporaryDirectory { + $parent = [System.IO.Path]::GetTempPath() + $name = [System.IO.Path]::GetRandomFileName() + New-Item -ItemType Directory -Path (Join-Path $parent $name) +} + +function Ensure-Directory([string]$TestDir) { + Try { + New-Item -ItemType Directory -Path $TestDir -Force -ErrorAction stop | Out-Null + [io.file]::OpenWrite($(Join-Path -Path $TestDir -ChildPath ".test-write-access")).Close() + Remove-Item -Path $(Join-Path -Path $TestDir -ChildPath ".test-write-access") -Force + } + Catch [System.UnauthorizedAccessException] { + Write-Error "No permission to install. Try run with administrator mode." + } +} + +function Get-LatestVersion([string]$Id) { + $attempts=3 + $sleepInSeconds=3 + do + { + try + { + $Response = Invoke-WebRequest -Uri https://api.nuget.org/v3-flatcontainer/$Id/index.json -UseBasicParsing | ConvertFrom-Json + return $Response.versions | Select-Object -Last 1 + } + catch { + Write-Host "Id: $Id" + Write-Host "An exception was caught: $($_.Exception.Message)" + } + + $attempts-- + if ($attempts -gt 0) { Start-Sleep $sleepInSeconds } + } while ($attempts -gt 0) + + if ($LatestVersionMap.Contains($Id)) + { + Write-Host "Return cached latest version." + return $LatestVersionMap.$Id + } + else + { + $SubStringId = $Id.Substring(0, $ManifestBaseName.Length + 2); + $MatchingFallbackId = @() + $MatchingFallbackVersion = @() + foreach ($key in $LatestVersionMap.Keys) { + if ($key -like "$SubStringId*") { + $MatchingFallbackId += $key + $MatchingFallbackVersion += $LatestVersionMap[$key] + } + } + if ($MatchingFallbackVersion) + { + $global:FallbackId = $MatchingFallbackId[-1] + $FallbackVersion = $MatchingFallbackVersion[-1] + Write-Host "Return fallback version: $FallbackVersion" + return $FallbackVersion + } + } + + Write-Error "Wrong Id: $Id" +} + +function Get-Package([string]$Id, [string]$Version, [string]$Destination, [string]$FileExt = "nupkg") { + $OutFileName = "$Id.$Version.$FileExt" + $OutFilePath = Join-Path -Path $Destination -ChildPath $OutFileName + + if ($Id -match ".net[0-9]+$") { + $Id = $Id -replace (".net[0-9]+", "") + } + + Invoke-WebRequest -Uri "https://www.nuget.org/api/v2/package/$Id/$Version" -OutFile $OutFilePath + + return $OutFilePath +} + +function Install-Pack([string]$Id, [string]$Version, [string]$Kind) { + $TempZipFile = $(Get-Package -Id $Id -Version $Version -Destination $TempDir -FileExt "zip") + $TempUnzipDir = Join-Path -Path $TempDir -ChildPath "unzipped\$Id" + + switch ($Kind) { + "manifest" { + Expand-Archive -Path $TempZipFile -DestinationPath $TempUnzipDir + New-Item -Path $TizenManifestDir -ItemType "directory" -Force | Out-Null + Copy-Item -Path "$TempUnzipDir\data\*" -Destination $TizenManifestDir -Force + } + {($_ -eq "sdk") -or ($_ -eq "framework")} { + Expand-Archive -Path $TempZipFile -DestinationPath $TempUnzipDir + if ( ($kind -eq "sdk") -and ($Id -match ".net[0-9]+$")) { + $Id = $Id -replace (".net[0-9]+", "") + } + $TargetDirectory = $(Join-Path -Path $DotnetInstallDir -ChildPath "packs\$Id\$Version") + New-Item -Path $TargetDirectory -ItemType "directory" -Force | Out-Null + Copy-Item -Path "$TempUnzipDir/*" -Destination $TargetDirectory -Recurse -Force + } + "template" { + $TargetFileName = "$Id.$Version.nupkg".ToLower() + $TargetDirectory = $(Join-Path -Path $DotnetInstallDir -ChildPath "template-packs") + New-Item -Path $TargetDirectory -ItemType "directory" -Force | Out-Null + Copy-Item $TempZipFile -Destination $(Join-Path -Path $TargetDirectory -ChildPath "$TargetFileName") -Force + } + } +} + +function Remove-Pack([string]$Id, [string]$Version, [string]$Kind) { + switch ($Kind) { + "manifest" { + Remove-Item -Path $TizenManifestDir -Recurse -Force + } + {($_ -eq "sdk") -or ($_ -eq "framework")} { + $TargetDirectory = $(Join-Path -Path $DotnetInstallDir -ChildPath "packs\$Id\$Version") + Remove-Item -Path $TargetDirectory -Recurse -Force + } + "template" { + $TargetFileName = "$Id.$Version.nupkg".ToLower(); + Remove-Item -Path $(Join-Path -Path $DotnetInstallDir -ChildPath "template-packs\$TargetFileName") -Force + } + } +} + +function Install-TizenWorkload([string]$DotnetVersion) +{ + $VersionSplitSymbol = '.' + $SplitVersion = $DotnetVersion.Split($VersionSplitSymbol) + + $CurrentDotnetVersion = [Version]"$($SplitVersion[0]).$($SplitVersion[1])" + $DotnetVersionBand = $SplitVersion[0] + $VersionSplitSymbol + $SplitVersion[1] + $VersionSplitSymbol + $SplitVersion[2][0] + "00" + $ManifestName = "$ManifestBaseName-$DotnetVersionBand" + + if ($DotnetTargetVersionBand -eq "" -or $UpdateAllWorkloads.IsPresent) { + if ($CurrentDotnetVersion -ge "7.0") + { + $IsPreviewVersion = $DotnetVersion.Contains("-preview") -or $DotnetVersion.Contains("-rc") -or $DotnetVersion.Contains("-alpha") + if ($IsPreviewVersion -and ($SplitVersion.Count -ge 4)) { + $DotnetTargetVersionBand = $DotnetVersionBand + $SplitVersion[2].SubString(3) + $VersionSplitSymbol + $($SplitVersion[3]) + $ManifestName = "$ManifestBaseName-$DotnetTargetVersionBand" + } + elseif ($DotnetVersion.Contains("-rtm") -and ($SplitVersion.Count -ge 3)) { + $DotnetTargetVersionBand = $DotnetVersionBand + $SplitVersion[2].SubString(3) + $ManifestName = "$ManifestBaseName-$DotnetTargetVersionBand" + } + else { + $DotnetTargetVersionBand = $DotnetVersionBand + } + } + else { + $DotnetTargetVersionBand = $DotnetVersionBand + } + } + + # Check latest version of manifest. + if ($Version -eq "" -or $UpdateAllWorkloads.IsPresent) { + $Version = Get-LatestVersion -Id $ManifestName + } + + # Check workload manifest directory. + $ManifestDir = Join-Path -Path $DotnetInstallDir -ChildPath "sdk-manifests" | Join-Path -ChildPath $DotnetTargetVersionBand + $TizenManifestDir = Join-Path -Path $ManifestDir -ChildPath "samsung.net.sdk.tizen" + $TizenManifestFile = Join-Path -Path $TizenManifestDir -ChildPath "WorkloadManifest.json" + + # Check and remove already installed old version. + if (Test-Path $TizenManifestFile) { + $ManifestJson = $(Get-Content $TizenManifestFile | ConvertFrom-Json) + $OldVersion = $ManifestJson.version + if ($OldVersion -eq $Version) { + $DotnetWorkloadList = Invoke-Expression "& '$DotnetCommand' workload list | Select-String -Pattern '^tizen'" + if ($DotnetWorkloadList) + { + Write-Host "Tizen Workload $Version version is already installed." + Continue + } + } + + Ensure-Directory $ManifestDir + Write-Host "Removing $ManifestName/$OldVersion from $ManifestDir..." + Remove-Pack -Id $ManifestName -Version $OldVersion -Kind "manifest" + $ManifestJson.packs.PSObject.Properties | ForEach-Object { + Write-Host "Removing $($_.Name)/$($_.Value.version)..." + Remove-Pack -Id $_.Name -Version $_.Value.version -Kind $_.Value.kind + } + } + + Ensure-Directory $ManifestDir + $TempDir = $(New-TemporaryDirectory) + + # Install workload manifest. + Write-Host "Installing $ManifestName/$Version to $ManifestDir..." + if ($global:FallbackId) { + Install-Pack -Id $global:FallbackId -Version $Version -Kind "manifest" + } else { + Install-Pack -Id $ManifestName -Version $Version -Kind "manifest" + } + + # Download and install workload packs. + $NewManifestJson = $(Get-Content $TizenManifestFile | ConvertFrom-Json) + $NewManifestJson.packs.PSObject.Properties | ForEach-Object { + Write-Host "Installing $($_.Name)/$($_.Value.version)..." + Install-Pack -Id $_.Name -Version $_.Value.version -Kind $_.Value.kind + } + + # Add tizen to the installed workload metadata. + # Featured version band for metadata does NOT include any preview specifier. + # https://github.com/dotnet/sdk/blob/main/documentation/general/workloads/user-local-workloads.md + New-Item -Path $(Join-Path -Path $DotnetInstallDir -ChildPath "metadata\workloads\$DotnetVersionBand\InstalledWorkloads\tizen") -Force | Out-Null + if (Test-Path $(Join-Path -Path $DotnetInstallDir -ChildPath "metadata\workloads\$DotnetVersionBand\InstallerType\msi")) { + New-Item -Path "HKLM:\SOFTWARE\Microsoft\dotnet\InstalledWorkloads\Standalone\x64\$DotnetTargetVersionBand\tizen" -Force | Out-Null + } + + # Clean up + Remove-Item -Path $TempDir -Force -Recurse + + Write-Host "Done installing Tizen workload $Version" +} + +# Check dotnet install directory. +if ($DotnetInstallDir -eq "") { + if ($Env:DOTNET_ROOT -And $(Test-Path "$Env:DOTNET_ROOT")) { + $DotnetInstallDir = $Env:DOTNET_ROOT + } else { + $DotnetInstallDir = Join-Path -Path $Env:Programfiles -ChildPath "dotnet" + } +} +if (-Not $(Test-Path "$DotnetInstallDir")) { + Write-Error "No installed dotnet '$DotnetInstallDir'." +} + +# Check installed dotnet version +$DotnetCommand = "$DotnetInstallDir\dotnet" +if (Get-Command $DotnetCommand -ErrorAction SilentlyContinue) +{ + if ($UpdateAllWorkloads.IsPresent) + { + $InstalledDotnetSdks = Invoke-Expression "& '$DotnetCommand' --list-sdks | Select-String -Pattern '^6|^7'" | ForEach-Object {$_ -replace (" \[.*","")} + } + else + { + $InstalledDotnetSdks = Invoke-Expression "& '$DotnetCommand' --version" + } +} +else +{ + Write-Error "'$DotnetCommand' occurs an error." +} + +if (-Not $InstalledDotnetSdks) +{ + Write-Host "`n.NET SDK version 6 or later is required to install Tizen Workload." +} +else +{ + foreach ($DotnetSdk in $InstalledDotnetSdks) + { + try { + Write-Host "`nCheck Tizen Workload for sdk $DotnetSdk" + Install-TizenWorkload -DotnetVersion $DotnetSdk + } + catch { + Write-Host "Failed to install Tizen Workload for sdk $DotnetSdk" + Write-Host "$_" + Continue + } + } +} + +Write-Host "`nDone"