diff --git a/.azure/pipelines/scripts/set-variables.sh b/.azure/pipelines/scripts/set-variables.sh index e4c3a4fb..6d8fe69a 100644 --- a/.azure/pipelines/scripts/set-variables.sh +++ b/.azure/pipelines/scripts/set-variables.sh @@ -1,7 +1,7 @@ #!/bin/bash define_variable () { - echo "Setting $1=$2" + echo "$1=$2" echo "##vso[task.setvariable variable=$1;isOutput=true]$2" } diff --git a/ai-cli.sln b/ai-cli.sln index 1bccb309..9e02bcfb 100644 --- a/ai-cli.sln +++ b/ai-cli.sln @@ -41,61 +41,169 @@ EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {D79D76D8-4E60-46DC-80B6-D5039C5D67F8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {D79D76D8-4E60-46DC-80B6-D5039C5D67F8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D79D76D8-4E60-46DC-80B6-D5039C5D67F8}.Debug|x64.ActiveCfg = Debug|Any CPU + {D79D76D8-4E60-46DC-80B6-D5039C5D67F8}.Debug|x64.Build.0 = Debug|Any CPU + {D79D76D8-4E60-46DC-80B6-D5039C5D67F8}.Debug|x86.ActiveCfg = Debug|Any CPU + {D79D76D8-4E60-46DC-80B6-D5039C5D67F8}.Debug|x86.Build.0 = Debug|Any CPU {D79D76D8-4E60-46DC-80B6-D5039C5D67F8}.Release|Any CPU.ActiveCfg = Release|Any CPU {D79D76D8-4E60-46DC-80B6-D5039C5D67F8}.Release|Any CPU.Build.0 = Release|Any CPU + {D79D76D8-4E60-46DC-80B6-D5039C5D67F8}.Release|x64.ActiveCfg = Release|Any CPU + {D79D76D8-4E60-46DC-80B6-D5039C5D67F8}.Release|x64.Build.0 = Release|Any CPU + {D79D76D8-4E60-46DC-80B6-D5039C5D67F8}.Release|x86.ActiveCfg = Release|Any CPU + {D79D76D8-4E60-46DC-80B6-D5039C5D67F8}.Release|x86.Build.0 = Release|Any CPU {7639F510-D2CD-491A-BB25-C9D89F3A576A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {7639F510-D2CD-491A-BB25-C9D89F3A576A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7639F510-D2CD-491A-BB25-C9D89F3A576A}.Debug|x64.ActiveCfg = Debug|Any CPU + {7639F510-D2CD-491A-BB25-C9D89F3A576A}.Debug|x64.Build.0 = Debug|Any CPU + {7639F510-D2CD-491A-BB25-C9D89F3A576A}.Debug|x86.ActiveCfg = Debug|Any CPU + {7639F510-D2CD-491A-BB25-C9D89F3A576A}.Debug|x86.Build.0 = Debug|Any CPU {7639F510-D2CD-491A-BB25-C9D89F3A576A}.Release|Any CPU.ActiveCfg = Release|Any CPU {7639F510-D2CD-491A-BB25-C9D89F3A576A}.Release|Any CPU.Build.0 = Release|Any CPU + {7639F510-D2CD-491A-BB25-C9D89F3A576A}.Release|x64.ActiveCfg = Release|Any CPU + {7639F510-D2CD-491A-BB25-C9D89F3A576A}.Release|x64.Build.0 = Release|Any CPU + {7639F510-D2CD-491A-BB25-C9D89F3A576A}.Release|x86.ActiveCfg = Release|Any CPU + {7639F510-D2CD-491A-BB25-C9D89F3A576A}.Release|x86.Build.0 = Release|Any CPU {272E0B1B-6C05-428E-BF64-E30B1E5F603A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {272E0B1B-6C05-428E-BF64-E30B1E5F603A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {272E0B1B-6C05-428E-BF64-E30B1E5F603A}.Debug|x64.ActiveCfg = Debug|Any CPU + {272E0B1B-6C05-428E-BF64-E30B1E5F603A}.Debug|x64.Build.0 = Debug|Any CPU + {272E0B1B-6C05-428E-BF64-E30B1E5F603A}.Debug|x86.ActiveCfg = Debug|Any CPU + {272E0B1B-6C05-428E-BF64-E30B1E5F603A}.Debug|x86.Build.0 = Debug|Any CPU {272E0B1B-6C05-428E-BF64-E30B1E5F603A}.Release|Any CPU.ActiveCfg = Release|Any CPU {272E0B1B-6C05-428E-BF64-E30B1E5F603A}.Release|Any CPU.Build.0 = Release|Any CPU + {272E0B1B-6C05-428E-BF64-E30B1E5F603A}.Release|x64.ActiveCfg = Release|Any CPU + {272E0B1B-6C05-428E-BF64-E30B1E5F603A}.Release|x64.Build.0 = Release|Any CPU + {272E0B1B-6C05-428E-BF64-E30B1E5F603A}.Release|x86.ActiveCfg = Release|Any CPU + {272E0B1B-6C05-428E-BF64-E30B1E5F603A}.Release|x86.Build.0 = Release|Any CPU {7BD6EF67-BA75-478D-9721-C1B2AB6DE3FF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {7BD6EF67-BA75-478D-9721-C1B2AB6DE3FF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7BD6EF67-BA75-478D-9721-C1B2AB6DE3FF}.Debug|x64.ActiveCfg = Debug|Any CPU + {7BD6EF67-BA75-478D-9721-C1B2AB6DE3FF}.Debug|x64.Build.0 = Debug|Any CPU + {7BD6EF67-BA75-478D-9721-C1B2AB6DE3FF}.Debug|x86.ActiveCfg = Debug|Any CPU + {7BD6EF67-BA75-478D-9721-C1B2AB6DE3FF}.Debug|x86.Build.0 = Debug|Any CPU {7BD6EF67-BA75-478D-9721-C1B2AB6DE3FF}.Release|Any CPU.ActiveCfg = Release|Any CPU {7BD6EF67-BA75-478D-9721-C1B2AB6DE3FF}.Release|Any CPU.Build.0 = Release|Any CPU + {7BD6EF67-BA75-478D-9721-C1B2AB6DE3FF}.Release|x64.ActiveCfg = Release|Any CPU + {7BD6EF67-BA75-478D-9721-C1B2AB6DE3FF}.Release|x64.Build.0 = Release|Any CPU + {7BD6EF67-BA75-478D-9721-C1B2AB6DE3FF}.Release|x86.ActiveCfg = Release|Any CPU + {7BD6EF67-BA75-478D-9721-C1B2AB6DE3FF}.Release|x86.Build.0 = Release|Any CPU {023B4F9C-E2B3-4CCD-A993-87E337C16EDE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {023B4F9C-E2B3-4CCD-A993-87E337C16EDE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {023B4F9C-E2B3-4CCD-A993-87E337C16EDE}.Debug|x64.ActiveCfg = Debug|Any CPU + {023B4F9C-E2B3-4CCD-A993-87E337C16EDE}.Debug|x64.Build.0 = Debug|Any CPU + {023B4F9C-E2B3-4CCD-A993-87E337C16EDE}.Debug|x86.ActiveCfg = Debug|Any CPU + {023B4F9C-E2B3-4CCD-A993-87E337C16EDE}.Debug|x86.Build.0 = Debug|Any CPU {023B4F9C-E2B3-4CCD-A993-87E337C16EDE}.Release|Any CPU.ActiveCfg = Release|Any CPU {023B4F9C-E2B3-4CCD-A993-87E337C16EDE}.Release|Any CPU.Build.0 = Release|Any CPU + {023B4F9C-E2B3-4CCD-A993-87E337C16EDE}.Release|x64.ActiveCfg = Release|Any CPU + {023B4F9C-E2B3-4CCD-A993-87E337C16EDE}.Release|x64.Build.0 = Release|Any CPU + {023B4F9C-E2B3-4CCD-A993-87E337C16EDE}.Release|x86.ActiveCfg = Release|Any CPU + {023B4F9C-E2B3-4CCD-A993-87E337C16EDE}.Release|x86.Build.0 = Release|Any CPU {7C3F1355-B679-487D-904D-7E5FEBA9E75C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {7C3F1355-B679-487D-904D-7E5FEBA9E75C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7C3F1355-B679-487D-904D-7E5FEBA9E75C}.Debug|x64.ActiveCfg = Debug|Any CPU + {7C3F1355-B679-487D-904D-7E5FEBA9E75C}.Debug|x64.Build.0 = Debug|Any CPU + {7C3F1355-B679-487D-904D-7E5FEBA9E75C}.Debug|x86.ActiveCfg = Debug|Any CPU + {7C3F1355-B679-487D-904D-7E5FEBA9E75C}.Debug|x86.Build.0 = Debug|Any CPU {7C3F1355-B679-487D-904D-7E5FEBA9E75C}.Release|Any CPU.ActiveCfg = Release|Any CPU {7C3F1355-B679-487D-904D-7E5FEBA9E75C}.Release|Any CPU.Build.0 = Release|Any CPU + {7C3F1355-B679-487D-904D-7E5FEBA9E75C}.Release|x64.ActiveCfg = Release|Any CPU + {7C3F1355-B679-487D-904D-7E5FEBA9E75C}.Release|x64.Build.0 = Release|Any CPU + {7C3F1355-B679-487D-904D-7E5FEBA9E75C}.Release|x86.ActiveCfg = Release|Any CPU + {7C3F1355-B679-487D-904D-7E5FEBA9E75C}.Release|x86.Build.0 = Release|Any CPU {B0B3437F-1828-4A13-866F-1CF7C924015E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {B0B3437F-1828-4A13-866F-1CF7C924015E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B0B3437F-1828-4A13-866F-1CF7C924015E}.Debug|x64.ActiveCfg = Debug|Any CPU + {B0B3437F-1828-4A13-866F-1CF7C924015E}.Debug|x64.Build.0 = Debug|Any CPU + {B0B3437F-1828-4A13-866F-1CF7C924015E}.Debug|x86.ActiveCfg = Debug|Any CPU + {B0B3437F-1828-4A13-866F-1CF7C924015E}.Debug|x86.Build.0 = Debug|Any CPU {B0B3437F-1828-4A13-866F-1CF7C924015E}.Release|Any CPU.ActiveCfg = Release|Any CPU {B0B3437F-1828-4A13-866F-1CF7C924015E}.Release|Any CPU.Build.0 = Release|Any CPU + {B0B3437F-1828-4A13-866F-1CF7C924015E}.Release|x64.ActiveCfg = Release|Any CPU + {B0B3437F-1828-4A13-866F-1CF7C924015E}.Release|x64.Build.0 = Release|Any CPU + {B0B3437F-1828-4A13-866F-1CF7C924015E}.Release|x86.ActiveCfg = Release|Any CPU + {B0B3437F-1828-4A13-866F-1CF7C924015E}.Release|x86.Build.0 = Release|Any CPU {39876475-2D98-40CF-8B08-CD423A5EB4E8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {39876475-2D98-40CF-8B08-CD423A5EB4E8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {39876475-2D98-40CF-8B08-CD423A5EB4E8}.Debug|x64.ActiveCfg = Debug|Any CPU + {39876475-2D98-40CF-8B08-CD423A5EB4E8}.Debug|x64.Build.0 = Debug|Any CPU + {39876475-2D98-40CF-8B08-CD423A5EB4E8}.Debug|x86.ActiveCfg = Debug|Any CPU + {39876475-2D98-40CF-8B08-CD423A5EB4E8}.Debug|x86.Build.0 = Debug|Any CPU {39876475-2D98-40CF-8B08-CD423A5EB4E8}.Release|Any CPU.ActiveCfg = Release|Any CPU {39876475-2D98-40CF-8B08-CD423A5EB4E8}.Release|Any CPU.Build.0 = Release|Any CPU + {39876475-2D98-40CF-8B08-CD423A5EB4E8}.Release|x64.ActiveCfg = Release|Any CPU + {39876475-2D98-40CF-8B08-CD423A5EB4E8}.Release|x64.Build.0 = Release|Any CPU + {39876475-2D98-40CF-8B08-CD423A5EB4E8}.Release|x86.ActiveCfg = Release|Any CPU + {39876475-2D98-40CF-8B08-CD423A5EB4E8}.Release|x86.Build.0 = Release|Any CPU {9499C018-FA08-4133-93B3-FC0F3863A6CC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {9499C018-FA08-4133-93B3-FC0F3863A6CC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9499C018-FA08-4133-93B3-FC0F3863A6CC}.Debug|x64.ActiveCfg = Debug|Any CPU + {9499C018-FA08-4133-93B3-FC0F3863A6CC}.Debug|x64.Build.0 = Debug|Any CPU + {9499C018-FA08-4133-93B3-FC0F3863A6CC}.Debug|x86.ActiveCfg = Debug|Any CPU + {9499C018-FA08-4133-93B3-FC0F3863A6CC}.Debug|x86.Build.0 = Debug|Any CPU {9499C018-FA08-4133-93B3-FC0F3863A6CC}.Release|Any CPU.ActiveCfg = Release|Any CPU {9499C018-FA08-4133-93B3-FC0F3863A6CC}.Release|Any CPU.Build.0 = Release|Any CPU + {9499C018-FA08-4133-93B3-FC0F3863A6CC}.Release|x64.ActiveCfg = Release|Any CPU + {9499C018-FA08-4133-93B3-FC0F3863A6CC}.Release|x64.Build.0 = Release|Any CPU + {9499C018-FA08-4133-93B3-FC0F3863A6CC}.Release|x86.ActiveCfg = Release|Any CPU + {9499C018-FA08-4133-93B3-FC0F3863A6CC}.Release|x86.Build.0 = Release|Any CPU {CED7C805-0435-4BF7-A42F-9F3BBF14A18F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {CED7C805-0435-4BF7-A42F-9F3BBF14A18F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CED7C805-0435-4BF7-A42F-9F3BBF14A18F}.Debug|x64.ActiveCfg = Debug|Any CPU + {CED7C805-0435-4BF7-A42F-9F3BBF14A18F}.Debug|x64.Build.0 = Debug|Any CPU + {CED7C805-0435-4BF7-A42F-9F3BBF14A18F}.Debug|x86.ActiveCfg = Debug|Any CPU + {CED7C805-0435-4BF7-A42F-9F3BBF14A18F}.Debug|x86.Build.0 = Debug|Any CPU {CED7C805-0435-4BF7-A42F-9F3BBF14A18F}.Release|Any CPU.ActiveCfg = Release|Any CPU {CED7C805-0435-4BF7-A42F-9F3BBF14A18F}.Release|Any CPU.Build.0 = Release|Any CPU + {CED7C805-0435-4BF7-A42F-9F3BBF14A18F}.Release|x64.ActiveCfg = Release|Any CPU + {CED7C805-0435-4BF7-A42F-9F3BBF14A18F}.Release|x64.Build.0 = Release|Any CPU + {CED7C805-0435-4BF7-A42F-9F3BBF14A18F}.Release|x86.ActiveCfg = Release|Any CPU + {CED7C805-0435-4BF7-A42F-9F3BBF14A18F}.Release|x86.Build.0 = Release|Any CPU {306A3CD6-91C2-450B-9995-79701CE63FE2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {306A3CD6-91C2-450B-9995-79701CE63FE2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {306A3CD6-91C2-450B-9995-79701CE63FE2}.Debug|x64.ActiveCfg = Debug|Any CPU + {306A3CD6-91C2-450B-9995-79701CE63FE2}.Debug|x64.Build.0 = Debug|Any CPU + {306A3CD6-91C2-450B-9995-79701CE63FE2}.Debug|x86.ActiveCfg = Debug|Any CPU + {306A3CD6-91C2-450B-9995-79701CE63FE2}.Debug|x86.Build.0 = Debug|Any CPU {306A3CD6-91C2-450B-9995-79701CE63FE2}.Release|Any CPU.ActiveCfg = Release|Any CPU {306A3CD6-91C2-450B-9995-79701CE63FE2}.Release|Any CPU.Build.0 = Release|Any CPU + {306A3CD6-91C2-450B-9995-79701CE63FE2}.Release|x64.ActiveCfg = Release|Any CPU + {306A3CD6-91C2-450B-9995-79701CE63FE2}.Release|x64.Build.0 = Release|Any CPU + {306A3CD6-91C2-450B-9995-79701CE63FE2}.Release|x86.ActiveCfg = Release|Any CPU + {306A3CD6-91C2-450B-9995-79701CE63FE2}.Release|x86.Build.0 = Release|Any CPU {A136A55F-C27B-4FC9-82ED-84A3790BFC3C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {A136A55F-C27B-4FC9-82ED-84A3790BFC3C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A136A55F-C27B-4FC9-82ED-84A3790BFC3C}.Debug|x64.ActiveCfg = Debug|Any CPU + {A136A55F-C27B-4FC9-82ED-84A3790BFC3C}.Debug|x64.Build.0 = Debug|Any CPU + {A136A55F-C27B-4FC9-82ED-84A3790BFC3C}.Debug|x86.ActiveCfg = Debug|Any CPU + {A136A55F-C27B-4FC9-82ED-84A3790BFC3C}.Debug|x86.Build.0 = Debug|Any CPU {A136A55F-C27B-4FC9-82ED-84A3790BFC3C}.Release|Any CPU.ActiveCfg = Release|Any CPU {A136A55F-C27B-4FC9-82ED-84A3790BFC3C}.Release|Any CPU.Build.0 = Release|Any CPU + {A136A55F-C27B-4FC9-82ED-84A3790BFC3C}.Release|x64.ActiveCfg = Release|Any CPU + {A136A55F-C27B-4FC9-82ED-84A3790BFC3C}.Release|x64.Build.0 = Release|Any CPU + {A136A55F-C27B-4FC9-82ED-84A3790BFC3C}.Release|x86.ActiveCfg = Release|Any CPU + {A136A55F-C27B-4FC9-82ED-84A3790BFC3C}.Release|x86.Build.0 = Release|Any CPU {BA7F8DB9-2789-4410-99B5-AC38F85697FE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {BA7F8DB9-2789-4410-99B5-AC38F85697FE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BA7F8DB9-2789-4410-99B5-AC38F85697FE}.Debug|x64.ActiveCfg = Debug|Any CPU + {BA7F8DB9-2789-4410-99B5-AC38F85697FE}.Debug|x64.Build.0 = Debug|Any CPU + {BA7F8DB9-2789-4410-99B5-AC38F85697FE}.Debug|x86.ActiveCfg = Debug|Any CPU + {BA7F8DB9-2789-4410-99B5-AC38F85697FE}.Debug|x86.Build.0 = Debug|Any CPU {BA7F8DB9-2789-4410-99B5-AC38F85697FE}.Release|Any CPU.ActiveCfg = Release|Any CPU {BA7F8DB9-2789-4410-99B5-AC38F85697FE}.Release|Any CPU.Build.0 = Release|Any CPU + {BA7F8DB9-2789-4410-99B5-AC38F85697FE}.Release|x64.ActiveCfg = Release|Any CPU + {BA7F8DB9-2789-4410-99B5-AC38F85697FE}.Release|x64.Build.0 = Release|Any CPU + {BA7F8DB9-2789-4410-99B5-AC38F85697FE}.Release|x86.ActiveCfg = Release|Any CPU + {BA7F8DB9-2789-4410-99B5-AC38F85697FE}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/ai/Program_AI.cs b/src/ai/Program_AI.cs index 5f6f9c7f..601ec151 100644 --- a/src/ai/Program_AI.cs +++ b/src/ai/Program_AI.cs @@ -41,12 +41,6 @@ static async Task Main(string[] args) Console.WriteLine($"StopWatch: Stopped at {DateTime.Now} ({GetStopWatchElapsedAsString(stopwatch.Elapsed)})"); } - if (data.Telemetry != null) - { - await data.Telemetry.DisposeAsync() - .ConfigureAwait(false); - } - return exitCode; } catch (Exception) diff --git a/src/ai/commands/init_command.cs b/src/ai/commands/init_command.cs index c5e01494..6eb81ff2 100644 --- a/src/ai/commands/init_command.cs +++ b/src/ai/commands/init_command.cs @@ -283,29 +283,30 @@ private async ValueTask DoInitRootMenuPick() var label = " Initialize"; Console.Write($"{label}: "); - var choices = new ListBoxPickerChoice[] + var choices = new[] { - new() { DisplayName = "New AI Project", Value = "init-root-project-create", Metadata = "new" }, - new() { DisplayName = "Existing AI Project", Value = "init-root-project-select", Metadata = "existing" }, - new() { DisplayName = "Standalone resources", Value = "init-root-standalone-select-or-create", Metadata = "standalone" }, + new { DisplayName = "New AI Project", Value = "init-root-project-create", Metadata = "new" }, + new { DisplayName = "Existing AI Project", Value = "init-root-project-select", Metadata = "existing" }, + new { DisplayName = "Standalone resources", Value = "init-root-standalone-select-or-create", Metadata = "standalone" }, }; - ListBoxPickerChoice selected = default; + int selected = -1; + var outcome = Program.Telemetry.Wrap(() => - { - selected = ListBoxPicker.PickValue(choices); - if (selected == null) { - Console.WriteLine($"\r{label}: CANCELED (no selection)"); - return Outcome.Canceled; - } + selected = ListBoxPicker.PickIndexOf(choices.Select(e => e.DisplayName).ToArray()); + if (selected < 0) + { + Console.WriteLine($"\r{label}: CANCELED (no selection)"); + return Outcome.Canceled; + } - Console.Write($"\r{label.Trim()}: {selected.DisplayName}\n"); - _values.Reset("telemetry.init.run_type", selected.Metadata); + Console.Write($"\r{label.Trim()}: {choices.ElementAtOrDefault(selected)?.DisplayName}\n"); + _values.Reset("telemetry.init.run_type", choices.ElementAtOrDefault(selected)?.Metadata); - return Outcome.Success; - }, - (outcome, ex, timeTaken) => selected.Metadata == "standalone" + return Outcome.Success; + }, + (outcome, ex, timeTaken) => choices.ElementAtOrDefault(selected)?.Metadata == "standalone" ? null : new InitTelemetryEvent(InitStage.Choice) { @@ -318,7 +319,7 @@ private async ValueTask DoInitRootMenuPick() if (outcome == Outcome.Success) { - await DoInitServiceParts(interactive, selected.Value); + await DoInitServiceParts(interactive, choices.ElementAtOrDefault(selected)?.Value); } } @@ -335,26 +336,26 @@ private async Task DoInitStandaloneResources(bool interactive) var label = " Initialize"; Console.Write($"{label}: "); - var choices = new ListBoxPickerChoice[] + var choices = new[] { - new ("Azure AI Services (v2)", "init-root-cognitiveservices-ai-services-kind-create-or-select", "aiservices"), - new ("Azure AI Services (v1)", "init-root-cognitiveservices-cognitiveservices-kind-create-or-select", "cognitiveservices"), - new ("Azure OpenAI", "init-root-openai-create-or-select", "openai"), - new ("Azure Search", "init-root-search-create-or-select", "search"), - new ("Azure Speech", "init-root-speech-create-or-select", "speech") + new { DisplayName = "Azure AI Services (v2)", Value = "init-root-cognitiveservices-ai-services-kind-create-or-select", Metadata = "aiservices" }, + new { DisplayName = "Azure AI Services (v1)", Value = "init-root-cognitiveservices-cognitiveservices-kind-create-or-select", Metadata ="cognitiveservices" }, + new { DisplayName = "Azure OpenAI", Value = "init-root-openai-create-or-select", Metadata = "openai" }, + new { DisplayName = "Azure Search", Value = "init-root-search-create-or-select", Metadata = "search" }, + new { DisplayName = "Azure Speech", Value = "init-root-speech-create-or-select", Metadata = "speech" } }; - ListBoxPickerChoice picked = null; + int picked = -1; var outcome = Program.Telemetry.Wrap(() => { - picked = ListBoxPicker.PickValue(choices); - if (picked == null) + picked = ListBoxPicker.PickIndexOf(choices.Select(e => e.DisplayName).ToArray()); + if (picked < 0) { Console.WriteLine("\rInitialize: CANCELED (no selection)"); return Outcome.Canceled; } - Console.WriteLine($"\rInitialize: {picked.DisplayName}"); + Console.WriteLine($"\rInitialize: {choices.ElementAtOrDefault(picked)?.DisplayName}"); return Outcome.Success; }, (outcome, ex, timeTaken) => new InitTelemetryEvent(InitStage.Choice) @@ -362,14 +363,14 @@ private async Task DoInitStandaloneResources(bool interactive) Outcome = outcome, RunId = _values.GetOrDefault("telemetry.init.run_id", null), RunType = _values.GetOrDefault("telemetry.init.run_type", null), - Selected = picked.Metadata, + Selected = choices.ElementAtOrDefault(picked)?.Metadata, DurationInMs = timeTaken.TotalMilliseconds, Error = ex?.Message }); if (outcome == Outcome.Success) { - await DoInitServiceParts(true, picked.Value); + await DoInitServiceParts(true, choices.ElementAtOrDefault(picked)?.Value); } } @@ -646,7 +647,6 @@ private async Task DoInitRootSpeech(bool interactive) await DoInitSubscriptionId(interactive); await DoInitSpeech(interactive); } - private async Task DoInitRootVision(bool interactive) { await DoInitSubscriptionId(interactive); diff --git a/src/common/Program.cs b/src/common/Program.cs index 18f6b7b7..d9a191e3 100644 --- a/src/common/Program.cs +++ b/src/common/Program.cs @@ -373,6 +373,25 @@ private static void DisplayLogException(ICommandValues values, Exception ex) DisplayException(ex); } + private static void TryCatchErrorOrException(ICommandValues values, Action action) + { + if (System.Diagnostics.Debugger.IsAttached) + { + action(); + } + else + { + try + { + action(); + } + catch (Exception ex) + { + DisplayErrorOrException(values, ex); + } + } + } + private static bool RunCommand(ICommandValues values) { string errorInfo = null; diff --git a/src/common/details/ai_python_generative_sdk/AiSdkConsoleGui.cs b/src/common/details/ai_python_generative_sdk/AiSdkConsoleGui.cs index 807d03ed..54415c19 100644 --- a/src/common/details/ai_python_generative_sdk/AiSdkConsoleGui.cs +++ b/src/common/details/ai_python_generative_sdk/AiSdkConsoleGui.cs @@ -3,8 +3,6 @@ // Licensed under the MIT license. See LICENSE.md file in the project root for full license information. // -#nullable enable - using System.Text.Json; using System.Text.Json.Serialization; @@ -55,7 +53,7 @@ public struct AiHubProjectInfo public partial class AiSdkConsoleGui { - public static async Task<(string?, AzCli.CognitiveServicesResourceInfo?, AzCli.CognitiveSearchResourceInfo?)> VerifyResourceConnections(ICommandValues values, string subscription, string groupName, string projectName) + public static async Task<(string, AzCli.CognitiveServicesResourceInfo?, AzCli.CognitiveSearchResourceInfo?)> VerifyResourceConnections(ICommandValues values, string subscription, string groupName, string projectName) { try { @@ -99,7 +97,7 @@ public partial class AiSdkConsoleGui return null; } - Func match = (a, b) => { + Func match = (a, b) => { return a == b || a?.Replace(".openai.azure.com/", ".cognitiveservices.azure.com/") == b || b?.Replace(".openai.azure.com/", ".cognitiveservices.azure.com/") == a; diff --git a/src/common/details/ai_python_generative_sdk/python_sdk_wrapper.cs b/src/common/details/ai_python_generative_sdk/python_sdk_wrapper.cs index 36857650..3e756daf 100644 --- a/src/common/details/ai_python_generative_sdk/python_sdk_wrapper.cs +++ b/src/common/details/ai_python_generative_sdk/python_sdk_wrapper.cs @@ -210,12 +210,13 @@ private static string DoGetConnectionViaPython(ICommandValues values, string sub private static void CreateResourceGroup(ICommandValues values, string subscription, string location, string group) { + // TODO FIXME: This method should be made async + var quiet = values.GetOrDefault("x.quiet", false); var message = $"Creating resource group '{group}'..."; if (!quiet) Console.WriteLine(message); - // TODO FIXME: This method should be made async var response = Program.SubscriptionClient.CreateResourceGroupAsync(subscription, location, group, Program.CancelToken) .Result; diff --git a/src/common/details/azcli/AzCliConsoleGui_CognitiveServicesResourcePicker.cs b/src/common/details/azcli/AzCliConsoleGui_CognitiveServicesResourcePicker.cs index d2382433..5c46172c 100644 --- a/src/common/details/azcli/AzCliConsoleGui_CognitiveServicesResourcePicker.cs +++ b/src/common/details/azcli/AzCliConsoleGui_CognitiveServicesResourcePicker.cs @@ -111,7 +111,7 @@ public partial class AzCliConsoleGui { ConsoleHelpers.WriteLineWithHighlight("\n`RESOURCE GROUP`"); - var regionLocation = !string.IsNullOrEmpty(regionLocationFilter) ? await FindRegionAsync(interactive, subscriptionId, regionLocationFilter, true) : new AccountRegionLocationInfo(); + var regionLocation = !string.IsNullOrEmpty(regionLocationFilter) ? await FindRegionAsync(interactive, subscriptionId, regionLocationFilter, true) : new AzCli.AccountRegionLocationInfo(); if (regionLocation == null) return null; var (group, createdNew) = await PickOrCreateResourceGroup(interactive, subscriptionId, regionLocation?.Name, groupFilter); @@ -139,7 +139,6 @@ public partial class AzCliConsoleGui if (!agreeTerms && !CheckAgreeTerms(createKind)) return null; Console.Write("*** CREATING ***"); - var response = await Program.CognitiveServicesClient.CreateResourceAsync( createKind, subscriptionId, group.Name, group.Region, name, sku, Program.CancelToken); Console.Write("\r"); diff --git a/src/common/details/azcli/AzCliConsoleGui_SubscriptionPicker.cs b/src/common/details/azcli/AzCliConsoleGui_SubscriptionPicker.cs index 2762458a..67ed8cb0 100644 --- a/src/common/details/azcli/AzCliConsoleGui_SubscriptionPicker.cs +++ b/src/common/details/azcli/AzCliConsoleGui_SubscriptionPicker.cs @@ -116,22 +116,19 @@ public static async Task PickSubscriptionIdAsync(bool allowInteractiveLo private static AzCli.SubscriptionInfo? ListBoxPickSubscription(AzCli.SubscriptionInfo[] subscriptions) { - var selected = ListBoxPicker.PickValue( - subscriptions - .Select(s => new ListBoxPickerChoice() - { - IsDefault = s.IsDefault, - DisplayName = s.Name, - Value = s - })); - if (selected == null) + var list = subscriptions.Select(x => x.Name).ToArray(); + var defaultIndex = subscriptions.Select((x, i) => new { x, i }).Where(x => x.x.IsDefault).Select(x => x.i).FirstOrDefault(); + + var picked = ListBoxPicker.PickIndexOf(list, defaultIndex); + if (picked < 0) { throw new OperationCanceledException("User canceled"); } - DisplayNameAndId(selected.Value); - CacheSubscriptionUserName(selected.Value); - return selected.Value; + var subscription = subscriptions[picked]; + DisplayNameAndId(subscription); + CacheSubscriptionUserName(subscription); + return subscription; } private static bool MatchSubscriptionFilter(AzCli.SubscriptionInfo subscription, string subscriptionFilter) diff --git a/src/common/details/commands/parsers/help_command_parser.cs b/src/common/details/commands/parsers/help_command_parser.cs index ef9e7df9..aa6f4c53 100644 --- a/src/common/details/commands/parsers/help_command_parser.cs +++ b/src/common/details/commands/parsers/help_command_parser.cs @@ -262,13 +262,10 @@ private static bool DisplayHelp(string path, INamedValues values) private static bool DisplayDefaultHelp() { - Console.WriteLine( - """ - ___ ____ ___ _____ - / _ /_ / / _ |/_ _/ - / __ |/ /_/ __ |_/ /_ - /_/ |_/___/_/ |_/____/ - """); + Console.WriteLine(@" ______ ___ _ __"); + Console.WriteLine(@" / ___// _ \ \/ /"); + Console.WriteLine(@" \___ \/ ___/ <"); + Console.WriteLine(@"/____ /_/ /__/\_\"); Console.WriteLine(); Console.WriteLine($"USAGE: {Program.Name} [...]"); Console.WriteLine(); diff --git a/src/common/details/console/gui/controls/ListBoxPicker.cs b/src/common/details/console/gui/controls/ListBoxPicker.cs index 659e68fd..4cecb8e9 100644 --- a/src/common/details/console/gui/controls/ListBoxPicker.cs +++ b/src/common/details/console/gui/controls/ListBoxPicker.cs @@ -3,15 +3,13 @@ // Licensed under the MIT license. See LICENSE.md file in the project root for full license information. // +using System; +using System.Linq; +using System.Text; +using Azure.AI.Details.Common.CLI; + namespace Azure.AI.Details.Common.CLI.ConsoleGui { - public interface IListBoxPickerChoice - { - bool IsDefault { get; } - - string DisplayName { get; } - } - public class ListBoxPicker : SpeedSearchListBoxControl { public static int PickIndexOf(string[] choices, int select = 0) @@ -62,30 +60,6 @@ public static string PickString(string[] lines, int width, int height, Colors no : null; } - public static TVal PickValue(IEnumerable items) where TVal : IListBoxPickerChoice - { - if (items == null) - { - return default; - } - - int? select = null; - var displayTexts = items - .Select((item, index) => - { - if (item.IsDefault && !select.HasValue) - { - select = index; - } - - return item.DisplayName; - }) - .ToArray(); - - int selected = PickIndexOf(displayTexts, select ?? 0); - return items.ElementAtOrDefault(selected); // this handles negatives and values out of bound - } - public override bool ProcessKey(ConsoleKeyInfo key) { var processed = ProcessSpeedSearchKey(key); @@ -127,49 +101,4 @@ protected ListBoxPicker(Window parent, Rect rect, Colors colorNormal, Colors col #endregion } - - public class ListBoxPickerChoice : IListBoxPickerChoice - { - public ListBoxPickerChoice() - { } - - public ListBoxPickerChoice(string displayName, TVal value, bool isDefault = false) - { - IsDefault = isDefault; - DisplayName = displayName; - Value = value; - } - - public bool IsDefault { get; set; } - - public string DisplayName { get; set; } - - public TVal Value { get; set; } - - public override string ToString() => DisplayName; - } - - public class ListBoxPickerChoice : ListBoxPickerChoice - { - public ListBoxPickerChoice() - { } - - public ListBoxPickerChoice(string displayName, TVal value, TMeta metadata = default, bool isDefault = false) - : base(displayName, value, isDefault) - { - Metadata = metadata; - } - - public TMeta Metadata { get; set; } - } - - public class ListBoxPickerChoice : ListBoxPickerChoice - { - public ListBoxPickerChoice() - { } - - public ListBoxPickerChoice(string displayName, string value, string metadata = null, bool isDefault = false) - : base(displayName, value, metadata, isDefault) - { } - } } diff --git a/src/common/details/helpers/file_helpers.cs b/src/common/details/helpers/file_helpers.cs index 84edc8ed..8019ed14 100644 --- a/src/common/details/helpers/file_helpers.cs +++ b/src/common/details/helpers/file_helpers.cs @@ -1071,8 +1071,16 @@ private static Stream GetResourceStream(string fileName) private static string ReadAllResourceText(string fileName, Encoding encoding) { - using var reader = new StreamReader(GetResourceStream(fileName), encoding); - return reader.ReadToEnd(); + var stream = GetResourceStream(fileName); + var length = stream.Length; + + byte[] buffer = new byte[length]; + string text = stream.Read(buffer, 0, (int)length) != 0 + ? encoding.GetString(buffer) + : ""; + + stream.Dispose(); + return text; } private static byte[] ReadAllResourceBytes(string fileName) @@ -1266,7 +1274,7 @@ private static void CheckScopedConfigPath(INamedValues values) private static string ExpandConfigPath(string path0, string paths) { var sb = new StringBuilder(); - foreach (var path in paths.Split(';', StringSplitOptions.RemoveEmptyEntries)) + foreach (var path in paths.Split(";".ToCharArray(), StringSplitOptions.RemoveEmptyEntries)) { if (Program.Debug) Console.WriteLine($" CONFIG DATASTORE: '{path}'"); sb.Append($"{path}data/;{path}config/;{path};"); diff --git a/src/common/details/helpers/python_runner.cs b/src/common/details/helpers/python_runner.cs index 67261cb1..15fd09cf 100644 --- a/src/common/details/helpers/python_runner.cs +++ b/src/common/details/helpers/python_runner.cs @@ -3,8 +3,6 @@ // Licensed under the MIT license. See LICENSE.md file in the project root for full license information. // -#nullable enable - using System; using System.Diagnostics; using System.IO; @@ -17,17 +15,17 @@ namespace Azure.AI.Details.Common.CLI { public class PythonRunner { - public static async Task RunPythonScriptAsync(string script, string? args = null, IDictionary? addToEnvironment = null, Action? stdOutHandler = null, Action? stdErrHandler = null, Action? mergedOutputHandler = null) + public static async Task RunPythonScriptAsync(string script, string args = null, Dictionary addToEnvironment = null, Action stdOutHandler = null, Action stdErrHandler = null, Action mergedOutputHandler = null) { - string? pythonBinary = EnsureFindPython(); - if (pythonBinary == null) + EnsureFindPython(); + if (_pythonBinary == null) { ConsoleHelpers.WriteLineError("*** Please install Python 3.10 or above ***"); Console.Write("\nNOTE: If it's already installed ensure it's in the system PATH and working (try: `python --version`)\n"); return new ProcessOutput() { ExitCode = -1 }; } - string? tempFile = null; + string tempFile = null; try { @@ -37,7 +35,7 @@ public static async Task RunPythonScriptAsync(string script, stri args = args != null ? $"\"{tempFile}\" {args}" : $"\"{tempFile}\""; - return await ProcessHelpers.RunShellCommandAsync(pythonBinary, args, addToEnvironment, stdOutHandler, stdErrHandler, mergedOutputHandler); + return await ProcessHelpers.RunShellCommandAsync(_pythonBinary, args, addToEnvironment, stdOutHandler, stdErrHandler, mergedOutputHandler); } finally { @@ -70,8 +68,8 @@ public static string RunEmbeddedPythonScript(ICommandValues values, string scrip AI.DBG_TRACE_VERBOSE($"RunEmbeddedPythonScript: '{scriptName}' {scriptArgs}"); var process = PythonRunner.RunPythonScriptAsync(script, scriptArgs, addToEnvironment, stdOutHandler, stdErrHandler, mergedOutputHandler).Result; - string? output = process.MergedOutput; - int exit = process.ExitCode; + var output = process.MergedOutput; + var exit = process.ExitCode; if (exit != 0) { @@ -84,8 +82,8 @@ public static string RunEmbeddedPythonScript(ICommandValues values, string scrip if (output.Contains("MESSAGE:") && output.Contains("EXCEPTION:") && output.Contains("TRACEBACK:")) { - string? messageLine = process.StdError.Split(new[] { '\r', '\n' }).FirstOrDefault(x => x.StartsWith("MESSAGE:")); - var message = messageLine?.Substring("MESSAGE:".Length).Trim(); + var messageLine = process.StdError.Split(new[] { '\r', '\n' }).FirstOrDefault(x => x.StartsWith("MESSAGE:")); + var message = messageLine.Substring("MESSAGE:".Length).Trim(); FileHelpers.LogException(values, new PythonScriptException(output, exit)); if (output.Contains("az login")) @@ -173,7 +171,7 @@ public static string RunEmbeddedPythonScript(ICommandValues values, string scrip info.Add($"Python script failed! (exit code={exit})"); info.Add(""); info.Add("OUTPUT:"); - info.Add(output ?? string.Empty); + info.Add(output); values.AddThrowError(info[0], info[1], info.Skip(2).ToArray()); } @@ -181,13 +179,8 @@ public static string RunEmbeddedPythonScript(ICommandValues values, string scrip return ParseOutputAndSkipLinesUntilStartsWith(output, "---").Trim('\r', '\n', ' '); } - private static string ParseOutputAndSkipLinesUntilStartsWith(string? output, string startsWith) + private static string ParseOutputAndSkipLinesUntilStartsWith(string output, string startsWith) { - if (output == null) - { - return string.Empty; - } - var lines = output.Split(new[] { "\r\n", "\n", "\r" }, StringSplitOptions.None); var sb = new StringBuilder(); var skip = true; @@ -205,7 +198,7 @@ private static string ParseOutputAndSkipLinesUntilStartsWith(string? output, str return sb.ToString(); } - private static string? EnsureFindPython() + private static string EnsureFindPython() { if (_pythonBinary == null) { @@ -215,10 +208,10 @@ private static string ParseOutputAndSkipLinesUntilStartsWith(string? output, str return _pythonBinary; } - private static string? FindPython() + private static string FindPython() { - string? fullPath = FindPythonBinaryInOsPath(); - string? pythonExec = fullPath; + string fullPath = FindPythonBinaryInOsPath(); + string pythonExec = fullPath; if (OperatingSystem.IsWindows()) { // TODO FIXME Longer term we really shouldn't be wrapping calls to python in cmd /c python @@ -231,14 +224,11 @@ private static string ParseOutputAndSkipLinesUntilStartsWith(string? output, str pythonExec = Path.GetFileName(fullPath); } - if (pythonExec != null) + var process = ProcessHelpers.RunShellCommandAsync(pythonExec, "--version").Result; + if (process.ExitCode == 0 && process.MergedOutput.Contains("Python 3.")) { - var process = ProcessHelpers.RunShellCommandAsync(pythonExec, "--version").Result; - if (process.ExitCode == 0 && process.MergedOutput.Contains("Python 3.")) - { - AI.DBG_TRACE_VERBOSE($"Python found: {fullPath}"); - return pythonExec; - } + AI.DBG_TRACE_VERBOSE($"Python found: {fullPath}"); + return pythonExec; } return null; diff --git a/src/common/details/named_values/named_values.cs b/src/common/details/named_values/named_values.cs index 6542113e..7cb7542d 100644 --- a/src/common/details/named_values/named_values.cs +++ b/src/common/details/named_values/named_values.cs @@ -228,7 +228,17 @@ public class NamedValues : INamedValues { public void Add(string name, string value) { - _values[name] = value; + var exists = _values.ContainsKey(name); + var current = exists ? _values[name] : null; + + var matches = exists && current == value; + if (matches) return; + + var remove = exists && string.IsNullOrWhiteSpace(current); + if (remove) _values.Remove(name); + + _values.Add(name, value); + _names.Add(name); } public bool Contains(string name, bool checkDefault = true) @@ -238,14 +248,13 @@ public bool Contains(string name, bool checkDefault = true) public string Get(string name, bool checkDefault = true) { - return _values.TryGetValue(name, out var value) - ? value - : null; + return Contains(name, checkDefault) ? _values[name] : null; } public void Reset(string name, string value = null) { _values.Remove(name); + _names.Remove(name); if (value != null) { Add(name, value); @@ -260,8 +269,15 @@ public string this[string name] } } - public IEnumerable Names => _values.Keys; + public IEnumerable Names + { + get + { + return _names; + } + } private Dictionary _values = new Dictionary(); + private List _names = new List(); } }