Dynamically retrieve .NET templates (#457)
This commit is contained in:
Родитель
72477583ab
Коммит
3c65d5596b
|
@ -63,4 +63,7 @@ package-lock.json
|
|||
# Output
|
||||
out
|
||||
*.vsix
|
||||
.vscode-test
|
||||
.vscode-test
|
||||
|
||||
# debugging artifacts
|
||||
resources/dotnetTemplates
|
||||
|
|
|
@ -128,15 +128,6 @@ brew install azure-functions-core-tools
|
|||
|
||||
* [VS Code Debugger for C#](https://marketplace.visualstudio.com/items?itemName=ms-vscode.csharp)
|
||||
* [.NET CLI](https://docs.microsoft.com/dotnet/core/tools/?tabs=netcore2x)
|
||||
* .NET Templates for Azure Functions
|
||||
* You will be automatically prompted to install these templates when you first create a project/function
|
||||
* If you are using v2.0 of the Azure Functions runtime, you must install the beta (.NET Core) templates
|
||||
* If you are using v1.0 of the Azure Functions runtime, you must install the v1.0 (.NET Framework) templates.
|
||||
> **NOTE**: The VS Code Debugger for C# [only supports](https://github.com/OmniSharp/omnisharp-vscode/issues/1716) attaching to 64-bit processes. v1.0 of the Azure Functions runtime defaults to 32-bit and you must install a 64-bit version. See [here](https://aka.ms/azFunc64bit) for instructions.
|
||||
* You may uninstall or reinstall the templates with the following steps:
|
||||
1. Open Command Palette (View -> Command Palette...)
|
||||
1. Search for "Azure Functions" and "install" or "uninstall"
|
||||
1. Run the corresponding command for .NET templates
|
||||
|
||||
> **NOTE**: The default experience for C# uses class libraries (*.cs files), which provide superior performance, scalability, and versatility over C# Scripts (*.csx files). If you want to use C# Scripts, you may change your `azureFunctions.projectLanguage` user setting to `C#Script`.
|
||||
|
||||
|
|
|
@ -54,7 +54,6 @@
|
|||
"onCommand:azureFunctions.appSettings.encrypt",
|
||||
"onCommand:azureFunctions.appSettings.decrypt",
|
||||
"onCommand:azureFunctions.pickProcess",
|
||||
"onCommand:azureFunctions.uninstallDotnetTemplates",
|
||||
"onCommand:azureFunctions.startStreamingLogs",
|
||||
"onCommand:azureFunctions.stopStreamingLogs",
|
||||
"onCommand:azureFunctions.deleteProxy",
|
||||
|
@ -215,11 +214,6 @@
|
|||
"title": "%azFunc.pickProcess%",
|
||||
"category": "Azure Functions"
|
||||
},
|
||||
{
|
||||
"command": "azureFunctions.uninstallDotnetTemplates",
|
||||
"title": "%azFunc.uninstallDotnetTemplates%",
|
||||
"category": "Azure Functions"
|
||||
},
|
||||
{
|
||||
"command": "azureFunctions.startStreamingLogs",
|
||||
"title": "%azFunc.startStreamingLogs%",
|
||||
|
|
|
@ -30,8 +30,6 @@
|
|||
"azFunc.appSettings.encrypt": "Encrypt Settings",
|
||||
"azFunc.pickProcess": "Pick Process",
|
||||
"azFunc.deploySubpathDescription": "The default subpath of a workspace folder to use when deploying.",
|
||||
"azFunc.installDotnetTemplates": "Install templates for the .NET CLI",
|
||||
"azFunc.uninstallDotnetTemplates": "Uninstall templates for the .NET CLI",
|
||||
"azFunc.showCoreToolsWarningDescription": "Show a warning if your installed version of Azure Functions Core Tools is out-of-date.",
|
||||
"azFunc.show64BitWarningDescription": "Show a warning to install a 64-bit version of the Azure Functions Core Tools when you create a .NET Framework project.",
|
||||
"azFunc.showProjectWarningDescription": "Show a warning when an Azure Functions project was detected that has not been initialized for use in VS Code.",
|
||||
|
|
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
|
@ -0,0 +1,995 @@
|
|||
{
|
||||
"runtimeTarget": {
|
||||
"name": ".NETCoreApp,Version=v2.0",
|
||||
"signature": "12ab36320203a93d9a46b7b16769f227b28d545e"
|
||||
},
|
||||
"compilationOptions": {},
|
||||
"targets": {
|
||||
".NETCoreApp,Version=v2.0": {
|
||||
"Microsoft.TemplateEngine.JsonCli/1.0.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.TemplateEngine.Cli": "1.0.1-beta3-20180212-1375715",
|
||||
"Microsoft.TemplateEngine.Orchestrator.RunnableProjects": "1.0.1-beta3-20180212-1375715"
|
||||
},
|
||||
"runtime": {
|
||||
"Microsoft.TemplateEngine.JsonCli.dll": {}
|
||||
}
|
||||
},
|
||||
"Microsoft.CSharp/4.0.1": {
|
||||
"dependencies": {
|
||||
"System.Collections": "4.3.0",
|
||||
"System.Diagnostics.Debug": "4.3.0",
|
||||
"System.Dynamic.Runtime": "4.0.11",
|
||||
"System.Globalization": "4.3.0",
|
||||
"System.Linq": "4.1.0",
|
||||
"System.Linq.Expressions": "4.1.0",
|
||||
"System.ObjectModel": "4.0.12",
|
||||
"System.Reflection": "4.3.0",
|
||||
"System.Reflection.Extensions": "4.3.0",
|
||||
"System.Reflection.Primitives": "4.3.0",
|
||||
"System.Reflection.TypeExtensions": "4.1.0",
|
||||
"System.Resources.ResourceManager": "4.3.0",
|
||||
"System.Runtime": "4.3.0",
|
||||
"System.Runtime.Extensions": "4.3.0",
|
||||
"System.Runtime.InteropServices": "4.3.0",
|
||||
"System.Threading": "4.3.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.DotNet.Cli.CommandLine/0.1.0-alpha-142": {
|
||||
"runtime": {
|
||||
"lib/netstandard1.5/Microsoft.DotNet.Cli.CommandLine.dll": {
|
||||
"assemblyVersion": "0.1.0.0",
|
||||
"fileVersion": "0.1.0.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Microsoft.NETCore.Targets/1.1.0": {},
|
||||
"Microsoft.TemplateEngine.Abstractions/1.0.1-beta3-20180212-1375715": {
|
||||
"runtime": {
|
||||
"lib/netstandard1.3/Microsoft.TemplateEngine.Abstractions.dll": {
|
||||
"assemblyVersion": "1.0.1.0",
|
||||
"fileVersion": "1.0.1.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Microsoft.TemplateEngine.Cli/1.0.1-beta3-20180212-1375715": {
|
||||
"dependencies": {
|
||||
"Microsoft.DotNet.Cli.CommandLine": "0.1.0-alpha-142",
|
||||
"Microsoft.TemplateEngine.Abstractions": "1.0.1-beta3-20180212-1375715",
|
||||
"Microsoft.TemplateEngine.Edge": "1.0.1-beta3-20180212-1375715",
|
||||
"Microsoft.TemplateEngine.Utils": "1.0.1-beta3-20180212-1375715",
|
||||
"Newtonsoft.Json": "9.0.1",
|
||||
"System.Diagnostics.Process": "4.3.0"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/netstandard1.5/Microsoft.TemplateEngine.Cli.dll": {
|
||||
"assemblyVersion": "1.0.1.0",
|
||||
"fileVersion": "1.0.1.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Microsoft.TemplateEngine.Core/1.0.1-beta3-20180212-1375715": {
|
||||
"dependencies": {
|
||||
"Microsoft.TemplateEngine.Abstractions": "1.0.1-beta3-20180212-1375715",
|
||||
"Microsoft.TemplateEngine.Core.Contracts": "1.0.1-beta3-20180212-1375715",
|
||||
"Microsoft.TemplateEngine.Utils": "1.0.1-beta3-20180212-1375715",
|
||||
"System.Runtime.InteropServices.RuntimeInformation": "4.3.0"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/netstandard1.3/Microsoft.TemplateEngine.Core.dll": {
|
||||
"assemblyVersion": "1.0.1.0",
|
||||
"fileVersion": "1.0.1.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Microsoft.TemplateEngine.Core.Contracts/1.0.1-beta3-20180212-1375715": {
|
||||
"dependencies": {
|
||||
"Microsoft.TemplateEngine.Abstractions": "1.0.1-beta3-20180212-1375715"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/netstandard1.3/Microsoft.TemplateEngine.Core.Contracts.dll": {
|
||||
"assemblyVersion": "1.0.1.0",
|
||||
"fileVersion": "1.0.1.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Microsoft.TemplateEngine.Edge/1.0.1-beta3-20180212-1375715": {
|
||||
"dependencies": {
|
||||
"Microsoft.TemplateEngine.Abstractions": "1.0.1-beta3-20180212-1375715",
|
||||
"Microsoft.TemplateEngine.Utils": "1.0.1-beta3-20180212-1375715",
|
||||
"Newtonsoft.Json": "9.0.1",
|
||||
"System.IO.Compression": "4.3.0",
|
||||
"System.Runtime.Loader": "4.3.0"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/netstandard1.5/Microsoft.TemplateEngine.Edge.dll": {
|
||||
"assemblyVersion": "1.0.1.0",
|
||||
"fileVersion": "1.0.1.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Microsoft.TemplateEngine.Orchestrator.RunnableProjects/1.0.1-beta3-20180212-1375715": {
|
||||
"dependencies": {
|
||||
"Microsoft.TemplateEngine.Abstractions": "1.0.1-beta3-20180212-1375715",
|
||||
"Microsoft.TemplateEngine.Core": "1.0.1-beta3-20180212-1375715",
|
||||
"Microsoft.TemplateEngine.Core.Contracts": "1.0.1-beta3-20180212-1375715",
|
||||
"Microsoft.TemplateEngine.Utils": "1.0.1-beta3-20180212-1375715",
|
||||
"Newtonsoft.Json": "9.0.1"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/netstandard1.3/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.dll": {
|
||||
"assemblyVersion": "1.0.1.0",
|
||||
"fileVersion": "1.0.1.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Microsoft.TemplateEngine.Utils/1.0.1-beta3-20180212-1375715": {
|
||||
"dependencies": {
|
||||
"Microsoft.TemplateEngine.Abstractions": "1.0.1-beta3-20180212-1375715",
|
||||
"System.Runtime.InteropServices.RuntimeInformation": "4.3.0"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/netstandard1.3/Microsoft.TemplateEngine.Utils.dll": {
|
||||
"assemblyVersion": "1.0.1.0",
|
||||
"fileVersion": "1.0.1.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Microsoft.Win32.Primitives/4.3.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Targets": "1.1.0",
|
||||
"System.Runtime": "4.3.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Win32.Registry/4.3.0": {
|
||||
"dependencies": {
|
||||
"System.Collections": "4.3.0",
|
||||
"System.Globalization": "4.3.0",
|
||||
"System.Resources.ResourceManager": "4.3.0",
|
||||
"System.Runtime": "4.3.0",
|
||||
"System.Runtime.Extensions": "4.3.0",
|
||||
"System.Runtime.Handles": "4.3.0",
|
||||
"System.Runtime.InteropServices": "4.3.0"
|
||||
},
|
||||
"runtimeTargets": {
|
||||
"runtime/unix/lib/_._": {
|
||||
"rid": "unix",
|
||||
"assetType": "runtime"
|
||||
},
|
||||
"runtime/win/lib/_._": {
|
||||
"rid": "win",
|
||||
"assetType": "runtime"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Newtonsoft.Json/9.0.1": {
|
||||
"dependencies": {
|
||||
"Microsoft.CSharp": "4.0.1",
|
||||
"System.Collections": "4.3.0",
|
||||
"System.Diagnostics.Debug": "4.3.0",
|
||||
"System.Dynamic.Runtime": "4.0.11",
|
||||
"System.Globalization": "4.3.0",
|
||||
"System.IO": "4.3.0",
|
||||
"System.Linq": "4.1.0",
|
||||
"System.Linq.Expressions": "4.1.0",
|
||||
"System.ObjectModel": "4.0.12",
|
||||
"System.Reflection": "4.3.0",
|
||||
"System.Reflection.Extensions": "4.3.0",
|
||||
"System.Resources.ResourceManager": "4.3.0",
|
||||
"System.Runtime": "4.3.0",
|
||||
"System.Runtime.Extensions": "4.3.0",
|
||||
"System.Runtime.Serialization.Primitives": "4.1.1",
|
||||
"System.Text.Encoding": "4.3.0",
|
||||
"System.Text.Encoding.Extensions": "4.3.0",
|
||||
"System.Text.RegularExpressions": "4.1.0",
|
||||
"System.Threading": "4.3.0",
|
||||
"System.Threading.Tasks": "4.3.0",
|
||||
"System.Xml.ReaderWriter": "4.0.11",
|
||||
"System.Xml.XDocument": "4.0.11"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/netstandard1.0/Newtonsoft.Json.dll": {
|
||||
"assemblyVersion": "9.0.0.0",
|
||||
"fileVersion": "9.0.1.19813"
|
||||
}
|
||||
}
|
||||
},
|
||||
"runtime.native.System/4.3.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Targets": "1.1.0"
|
||||
}
|
||||
},
|
||||
"runtime.native.System.IO.Compression/4.3.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Targets": "1.1.0"
|
||||
}
|
||||
},
|
||||
"System.Buffers/4.3.0": {
|
||||
"dependencies": {
|
||||
"System.Diagnostics.Debug": "4.3.0",
|
||||
"System.Diagnostics.Tracing": "4.3.0",
|
||||
"System.Resources.ResourceManager": "4.3.0",
|
||||
"System.Runtime": "4.3.0",
|
||||
"System.Threading": "4.3.0"
|
||||
}
|
||||
},
|
||||
"System.Collections/4.3.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Targets": "1.1.0",
|
||||
"System.Runtime": "4.3.0"
|
||||
}
|
||||
},
|
||||
"System.Diagnostics.Debug/4.3.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Targets": "1.1.0",
|
||||
"System.Runtime": "4.3.0"
|
||||
}
|
||||
},
|
||||
"System.Diagnostics.Process/4.3.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.Win32.Primitives": "4.3.0",
|
||||
"Microsoft.Win32.Registry": "4.3.0",
|
||||
"System.Collections": "4.3.0",
|
||||
"System.Diagnostics.Debug": "4.3.0",
|
||||
"System.Globalization": "4.3.0",
|
||||
"System.IO": "4.3.0",
|
||||
"System.IO.FileSystem": "4.3.0",
|
||||
"System.IO.FileSystem.Primitives": "4.3.0",
|
||||
"System.Resources.ResourceManager": "4.3.0",
|
||||
"System.Runtime": "4.3.0",
|
||||
"System.Runtime.Extensions": "4.3.0",
|
||||
"System.Runtime.Handles": "4.3.0",
|
||||
"System.Runtime.InteropServices": "4.3.0",
|
||||
"System.Text.Encoding": "4.3.0",
|
||||
"System.Text.Encoding.Extensions": "4.3.0",
|
||||
"System.Threading": "4.3.0",
|
||||
"System.Threading.Tasks": "4.3.0",
|
||||
"System.Threading.Thread": "4.3.0",
|
||||
"System.Threading.ThreadPool": "4.3.0",
|
||||
"runtime.native.System": "4.3.0"
|
||||
},
|
||||
"runtimeTargets": {
|
||||
"runtime/linux/lib/_._": {
|
||||
"rid": "linux",
|
||||
"assetType": "runtime"
|
||||
},
|
||||
"runtime/osx/lib/_._": {
|
||||
"rid": "osx",
|
||||
"assetType": "runtime"
|
||||
},
|
||||
"runtime/win/lib/_._": {
|
||||
"rid": "win",
|
||||
"assetType": "runtime"
|
||||
}
|
||||
}
|
||||
},
|
||||
"System.Diagnostics.Tools/4.0.1": {
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Targets": "1.1.0",
|
||||
"System.Runtime": "4.3.0"
|
||||
}
|
||||
},
|
||||
"System.Diagnostics.Tracing/4.3.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Targets": "1.1.0",
|
||||
"System.Runtime": "4.3.0"
|
||||
}
|
||||
},
|
||||
"System.Dynamic.Runtime/4.0.11": {
|
||||
"dependencies": {
|
||||
"System.Collections": "4.3.0",
|
||||
"System.Diagnostics.Debug": "4.3.0",
|
||||
"System.Globalization": "4.3.0",
|
||||
"System.Linq": "4.1.0",
|
||||
"System.Linq.Expressions": "4.1.0",
|
||||
"System.ObjectModel": "4.0.12",
|
||||
"System.Reflection": "4.3.0",
|
||||
"System.Reflection.Emit": "4.0.1",
|
||||
"System.Reflection.Emit.ILGeneration": "4.0.1",
|
||||
"System.Reflection.Primitives": "4.3.0",
|
||||
"System.Reflection.TypeExtensions": "4.1.0",
|
||||
"System.Resources.ResourceManager": "4.3.0",
|
||||
"System.Runtime": "4.3.0",
|
||||
"System.Runtime.Extensions": "4.3.0",
|
||||
"System.Threading": "4.3.0"
|
||||
}
|
||||
},
|
||||
"System.Globalization/4.3.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Targets": "1.1.0",
|
||||
"System.Runtime": "4.3.0"
|
||||
}
|
||||
},
|
||||
"System.IO/4.3.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Targets": "1.1.0",
|
||||
"System.Runtime": "4.3.0",
|
||||
"System.Text.Encoding": "4.3.0",
|
||||
"System.Threading.Tasks": "4.3.0"
|
||||
}
|
||||
},
|
||||
"System.IO.Compression/4.3.0": {
|
||||
"dependencies": {
|
||||
"System.Buffers": "4.3.0",
|
||||
"System.Collections": "4.3.0",
|
||||
"System.Diagnostics.Debug": "4.3.0",
|
||||
"System.IO": "4.3.0",
|
||||
"System.Resources.ResourceManager": "4.3.0",
|
||||
"System.Runtime": "4.3.0",
|
||||
"System.Runtime.Extensions": "4.3.0",
|
||||
"System.Runtime.Handles": "4.3.0",
|
||||
"System.Runtime.InteropServices": "4.3.0",
|
||||
"System.Text.Encoding": "4.3.0",
|
||||
"System.Threading": "4.3.0",
|
||||
"System.Threading.Tasks": "4.3.0",
|
||||
"runtime.native.System": "4.3.0",
|
||||
"runtime.native.System.IO.Compression": "4.3.0"
|
||||
},
|
||||
"runtimeTargets": {
|
||||
"runtime/unix/lib/_._": {
|
||||
"rid": "unix",
|
||||
"assetType": "runtime"
|
||||
},
|
||||
"runtime/win/lib/_._": {
|
||||
"rid": "win",
|
||||
"assetType": "runtime"
|
||||
}
|
||||
}
|
||||
},
|
||||
"System.IO.FileSystem/4.3.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Targets": "1.1.0",
|
||||
"System.IO": "4.3.0",
|
||||
"System.IO.FileSystem.Primitives": "4.3.0",
|
||||
"System.Runtime": "4.3.0",
|
||||
"System.Runtime.Handles": "4.3.0",
|
||||
"System.Text.Encoding": "4.3.0",
|
||||
"System.Threading.Tasks": "4.3.0"
|
||||
}
|
||||
},
|
||||
"System.IO.FileSystem.Primitives/4.3.0": {
|
||||
"dependencies": {
|
||||
"System.Runtime": "4.3.0"
|
||||
}
|
||||
},
|
||||
"System.Linq/4.1.0": {
|
||||
"dependencies": {
|
||||
"System.Collections": "4.3.0",
|
||||
"System.Diagnostics.Debug": "4.3.0",
|
||||
"System.Resources.ResourceManager": "4.3.0",
|
||||
"System.Runtime": "4.3.0",
|
||||
"System.Runtime.Extensions": "4.3.0"
|
||||
}
|
||||
},
|
||||
"System.Linq.Expressions/4.1.0": {
|
||||
"dependencies": {
|
||||
"System.Collections": "4.3.0",
|
||||
"System.Diagnostics.Debug": "4.3.0",
|
||||
"System.Globalization": "4.3.0",
|
||||
"System.IO": "4.3.0",
|
||||
"System.Linq": "4.1.0",
|
||||
"System.ObjectModel": "4.0.12",
|
||||
"System.Reflection": "4.3.0",
|
||||
"System.Reflection.Emit": "4.0.1",
|
||||
"System.Reflection.Emit.ILGeneration": "4.0.1",
|
||||
"System.Reflection.Emit.Lightweight": "4.0.1",
|
||||
"System.Reflection.Extensions": "4.3.0",
|
||||
"System.Reflection.Primitives": "4.3.0",
|
||||
"System.Reflection.TypeExtensions": "4.1.0",
|
||||
"System.Resources.ResourceManager": "4.3.0",
|
||||
"System.Runtime": "4.3.0",
|
||||
"System.Runtime.Extensions": "4.3.0",
|
||||
"System.Threading": "4.3.0"
|
||||
}
|
||||
},
|
||||
"System.ObjectModel/4.0.12": {
|
||||
"dependencies": {
|
||||
"System.Collections": "4.3.0",
|
||||
"System.Diagnostics.Debug": "4.3.0",
|
||||
"System.Resources.ResourceManager": "4.3.0",
|
||||
"System.Runtime": "4.3.0",
|
||||
"System.Threading": "4.3.0"
|
||||
}
|
||||
},
|
||||
"System.Reflection/4.3.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Targets": "1.1.0",
|
||||
"System.IO": "4.3.0",
|
||||
"System.Reflection.Primitives": "4.3.0",
|
||||
"System.Runtime": "4.3.0"
|
||||
}
|
||||
},
|
||||
"System.Reflection.Emit/4.0.1": {
|
||||
"dependencies": {
|
||||
"System.IO": "4.3.0",
|
||||
"System.Reflection": "4.3.0",
|
||||
"System.Reflection.Emit.ILGeneration": "4.0.1",
|
||||
"System.Reflection.Primitives": "4.3.0",
|
||||
"System.Runtime": "4.3.0"
|
||||
}
|
||||
},
|
||||
"System.Reflection.Emit.ILGeneration/4.0.1": {
|
||||
"dependencies": {
|
||||
"System.Reflection": "4.3.0",
|
||||
"System.Reflection.Primitives": "4.3.0",
|
||||
"System.Runtime": "4.3.0"
|
||||
}
|
||||
},
|
||||
"System.Reflection.Emit.Lightweight/4.0.1": {
|
||||
"dependencies": {
|
||||
"System.Reflection": "4.3.0",
|
||||
"System.Reflection.Emit.ILGeneration": "4.0.1",
|
||||
"System.Reflection.Primitives": "4.3.0",
|
||||
"System.Runtime": "4.3.0"
|
||||
}
|
||||
},
|
||||
"System.Reflection.Extensions/4.3.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Targets": "1.1.0",
|
||||
"System.Reflection": "4.3.0",
|
||||
"System.Runtime": "4.3.0"
|
||||
}
|
||||
},
|
||||
"System.Reflection.Primitives/4.3.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Targets": "1.1.0",
|
||||
"System.Runtime": "4.3.0"
|
||||
}
|
||||
},
|
||||
"System.Reflection.TypeExtensions/4.1.0": {
|
||||
"dependencies": {
|
||||
"System.Reflection": "4.3.0",
|
||||
"System.Runtime": "4.3.0"
|
||||
}
|
||||
},
|
||||
"System.Resources.ResourceManager/4.3.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Targets": "1.1.0",
|
||||
"System.Globalization": "4.3.0",
|
||||
"System.Reflection": "4.3.0",
|
||||
"System.Runtime": "4.3.0"
|
||||
}
|
||||
},
|
||||
"System.Runtime/4.3.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Targets": "1.1.0"
|
||||
}
|
||||
},
|
||||
"System.Runtime.Extensions/4.3.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Targets": "1.1.0",
|
||||
"System.Runtime": "4.3.0"
|
||||
}
|
||||
},
|
||||
"System.Runtime.Handles/4.3.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Targets": "1.1.0",
|
||||
"System.Runtime": "4.3.0"
|
||||
}
|
||||
},
|
||||
"System.Runtime.InteropServices/4.3.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Targets": "1.1.0",
|
||||
"System.Reflection": "4.3.0",
|
||||
"System.Reflection.Primitives": "4.3.0",
|
||||
"System.Runtime": "4.3.0",
|
||||
"System.Runtime.Handles": "4.3.0"
|
||||
}
|
||||
},
|
||||
"System.Runtime.InteropServices.RuntimeInformation/4.3.0": {
|
||||
"dependencies": {
|
||||
"System.Reflection": "4.3.0",
|
||||
"System.Reflection.Extensions": "4.3.0",
|
||||
"System.Resources.ResourceManager": "4.3.0",
|
||||
"System.Runtime": "4.3.0",
|
||||
"System.Runtime.InteropServices": "4.3.0",
|
||||
"System.Threading": "4.3.0",
|
||||
"runtime.native.System": "4.3.0"
|
||||
},
|
||||
"runtimeTargets": {
|
||||
"runtime/unix/lib/_._": {
|
||||
"rid": "unix",
|
||||
"assetType": "runtime"
|
||||
},
|
||||
"runtime/win/lib/_._": {
|
||||
"rid": "win",
|
||||
"assetType": "runtime"
|
||||
}
|
||||
}
|
||||
},
|
||||
"System.Runtime.Loader/4.3.0": {
|
||||
"dependencies": {
|
||||
"System.IO": "4.3.0",
|
||||
"System.Reflection": "4.3.0",
|
||||
"System.Runtime": "4.3.0"
|
||||
}
|
||||
},
|
||||
"System.Runtime.Serialization.Primitives/4.1.1": {
|
||||
"dependencies": {
|
||||
"System.Resources.ResourceManager": "4.3.0",
|
||||
"System.Runtime": "4.3.0"
|
||||
}
|
||||
},
|
||||
"System.Text.Encoding/4.3.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Targets": "1.1.0",
|
||||
"System.Runtime": "4.3.0"
|
||||
}
|
||||
},
|
||||
"System.Text.Encoding.Extensions/4.3.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Targets": "1.1.0",
|
||||
"System.Runtime": "4.3.0",
|
||||
"System.Text.Encoding": "4.3.0"
|
||||
}
|
||||
},
|
||||
"System.Text.RegularExpressions/4.1.0": {
|
||||
"dependencies": {
|
||||
"System.Collections": "4.3.0",
|
||||
"System.Globalization": "4.3.0",
|
||||
"System.Resources.ResourceManager": "4.3.0",
|
||||
"System.Runtime": "4.3.0",
|
||||
"System.Runtime.Extensions": "4.3.0",
|
||||
"System.Threading": "4.3.0"
|
||||
}
|
||||
},
|
||||
"System.Threading/4.3.0": {
|
||||
"dependencies": {
|
||||
"System.Runtime": "4.3.0",
|
||||
"System.Threading.Tasks": "4.3.0"
|
||||
}
|
||||
},
|
||||
"System.Threading.Tasks/4.3.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Targets": "1.1.0",
|
||||
"System.Runtime": "4.3.0"
|
||||
}
|
||||
},
|
||||
"System.Threading.Tasks.Extensions/4.0.0": {
|
||||
"dependencies": {
|
||||
"System.Collections": "4.3.0",
|
||||
"System.Runtime": "4.3.0",
|
||||
"System.Threading.Tasks": "4.3.0"
|
||||
}
|
||||
},
|
||||
"System.Threading.Thread/4.3.0": {
|
||||
"dependencies": {
|
||||
"System.Runtime": "4.3.0"
|
||||
}
|
||||
},
|
||||
"System.Threading.ThreadPool/4.3.0": {
|
||||
"dependencies": {
|
||||
"System.Runtime": "4.3.0",
|
||||
"System.Runtime.Handles": "4.3.0"
|
||||
}
|
||||
},
|
||||
"System.Xml.ReaderWriter/4.0.11": {
|
||||
"dependencies": {
|
||||
"System.Collections": "4.3.0",
|
||||
"System.Diagnostics.Debug": "4.3.0",
|
||||
"System.Globalization": "4.3.0",
|
||||
"System.IO": "4.3.0",
|
||||
"System.IO.FileSystem": "4.3.0",
|
||||
"System.IO.FileSystem.Primitives": "4.3.0",
|
||||
"System.Resources.ResourceManager": "4.3.0",
|
||||
"System.Runtime": "4.3.0",
|
||||
"System.Runtime.Extensions": "4.3.0",
|
||||
"System.Runtime.InteropServices": "4.3.0",
|
||||
"System.Text.Encoding": "4.3.0",
|
||||
"System.Text.Encoding.Extensions": "4.3.0",
|
||||
"System.Text.RegularExpressions": "4.1.0",
|
||||
"System.Threading.Tasks": "4.3.0",
|
||||
"System.Threading.Tasks.Extensions": "4.0.0"
|
||||
}
|
||||
},
|
||||
"System.Xml.XDocument/4.0.11": {
|
||||
"dependencies": {
|
||||
"System.Collections": "4.3.0",
|
||||
"System.Diagnostics.Debug": "4.3.0",
|
||||
"System.Diagnostics.Tools": "4.0.1",
|
||||
"System.Globalization": "4.3.0",
|
||||
"System.IO": "4.3.0",
|
||||
"System.Reflection": "4.3.0",
|
||||
"System.Resources.ResourceManager": "4.3.0",
|
||||
"System.Runtime": "4.3.0",
|
||||
"System.Runtime.Extensions": "4.3.0",
|
||||
"System.Text.Encoding": "4.3.0",
|
||||
"System.Threading": "4.3.0",
|
||||
"System.Xml.ReaderWriter": "4.0.11"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"libraries": {
|
||||
"Microsoft.TemplateEngine.JsonCli/1.0.0": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Microsoft.CSharp/4.0.1": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-17h8b5mXa87XYKrrVqdgZ38JefSUqLChUQpXgSnpzsM0nDOhE40FTeNWOJ/YmySGV6tG6T8+hjz6vxbknHJr6A==",
|
||||
"path": "microsoft.csharp/4.0.1",
|
||||
"hashPath": "microsoft.csharp.4.0.1.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.DotNet.Cli.CommandLine/0.1.0-alpha-142": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-cJRQ8wRchiVercqc9XsdWRljurEvPgY4fhzUZtb8/wDpkkVX/9TyospjC7ZacGvtXtkY8hRubnOwfBvAIZpMeg==",
|
||||
"path": "microsoft.dotnet.cli.commandline/0.1.0-alpha-142",
|
||||
"hashPath": "microsoft.dotnet.cli.commandline.0.1.0-alpha-142.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.NETCore.Targets/1.1.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-aOZA3BWfz9RXjpzt0sRJJMjAscAUm3Hoa4UWAfceV9UTYxgwZ1lZt5nO2myFf+/jetYQo4uTP7zS8sJY67BBxg==",
|
||||
"path": "microsoft.netcore.targets/1.1.0",
|
||||
"hashPath": "microsoft.netcore.targets.1.1.0.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.TemplateEngine.Abstractions/1.0.1-beta3-20180212-1375715": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-3KigJHcuZDDkG/s4WPwelH4jeGOp29+Np28QFkX109umkoSMRXn4MCWzyd0t/aQB5+Fdi+U2cOL1qjBFuOrB0A==",
|
||||
"path": "microsoft.templateengine.abstractions/1.0.1-beta3-20180212-1375715",
|
||||
"hashPath": "microsoft.templateengine.abstractions.1.0.1-beta3-20180212-1375715.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.TemplateEngine.Cli/1.0.1-beta3-20180212-1375715": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-aBwLxeBt8Mvi3icI11A8q+QVgZ22VOOnP0P9DwxZnQJ1EaBAgiECgLiiNrxO3TdyJwb5e2t1jk0LHpUmQTnRxA==",
|
||||
"path": "microsoft.templateengine.cli/1.0.1-beta3-20180212-1375715",
|
||||
"hashPath": "microsoft.templateengine.cli.1.0.1-beta3-20180212-1375715.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.TemplateEngine.Core/1.0.1-beta3-20180212-1375715": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-uaBQSzvnA5g4wkUlFU2rRMREDsXN4qaWZE9LDOphCBtO2Yfx73ce952MSHGki2uoAMCCgxPMUurzJJAcklD8HA==",
|
||||
"path": "microsoft.templateengine.core/1.0.1-beta3-20180212-1375715",
|
||||
"hashPath": "microsoft.templateengine.core.1.0.1-beta3-20180212-1375715.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.TemplateEngine.Core.Contracts/1.0.1-beta3-20180212-1375715": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-hdUxrkjuSVIpcjLW2UwsxepSUnmMH8hjd9TLNwEuZhJOM24A6/Qs2op7NRAGf1AfF6bTb/XbXCAiy8sJxbskGw==",
|
||||
"path": "microsoft.templateengine.core.contracts/1.0.1-beta3-20180212-1375715",
|
||||
"hashPath": "microsoft.templateengine.core.contracts.1.0.1-beta3-20180212-1375715.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.TemplateEngine.Edge/1.0.1-beta3-20180212-1375715": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-kR9ZEXdkkpTsZIK2IF6DiX0JG1vCwj+8cp+/MedcPCLpHyx0sloo5sMAawAv8CIzpd85ZcdpMSiy+fVTSRcZTA==",
|
||||
"path": "microsoft.templateengine.edge/1.0.1-beta3-20180212-1375715",
|
||||
"hashPath": "microsoft.templateengine.edge.1.0.1-beta3-20180212-1375715.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.TemplateEngine.Orchestrator.RunnableProjects/1.0.1-beta3-20180212-1375715": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-rUXaRKDJurmTk48oYvLBB6g3xiVnQTJKY2zMQC5mgmNCcf9AtjVNNcczgnzCJEO8wqedsuNuWk3y3lQiKOwQhg==",
|
||||
"path": "microsoft.templateengine.orchestrator.runnableprojects/1.0.1-beta3-20180212-1375715",
|
||||
"hashPath": "microsoft.templateengine.orchestrator.runnableprojects.1.0.1-beta3-20180212-1375715.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.TemplateEngine.Utils/1.0.1-beta3-20180212-1375715": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-JSFRHP88D9Jar3O0uI8wMsk6CzS6IZMNvRBgRorZxfywxZ8aY1CFKEYfjGH/Dz2biWwrzcI4YukHWcYnfS4uqA==",
|
||||
"path": "microsoft.templateengine.utils/1.0.1-beta3-20180212-1375715",
|
||||
"hashPath": "microsoft.templateengine.utils.1.0.1-beta3-20180212-1375715.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.Win32.Primitives/4.3.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-9ZQKCWxH7Ijp9BfahvL2Zyf1cJIk8XYLF6Yjzr2yi0b2cOut/HQ31qf1ThHAgCc3WiZMdnWcfJCgN82/0UunxA==",
|
||||
"path": "microsoft.win32.primitives/4.3.0",
|
||||
"hashPath": "microsoft.win32.primitives.4.3.0.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.Win32.Registry/4.3.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-Lw1/VwLH1yxz6SfFEjVRCN0pnflLEsWgnV4qsdJ512/HhTwnKXUG+zDQ4yTO3K/EJQemGoNaBHX5InISNKTzUQ==",
|
||||
"path": "microsoft.win32.registry/4.3.0",
|
||||
"hashPath": "microsoft.win32.registry.4.3.0.nupkg.sha512"
|
||||
},
|
||||
"Newtonsoft.Json/9.0.1": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-U82mHQSKaIk+lpSVCbWYKNavmNH1i5xrExDEquU1i6I5pV6UMOqRnJRSlKO3cMPfcpp0RgDY+8jUXHdQ4IfXvw==",
|
||||
"path": "newtonsoft.json/9.0.1",
|
||||
"hashPath": "newtonsoft.json.9.0.1.nupkg.sha512"
|
||||
},
|
||||
"runtime.native.System/4.3.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-c/qWt2LieNZIj1jGnVNsE2Kl23Ya2aSTBuXMD6V7k9KWr6l16Tqdwq+hJScEpWER9753NWC8h96PaVNY5Ld7Jw==",
|
||||
"path": "runtime.native.system/4.3.0",
|
||||
"hashPath": "runtime.native.system.4.3.0.nupkg.sha512"
|
||||
},
|
||||
"runtime.native.System.IO.Compression/4.3.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-INBPonS5QPEgn7naufQFXJEp3zX6L4bwHgJ/ZH78aBTpeNfQMtf7C6VrAFhlq2xxWBveIOWyFzQjJ8XzHMhdOQ==",
|
||||
"path": "runtime.native.system.io.compression/4.3.0",
|
||||
"hashPath": "runtime.native.system.io.compression.4.3.0.nupkg.sha512"
|
||||
},
|
||||
"System.Buffers/4.3.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-ratu44uTIHgeBeI0dE8DWvmXVBSo4u7ozRZZHOMmK/JPpYyo0dAfgSiHlpiObMQ5lEtEyIXA40sKRYg5J6A8uQ==",
|
||||
"path": "system.buffers/4.3.0",
|
||||
"hashPath": "system.buffers.4.3.0.nupkg.sha512"
|
||||
},
|
||||
"System.Collections/4.3.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-3Dcj85/TBdVpL5Zr+gEEBUuFe2icOnLalmEh9hfck1PTYbbyWuZgh4fmm2ysCLTrqLQw6t3TgTyJ+VLp+Qb+Lw==",
|
||||
"path": "system.collections/4.3.0",
|
||||
"hashPath": "system.collections.4.3.0.nupkg.sha512"
|
||||
},
|
||||
"System.Diagnostics.Debug/4.3.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-ZUhUOdqmaG5Jk3Xdb8xi5kIyQYAA4PnTNlHx1mu9ZY3qv4ELIdKbnL/akbGaKi2RnNUWaZsAs31rvzFdewTj2g==",
|
||||
"path": "system.diagnostics.debug/4.3.0",
|
||||
"hashPath": "system.diagnostics.debug.4.3.0.nupkg.sha512"
|
||||
},
|
||||
"System.Diagnostics.Process/4.3.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-J0wOX07+QASQblsfxmIMFc9Iq7KTXYL3zs2G/Xc704Ylv3NpuVdo6gij6V3PGiptTxqsK0K7CdXenRvKUnkA2g==",
|
||||
"path": "system.diagnostics.process/4.3.0",
|
||||
"hashPath": "system.diagnostics.process.4.3.0.nupkg.sha512"
|
||||
},
|
||||
"System.Diagnostics.Tools/4.0.1": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-xBfJ8pnd4C17dWaC9FM6aShzbJcRNMChUMD42I6772KGGrqaFdumwhn9OdM68erj1ueNo3xdQ1EwiFjK5k8p0g==",
|
||||
"path": "system.diagnostics.tools/4.0.1",
|
||||
"hashPath": "system.diagnostics.tools.4.0.1.nupkg.sha512"
|
||||
},
|
||||
"System.Diagnostics.Tracing/4.3.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-rswfv0f/Cqkh78rA5S8eN8Neocz234+emGCtTF3lxPY96F+mmmUen6tbn0glN6PMvlKQb9bPAY5e9u7fgPTkKw==",
|
||||
"path": "system.diagnostics.tracing/4.3.0",
|
||||
"hashPath": "system.diagnostics.tracing.4.3.0.nupkg.sha512"
|
||||
},
|
||||
"System.Dynamic.Runtime/4.0.11": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-db34f6LHYM0U0JpE+sOmjar27BnqTVkbLJhgfwMpTdgTigG/Hna3m2MYVwnFzGGKnEJk2UXFuoVTr8WUbU91/A==",
|
||||
"path": "system.dynamic.runtime/4.0.11",
|
||||
"hashPath": "system.dynamic.runtime.4.0.11.nupkg.sha512"
|
||||
},
|
||||
"System.Globalization/4.3.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-kYdVd2f2PAdFGblzFswE4hkNANJBKRmsfa2X5LG2AcWE1c7/4t0pYae1L8vfZ5xvE2nK/R9JprtToA61OSHWIg==",
|
||||
"path": "system.globalization/4.3.0",
|
||||
"hashPath": "system.globalization.4.3.0.nupkg.sha512"
|
||||
},
|
||||
"System.IO/4.3.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-3qjaHvxQPDpSOYICjUoTsmoq5u6QJAFRUITgeT/4gqkF1bajbSmb1kwSxEA8AHlofqgcKJcM8udgieRNhaJ5Cg==",
|
||||
"path": "system.io/4.3.0",
|
||||
"hashPath": "system.io.4.3.0.nupkg.sha512"
|
||||
},
|
||||
"System.IO.Compression/4.3.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-YHndyoiV90iu4iKG115ibkhrG+S3jBm8Ap9OwoUAzO5oPDAWcr0SFwQFm0HjM8WkEZWo0zvLTyLmbvTkW1bXgg==",
|
||||
"path": "system.io.compression/4.3.0",
|
||||
"hashPath": "system.io.compression.4.3.0.nupkg.sha512"
|
||||
},
|
||||
"System.IO.FileSystem/4.3.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-3wEMARTnuio+ulnvi+hkRNROYwa1kylvYahhcLk4HSoVdl+xxTFVeVlYOfLwrDPImGls0mDqbMhrza8qnWPTdA==",
|
||||
"path": "system.io.filesystem/4.3.0",
|
||||
"hashPath": "system.io.filesystem.4.3.0.nupkg.sha512"
|
||||
},
|
||||
"System.IO.FileSystem.Primitives/4.3.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-6QOb2XFLch7bEc4lIcJH49nJN2HV+OC3fHDgsLVsBVBk3Y4hFAnOBGzJ2lUu7CyDDFo9IBWkSsnbkT6IBwwiMw==",
|
||||
"path": "system.io.filesystem.primitives/4.3.0",
|
||||
"hashPath": "system.io.filesystem.primitives.4.3.0.nupkg.sha512"
|
||||
},
|
||||
"System.Linq/4.1.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-bQ0iYFOQI0nuTnt+NQADns6ucV4DUvMdwN6CbkB1yj8i7arTGiTN5eok1kQwdnnNWSDZfIUySQY+J3d5KjWn0g==",
|
||||
"path": "system.linq/4.1.0",
|
||||
"hashPath": "system.linq.4.1.0.nupkg.sha512"
|
||||
},
|
||||
"System.Linq.Expressions/4.1.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-I+y02iqkgmCAyfbqOmSDOgqdZQ5tTj80Akm5BPSS8EeB0VGWdy6X1KCoYe8Pk6pwDoAKZUOdLVxnTJcExiv5zw==",
|
||||
"path": "system.linq.expressions/4.1.0",
|
||||
"hashPath": "system.linq.expressions.4.1.0.nupkg.sha512"
|
||||
},
|
||||
"System.ObjectModel/4.0.12": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-tAgJM1xt3ytyMoW4qn4wIqgJYm7L7TShRZG4+Q4Qsi2PCcj96pXN7nRywS9KkB3p/xDUjc2HSwP9SROyPYDYKQ==",
|
||||
"path": "system.objectmodel/4.0.12",
|
||||
"hashPath": "system.objectmodel.4.0.12.nupkg.sha512"
|
||||
},
|
||||
"System.Reflection/4.3.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-KMiAFoW7MfJGa9nDFNcfu+FpEdiHpWgTcS2HdMpDvt9saK3y/G4GwprPyzqjFH9NTaGPQeWNHU+iDlDILj96aQ==",
|
||||
"path": "system.reflection/4.3.0",
|
||||
"hashPath": "system.reflection.4.3.0.nupkg.sha512"
|
||||
},
|
||||
"System.Reflection.Emit/4.0.1": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-P2wqAj72fFjpP6wb9nSfDqNBMab+2ovzSDzUZK7MVIm54tBJEPr9jWfSjjoTpPwj1LeKcmX3vr0ttyjSSFM47g==",
|
||||
"path": "system.reflection.emit/4.0.1",
|
||||
"hashPath": "system.reflection.emit.4.0.1.nupkg.sha512"
|
||||
},
|
||||
"System.Reflection.Emit.ILGeneration/4.0.1": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-Ov6dU8Bu15Bc7zuqttgHF12J5lwSWyTf1S+FJouUXVMSqImLZzYaQ+vRr1rQ0OZ0HqsrwWl4dsKHELckQkVpgA==",
|
||||
"path": "system.reflection.emit.ilgeneration/4.0.1",
|
||||
"hashPath": "system.reflection.emit.ilgeneration.4.0.1.nupkg.sha512"
|
||||
},
|
||||
"System.Reflection.Emit.Lightweight/4.0.1": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-sSzHHXueZ5Uh0OLpUQprhr+ZYJrLPA2Cmr4gn0wj9+FftNKXx8RIMKvO9qnjk2ebPYUjZ+F2ulGdPOsvj+MEjA==",
|
||||
"path": "system.reflection.emit.lightweight/4.0.1",
|
||||
"hashPath": "system.reflection.emit.lightweight.4.0.1.nupkg.sha512"
|
||||
},
|
||||
"System.Reflection.Extensions/4.3.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-rJkrJD3kBI5B712aRu4DpSIiHRtr6QlfZSQsb0hYHrDCZORXCFjQfoipo2LaMUHoT9i1B7j7MnfaEKWDFmFQNQ==",
|
||||
"path": "system.reflection.extensions/4.3.0",
|
||||
"hashPath": "system.reflection.extensions.4.3.0.nupkg.sha512"
|
||||
},
|
||||
"System.Reflection.Primitives/4.3.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-5RXItQz5As4xN2/YUDxdpsEkMhvw3e6aNveFXUn4Hl/udNTCNhnKp8lT9fnc3MhvGKh1baak5CovpuQUXHAlIA==",
|
||||
"path": "system.reflection.primitives/4.3.0",
|
||||
"hashPath": "system.reflection.primitives.4.3.0.nupkg.sha512"
|
||||
},
|
||||
"System.Reflection.TypeExtensions/4.1.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-tsQ/ptQ3H5FYfON8lL4MxRk/8kFyE0A+tGPXmVP967cT/gzLHYxIejIYSxp4JmIeFHVP78g/F2FE1mUUTbDtrg==",
|
||||
"path": "system.reflection.typeextensions/4.1.0",
|
||||
"hashPath": "system.reflection.typeextensions.4.1.0.nupkg.sha512"
|
||||
},
|
||||
"System.Resources.ResourceManager/4.3.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-/zrcPkkWdZmI4F92gL/TPumP98AVDu/Wxr3CSJGQQ+XN6wbRZcyfSKVoPo17ilb3iOr0cCRqJInGwNMolqhS8A==",
|
||||
"path": "system.resources.resourcemanager/4.3.0",
|
||||
"hashPath": "system.resources.resourcemanager.4.3.0.nupkg.sha512"
|
||||
},
|
||||
"System.Runtime/4.3.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-JufQi0vPQ0xGnAczR13AUFglDyVYt4Kqnz1AZaiKZ5+GICq0/1MH/mO/eAJHt/mHW1zjKBJd7kV26SrxddAhiw==",
|
||||
"path": "system.runtime/4.3.0",
|
||||
"hashPath": "system.runtime.4.3.0.nupkg.sha512"
|
||||
},
|
||||
"System.Runtime.Extensions/4.3.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-guW0uK0fn5fcJJ1tJVXYd7/1h5F+pea1r7FLSOz/f8vPEqbR2ZAknuRDvTQ8PzAilDveOxNjSfr0CHfIQfFk8g==",
|
||||
"path": "system.runtime.extensions/4.3.0",
|
||||
"hashPath": "system.runtime.extensions.4.3.0.nupkg.sha512"
|
||||
},
|
||||
"System.Runtime.Handles/4.3.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-OKiSUN7DmTWeYb3l51A7EYaeNMnvxwE249YtZz7yooT4gOZhmTjIn48KgSsw2k2lYdLgTKNJw/ZIfSElwDRVgg==",
|
||||
"path": "system.runtime.handles/4.3.0",
|
||||
"hashPath": "system.runtime.handles.4.3.0.nupkg.sha512"
|
||||
},
|
||||
"System.Runtime.InteropServices/4.3.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-uv1ynXqiMK8mp1GM3jDqPCFN66eJ5w5XNomaK2XD+TuCroNTLFGeZ+WCmBMcBDyTFKou3P6cR6J/QsaqDp7fGQ==",
|
||||
"path": "system.runtime.interopservices/4.3.0",
|
||||
"hashPath": "system.runtime.interopservices.4.3.0.nupkg.sha512"
|
||||
},
|
||||
"System.Runtime.InteropServices.RuntimeInformation/4.3.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-cbz4YJMqRDR7oLeMRbdYv7mYzc++17lNhScCX0goO2XpGWdvAt60CGN+FHdePUEHCe/Jy9jUlvNAiNdM+7jsOw==",
|
||||
"path": "system.runtime.interopservices.runtimeinformation/4.3.0",
|
||||
"hashPath": "system.runtime.interopservices.runtimeinformation.4.3.0.nupkg.sha512"
|
||||
},
|
||||
"System.Runtime.Loader/4.3.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-DHMaRn8D8YCK2GG2pw+UzNxn/OHVfaWx7OTLBD/hPegHZZgcZh3H6seWegrC4BYwsfuGrywIuT+MQs+rPqRLTQ==",
|
||||
"path": "system.runtime.loader/4.3.0",
|
||||
"hashPath": "system.runtime.loader.4.3.0.nupkg.sha512"
|
||||
},
|
||||
"System.Runtime.Serialization.Primitives/4.1.1": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-HZ6Du5QrTG8MNJbf4e4qMO3JRAkIboGT5Fk804uZtg3Gq516S7hAqTm2UZKUHa7/6HUGdVy3AqMQKbns06G/cg==",
|
||||
"path": "system.runtime.serialization.primitives/4.1.1",
|
||||
"hashPath": "system.runtime.serialization.primitives.4.1.1.nupkg.sha512"
|
||||
},
|
||||
"System.Text.Encoding/4.3.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-BiIg+KWaSDOITze6jGQynxg64naAPtqGHBwDrLaCtixsa5bKiR8dpPOHA7ge3C0JJQizJE+sfkz1wV+BAKAYZw==",
|
||||
"path": "system.text.encoding/4.3.0",
|
||||
"hashPath": "system.text.encoding.4.3.0.nupkg.sha512"
|
||||
},
|
||||
"System.Text.Encoding.Extensions/4.3.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-YVMK0Bt/A43RmwizJoZ22ei2nmrhobgeiYwFzC4YAN+nue8RF6djXDMog0UCn+brerQoYVyaS+ghy9P/MUVcmw==",
|
||||
"path": "system.text.encoding.extensions/4.3.0",
|
||||
"hashPath": "system.text.encoding.extensions.4.3.0.nupkg.sha512"
|
||||
},
|
||||
"System.Text.RegularExpressions/4.1.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-i88YCXpRTjCnoSQZtdlHkAOx4KNNik4hMy83n0+Ftlb7jvV6ZiZWMpnEZHhjBp6hQVh8gWd/iKNPzlPF7iyA2g==",
|
||||
"path": "system.text.regularexpressions/4.1.0",
|
||||
"hashPath": "system.text.regularexpressions.4.1.0.nupkg.sha512"
|
||||
},
|
||||
"System.Threading/4.3.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-VkUS0kOBcUf3Wwm0TSbrevDDZ6BlM+b/HRiapRFWjM5O0NS0LviG0glKmFK+hhPDd1XFeSdU1GmlLhb2CoVpIw==",
|
||||
"path": "system.threading/4.3.0",
|
||||
"hashPath": "system.threading.4.3.0.nupkg.sha512"
|
||||
},
|
||||
"System.Threading.Tasks/4.3.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-LbSxKEdOUhVe8BezB/9uOGGppt+nZf6e1VFyw6v3DN6lqitm0OSn2uXMOdtP0M3W4iMcqcivm2J6UgqiwwnXiA==",
|
||||
"path": "system.threading.tasks/4.3.0",
|
||||
"hashPath": "system.threading.tasks.4.3.0.nupkg.sha512"
|
||||
},
|
||||
"System.Threading.Tasks.Extensions/4.0.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-pH4FZDsZQ/WmgJtN4LWYmRdJAEeVkyriSwrv2Teoe5FOU0Yxlb6II6GL8dBPOfRmutHGATduj3ooMt7dJ2+i+w==",
|
||||
"path": "system.threading.tasks.extensions/4.0.0",
|
||||
"hashPath": "system.threading.tasks.extensions.4.0.0.nupkg.sha512"
|
||||
},
|
||||
"System.Threading.Thread/4.3.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-OHmbT+Zz065NKII/ZHcH9XO1dEuLGI1L2k7uYss+9C1jLxTC9kTZZuzUOyXHayRk+dft9CiDf3I/QZ0t8JKyBQ==",
|
||||
"path": "system.threading.thread/4.3.0",
|
||||
"hashPath": "system.threading.thread.4.3.0.nupkg.sha512"
|
||||
},
|
||||
"System.Threading.ThreadPool/4.3.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-k/+g4b7vjdd4aix83sTgC9VG6oXYKAktSfNIJUNGxPEj7ryEOfzHHhfnmsZvjxawwcD9HyWXKCXmPjX8U4zeSw==",
|
||||
"path": "system.threading.threadpool/4.3.0",
|
||||
"hashPath": "system.threading.threadpool.4.3.0.nupkg.sha512"
|
||||
},
|
||||
"System.Xml.ReaderWriter/4.0.11": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-ZIiLPsf67YZ9zgr31vzrFaYQqxRPX9cVHjtPSnmx4eN6lbS/yEyYNr2vs1doGDEscF0tjCZFsk9yUg1sC9e8tg==",
|
||||
"path": "system.xml.readerwriter/4.0.11",
|
||||
"hashPath": "system.xml.readerwriter.4.0.11.nupkg.sha512"
|
||||
},
|
||||
"System.Xml.XDocument/4.0.11": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-Mk2mKmPi0nWaoiYeotq1dgeNK1fqWh61+EK+w4Wu8SWuTYLzpUnschb59bJtGywaPq7SmTuPf44wrXRwbIrukg==",
|
||||
"path": "system.xml.xdocument/4.0.11",
|
||||
"hashPath": "system.xml.xdocument.4.0.11.nupkg.sha512"
|
||||
}
|
||||
}
|
||||
}
|
Двоичный файл не отображается.
Двоичный файл не отображается.
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"runtimeOptions": {
|
||||
"tfm": "netcoreapp2.0",
|
||||
"framework": {
|
||||
"name": "Microsoft.NETCore.App",
|
||||
"version": "2.0.0"
|
||||
}
|
||||
}
|
||||
}
|
Двоичные данные
resources/dotnetJsonCli/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.dll
Executable file
Двоичные данные
resources/dotnetJsonCli/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.dll
Executable file
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
|
@ -10,7 +10,7 @@ import { localSettingsFileName } from './constants';
|
|||
import { NoSubscriptionError } from './errors';
|
||||
import { ext } from './extensionVariables';
|
||||
import { localize } from './localize';
|
||||
import { getResourceTypeLabel, ResourceType } from './templates/ConfigSetting';
|
||||
import { getResourceTypeLabel, ResourceType } from './templates/IFunctionSetting';
|
||||
import * as azUtil from './utils/azure';
|
||||
import { IResourceResult } from './utils/azure';
|
||||
import * as fsUtil from './utils/fs';
|
||||
|
|
|
@ -5,31 +5,28 @@
|
|||
|
||||
import * as fse from 'fs-extra';
|
||||
import * as path from 'path';
|
||||
import { OutputChannel } from "vscode";
|
||||
import { IAzureUserInput } from 'vscode-azureextensionui';
|
||||
// tslint:disable-next-line:no-require-imports
|
||||
import XRegExp = require('xregexp');
|
||||
import { ProjectRuntime } from '../../constants';
|
||||
import { localize } from "../../localize";
|
||||
import { Template } from "../../templates/Template";
|
||||
import { removeLanguageFromId } from "../../templates/TemplateData";
|
||||
import { cpUtils } from "../../utils/cpUtils";
|
||||
import { executeDotnetTemplateCommand } from '../../templates/executeDotnetTemplateCommand';
|
||||
import { IFunctionTemplate } from "../../templates/IFunctionTemplate";
|
||||
import { dotnetUtils } from '../../utils/dotnetUtils';
|
||||
import * as fsUtil from '../../utils/fs';
|
||||
import { FunctionCreatorBase } from './FunctionCreatorBase';
|
||||
|
||||
export class CSharpFunctionCreator extends FunctionCreatorBase {
|
||||
private _outputChannel: OutputChannel;
|
||||
private _functionName: string;
|
||||
private _namespace: string;
|
||||
|
||||
constructor(functionAppPath: string, template: Template, outputChannel: OutputChannel) {
|
||||
constructor(functionAppPath: string, template: IFunctionTemplate) {
|
||||
super(functionAppPath, template);
|
||||
this._outputChannel = outputChannel;
|
||||
}
|
||||
|
||||
public async promptForSettings(ui: IAzureUserInput, functionName: string | undefined, functionSettings: { [key: string]: string | undefined; }): Promise<void> {
|
||||
if (!functionName) {
|
||||
const defaultFunctionName: string | undefined = await fsUtil.getUniqueFsPath(this._functionAppPath, removeLanguageFromId(this._template.id), '.cs');
|
||||
const defaultFunctionName: string | undefined = await fsUtil.getUniqueFsPath(this._functionAppPath, this._template.defaultFunctionName, '.cs');
|
||||
this._functionName = await ui.showInputBox({
|
||||
placeHolder: localize('azFunc.funcNamePlaceholder', 'Function name'),
|
||||
prompt: localize('azFunc.funcNamePrompt', 'Provide a function name'),
|
||||
|
@ -52,36 +49,22 @@ export class CSharpFunctionCreator extends FunctionCreatorBase {
|
|||
}
|
||||
}
|
||||
|
||||
public async createFunction(userSettings: { [propertyName: string]: string }): Promise<string | undefined> {
|
||||
await dotnetUtils.validateTemplatesInstalled();
|
||||
public async createFunction(userSettings: { [propertyName: string]: string }, runtime: ProjectRuntime): Promise<string | undefined> {
|
||||
await dotnetUtils.validateDotnetInstalled();
|
||||
|
||||
const args: string[] = [];
|
||||
args.push('--arg:name');
|
||||
args.push(this._functionName);
|
||||
|
||||
args.push('--arg:namespace');
|
||||
args.push(this._namespace);
|
||||
|
||||
for (const key of Object.keys(userSettings)) {
|
||||
let parameter: string = key.charAt(0).toUpperCase() + key.slice(1);
|
||||
// the parameters for dotnet templates are not consistent. Hence, we have to special-case a few of them:
|
||||
if (parameter.toLowerCase() === 'authlevel') {
|
||||
parameter = 'AccessRights';
|
||||
}
|
||||
|
||||
// https://github.com/Microsoft/vscode-azurefunctions/issues/166
|
||||
const nameSuffix: string = '/{name}';
|
||||
if (userSettings[key].endsWith(nameSuffix)) {
|
||||
userSettings[key] = userSettings[key].slice(0, -1 * nameSuffix.length);
|
||||
}
|
||||
|
||||
args.push(`--${parameter}="${userSettings[key]}"`);
|
||||
args.push(`--arg:${key}`);
|
||||
args.push(`"${userSettings[key]}"`);
|
||||
}
|
||||
|
||||
await cpUtils.executeCommand(
|
||||
this._outputChannel,
|
||||
this._functionAppPath,
|
||||
'dotnet',
|
||||
'new',
|
||||
removeLanguageFromId(this._template.id),
|
||||
`--name="${this._functionName}"`,
|
||||
`--namespace="${this._namespace}"`,
|
||||
...args
|
||||
);
|
||||
await executeDotnetTemplateCommand(runtime, this._functionAppPath, 'create', '--identity', this._template.id, ...args);
|
||||
|
||||
return path.join(this._functionAppPath, `${this._functionName}.cs`);
|
||||
}
|
||||
|
|
|
@ -4,14 +4,15 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IAzureUserInput } from "vscode-azureextensionui";
|
||||
import { Template } from "../../templates/Template";
|
||||
import { ProjectRuntime } from "../../constants";
|
||||
import { IFunctionTemplate } from "../../templates/IFunctionTemplate";
|
||||
|
||||
export abstract class FunctionCreatorBase {
|
||||
protected readonly _functionNameRegex: RegExp = /^[a-zA-Z][a-zA-Z\d_\-]*$/;
|
||||
protected _functionAppPath: string;
|
||||
protected _template: Template;
|
||||
protected _template: IFunctionTemplate;
|
||||
|
||||
constructor(functionAppPath: string, template: Template) {
|
||||
constructor(functionAppPath: string, template: IFunctionTemplate) {
|
||||
this._functionAppPath = functionAppPath;
|
||||
this._template = template;
|
||||
}
|
||||
|
@ -21,5 +22,5 @@ export abstract class FunctionCreatorBase {
|
|||
* This includes the function name (Since the name could have different restrictions for different languages)
|
||||
*/
|
||||
public abstract async promptForSettings(ui: IAzureUserInput, functionName: string | undefined, functionSettings: { [key: string]: string | undefined; }): Promise<void>;
|
||||
public abstract async createFunction(userSettings: { [propertyName: string]: string }): Promise<string | undefined>;
|
||||
public abstract async createFunction(userSettings: { [propertyName: string]: string }, runtime: ProjectRuntime): Promise<string | undefined>;
|
||||
}
|
||||
|
|
|
@ -8,8 +8,8 @@ import * as path from 'path';
|
|||
import { OutputChannel } from "vscode";
|
||||
import { IAzureUserInput } from 'vscode-azureextensionui';
|
||||
import { localize } from "../../localize";
|
||||
import { Template } from "../../templates/Template";
|
||||
import { removeLanguageFromId } from "../../templates/TemplateData";
|
||||
import { removeLanguageFromId } from "../../templates/FunctionTemplates";
|
||||
import { IFunctionTemplate } from "../../templates/IFunctionTemplate";
|
||||
import { cpUtils } from "../../utils/cpUtils";
|
||||
import * as fsUtil from '../../utils/fs';
|
||||
import { getFullClassName, parseJavaClassName, validatePackageName } from "../../utils/javaNameUtils";
|
||||
|
@ -25,7 +25,7 @@ export class JavaFunctionCreator extends FunctionCreatorBase {
|
|||
private _packageName: string;
|
||||
private _functionName: string;
|
||||
|
||||
constructor(functionAppPath: string, template: Template, outputChannel: OutputChannel) {
|
||||
constructor(functionAppPath: string, template: IFunctionTemplate, outputChannel: OutputChannel) {
|
||||
super(functionAppPath, template);
|
||||
this._outputChannel = outputChannel;
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ import * as path from 'path';
|
|||
import { IAzureUserInput } from 'vscode-azureextensionui';
|
||||
import { ProjectLanguage } from '../../constants';
|
||||
import { localize } from "../../localize";
|
||||
import { Template } from "../../templates/Template";
|
||||
import { IScriptFunctionTemplate } from '../../templates/parseScriptTemplates';
|
||||
import * as fsUtil from '../../utils/fs';
|
||||
import { FunctionCreatorBase } from './FunctionCreatorBase';
|
||||
|
||||
|
@ -41,10 +41,11 @@ export function getScriptFileNameFromLanguage(language: string): string | undefi
|
|||
* Function creator for multiple languages that don't require compilation (JavaScript, C# Script, Bash, etc.)
|
||||
*/
|
||||
export class ScriptFunctionCreator extends FunctionCreatorBase {
|
||||
protected _template: IScriptFunctionTemplate;
|
||||
private _language: string;
|
||||
private _functionName: string;
|
||||
|
||||
constructor(functionAppPath: string, template: Template, language: string) {
|
||||
constructor(functionAppPath: string, template: IScriptFunctionTemplate, language: string) {
|
||||
super(functionAppPath, template);
|
||||
this._language = language;
|
||||
}
|
||||
|
|
|
@ -14,9 +14,9 @@ import { ext } from '../../extensionVariables';
|
|||
import { promptForAppSetting, validateAzureWebJobsStorage } from '../../LocalAppSettings';
|
||||
import { localize } from '../../localize';
|
||||
import { getProjectLanguage, getProjectRuntime, getTemplateFilter, promptForProjectLanguage, promptForProjectRuntime, selectTemplateFilter, updateWorkspaceSetting } from '../../ProjectSettings';
|
||||
import { ConfigSetting, ValueType } from '../../templates/ConfigSetting';
|
||||
import { EnumValue } from '../../templates/EnumValue';
|
||||
import { Template } from '../../templates/Template';
|
||||
import { IEnumValue, IFunctionSetting, ValueType } from '../../templates/IFunctionSetting';
|
||||
import { IFunctionTemplate } from '../../templates/IFunctionTemplate';
|
||||
import { IScriptFunctionTemplate } from '../../templates/parseScriptTemplates';
|
||||
import * as workspaceUtil from '../../utils/workspace';
|
||||
import { createNewProject } from '../createNewProject/createNewProject';
|
||||
import { isFunctionProject } from '../createNewProject/validateFunctionProjects';
|
||||
|
@ -25,7 +25,7 @@ import { FunctionCreatorBase } from './FunctionCreatorBase';
|
|||
import { JavaFunctionCreator } from './JavaFunctionCreator';
|
||||
import { ScriptFunctionCreator } from './ScriptFunctionCreator';
|
||||
|
||||
async function promptForSetting(actionContext: IActionContext, localSettingsPath: string, setting: ConfigSetting, defaultValue?: string): Promise<string> {
|
||||
async function promptForSetting(actionContext: IActionContext, localSettingsPath: string, setting: IFunctionSetting): Promise<string> {
|
||||
if (setting.resourceType !== undefined) {
|
||||
return await promptForAppSetting(actionContext, localSettingsPath, setting.resourceType);
|
||||
} else {
|
||||
|
@ -36,18 +36,18 @@ async function promptForSetting(actionContext: IActionContext, localSettingsPath
|
|||
return await promptForEnumSetting(setting);
|
||||
default:
|
||||
// Default to 'string' type for any setting that isn't supported
|
||||
return await promptForStringSetting(setting, defaultValue);
|
||||
return await promptForStringSetting(setting);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function promptForEnumSetting(setting: ConfigSetting): Promise<string> {
|
||||
const picks: IAzureQuickPickItem<string>[] = setting.enums.map((ev: EnumValue) => { return { data: ev.value, label: ev.displayName, description: '' }; });
|
||||
async function promptForEnumSetting(setting: IFunctionSetting): Promise<string> {
|
||||
const picks: IAzureQuickPickItem<string>[] = setting.enums.map((ev: IEnumValue) => { return { data: ev.value, label: ev.displayName, description: '' }; });
|
||||
|
||||
return (await ext.ui.showQuickPick(picks, { placeHolder: setting.label })).data;
|
||||
}
|
||||
|
||||
async function promptForBooleanSetting(setting: ConfigSetting): Promise<string> {
|
||||
async function promptForBooleanSetting(setting: IFunctionSetting): Promise<string> {
|
||||
const picks: QuickPickItem[] = [
|
||||
{ label: 'true', description: '' },
|
||||
{ label: 'false', description: '' }
|
||||
|
@ -56,12 +56,12 @@ async function promptForBooleanSetting(setting: ConfigSetting): Promise<string>
|
|||
return (await ext.ui.showQuickPick(picks, { placeHolder: setting.label })).label;
|
||||
}
|
||||
|
||||
async function promptForStringSetting(setting: ConfigSetting, defaultValue?: string): Promise<string> {
|
||||
async function promptForStringSetting(setting: IFunctionSetting): Promise<string> {
|
||||
const options: vscode.InputBoxOptions = {
|
||||
placeHolder: setting.label,
|
||||
prompt: localize('azFunc.stringSettingPrompt', 'Provide a \'{0}\'', setting.label),
|
||||
validateInput: (s: string): string | undefined => setting.validateSetting(s),
|
||||
value: defaultValue ? defaultValue : setting.defaultValue
|
||||
value: setting.defaultValue
|
||||
};
|
||||
return await ext.ui.showInputBox(options);
|
||||
}
|
||||
|
@ -111,14 +111,14 @@ export async function createFunction(
|
|||
runtime = await getProjectRuntime(language, functionAppPath, ext.ui);
|
||||
}
|
||||
|
||||
let template: Template;
|
||||
let template: IFunctionTemplate;
|
||||
if (!templateId) {
|
||||
templateFilter = await getTemplateFilter(functionAppPath);
|
||||
[template, language, runtime, templateFilter] = await promptForTemplate(functionAppPath, language, runtime, templateFilter);
|
||||
} else {
|
||||
templateFilter = TemplateFilter.All;
|
||||
const templates: Template[] = await ext.templateData.getTemplates(language, runtime, TemplateFilter.All);
|
||||
const foundTemplate: Template | undefined = templates.find((t: Template) => t.id === templateId);
|
||||
const templates: IFunctionTemplate[] = await ext.functionTemplates.getTemplates(language, runtime, TemplateFilter.All);
|
||||
const foundTemplate: IFunctionTemplate | undefined = templates.find((t: IFunctionTemplate) => t.id === templateId);
|
||||
if (foundTemplate) {
|
||||
template = foundTemplate;
|
||||
} else {
|
||||
|
@ -138,38 +138,34 @@ export async function createFunction(
|
|||
functionCreator = new JavaFunctionCreator(functionAppPath, template, ext.outputChannel);
|
||||
break;
|
||||
case ProjectLanguage.CSharp:
|
||||
functionCreator = new CSharpFunctionCreator(functionAppPath, template, ext.outputChannel);
|
||||
functionCreator = new CSharpFunctionCreator(functionAppPath, template);
|
||||
break;
|
||||
default:
|
||||
functionCreator = new ScriptFunctionCreator(functionAppPath, template, language);
|
||||
functionCreator = new ScriptFunctionCreator(functionAppPath, <IScriptFunctionTemplate>template, language);
|
||||
break;
|
||||
}
|
||||
|
||||
await functionCreator.promptForSettings(ext.ui, functionName, functionSettings);
|
||||
|
||||
const userSettings: { [propertyName: string]: string } = {};
|
||||
for (const settingName of template.userPromptedSettings) {
|
||||
const setting: ConfigSetting | undefined = await ext.templateData.getSetting(runtime, template.functionConfig.inBindingType, settingName);
|
||||
if (setting) {
|
||||
let settingValue: string | undefined;
|
||||
if (functionSettings[settingName.toLowerCase()] !== undefined) {
|
||||
settingValue = functionSettings[settingName.toLowerCase()];
|
||||
} else {
|
||||
const defaultValue: string | undefined = template.functionConfig.inBinding[settingName];
|
||||
settingValue = await promptForSetting(actionContext, localSettingsPath, setting, defaultValue);
|
||||
}
|
||||
|
||||
userSettings[settingName] = settingValue ? settingValue : '';
|
||||
for (const setting of template.userPromptedSettings) {
|
||||
let settingValue: string | undefined;
|
||||
if (functionSettings[setting.name.toLowerCase()] !== undefined) {
|
||||
settingValue = functionSettings[setting.name.toLowerCase()];
|
||||
} else {
|
||||
settingValue = await promptForSetting(actionContext, localSettingsPath, setting);
|
||||
}
|
||||
|
||||
userSettings[setting.name] = settingValue ? settingValue : '';
|
||||
}
|
||||
|
||||
const newFilePath: string | undefined = await functionCreator.createFunction(userSettings);
|
||||
const newFilePath: string | undefined = await functionCreator.createFunction(userSettings, runtime);
|
||||
if (newFilePath && (await fse.pathExists(newFilePath))) {
|
||||
const newFileUri: vscode.Uri = vscode.Uri.file(newFilePath);
|
||||
vscode.window.showTextDocument(await vscode.workspace.openTextDocument(newFileUri));
|
||||
}
|
||||
|
||||
if (!template.functionConfig.isHttpTrigger) {
|
||||
if (!template.isHttpTrigger) {
|
||||
await validateAzureWebJobsStorage(actionContext, localSettingsPath);
|
||||
}
|
||||
|
||||
|
@ -178,15 +174,15 @@ export async function createFunction(
|
|||
}
|
||||
}
|
||||
|
||||
async function promptForTemplate(functionAppPath: string, language: ProjectLanguage, runtime: ProjectRuntime, templateFilter: TemplateFilter): Promise<[Template, ProjectLanguage, ProjectRuntime, TemplateFilter]> {
|
||||
async function promptForTemplate(functionAppPath: string, language: ProjectLanguage, runtime: ProjectRuntime, templateFilter: TemplateFilter): Promise<[IFunctionTemplate, ProjectLanguage, ProjectRuntime, TemplateFilter]> {
|
||||
const runtimePickId: string = 'runtime';
|
||||
const languagePickId: string = 'language';
|
||||
const filterPickId: string = 'filter';
|
||||
|
||||
let template: Template | undefined;
|
||||
let template: IFunctionTemplate | undefined;
|
||||
while (!template) {
|
||||
const templates: Template[] = await ext.templateData.getTemplates(language, runtime, templateFilter);
|
||||
let picks: IAzureQuickPickItem<Template | string>[] = templates.map((t: Template) => { return { data: t, label: t.name, description: '' }; });
|
||||
const templates: IFunctionTemplate[] = await ext.functionTemplates.getTemplates(language, runtime, templateFilter);
|
||||
let picks: IAzureQuickPickItem<IFunctionTemplate | string>[] = templates.map((t: IFunctionTemplate) => { return { data: t, label: t.name, description: '' }; });
|
||||
picks = picks.concat([
|
||||
{ label: localize('selectRuntime', '$(gear) Change project runtime'), description: localize('currentRuntime', 'Current: {0}', runtime), data: runtimePickId, suppressPersistence: true },
|
||||
{ label: localize('selectLanguage', '$(gear) Change project language'), description: localize('currentLanguage', 'Current: {0}', language), data: languagePickId, suppressPersistence: true },
|
||||
|
@ -194,7 +190,7 @@ async function promptForTemplate(functionAppPath: string, language: ProjectLangu
|
|||
]);
|
||||
|
||||
const placeHolder: string = templates.length > 0 ? localize('azFunc.selectFuncTemplate', 'Select a function template') : localize('azFunc.noTemplatesFound', 'No templates found. Change your settings to view more templates');
|
||||
const result: Template | string = (await ext.ui.showQuickPick(picks, { placeHolder })).data;
|
||||
const result: IFunctionTemplate | string = (await ext.ui.showQuickPick(picks, { placeHolder })).data;
|
||||
if (isString(result)) {
|
||||
switch (result) {
|
||||
case runtimePickId:
|
||||
|
|
|
@ -11,9 +11,10 @@ import { SemVer } from 'semver';
|
|||
import * as vscode from 'vscode';
|
||||
import { DialogResponses, parseError } from 'vscode-azureextensionui';
|
||||
import { gitignoreFileName, hostFileName, isWindows, localSettingsFileName, ProjectRuntime, TemplateFilter } from '../../constants';
|
||||
import { tryGetLocalRuntimeVersion } from '../../funcCoreTools/tryGetLocalRuntimeVersion';
|
||||
import { localize } from "../../localize";
|
||||
import { getFuncExtensionSetting, updateGlobalSetting } from '../../ProjectSettings';
|
||||
import { cpUtils } from '../../utils/cpUtils';
|
||||
import { getFuncExtensionSetting, promptForProjectRuntime, updateGlobalSetting } from '../../ProjectSettings';
|
||||
import { executeDotnetTemplateCommand } from '../../templates/executeDotnetTemplateCommand';
|
||||
import { dotnetUtils } from '../../utils/dotnetUtils';
|
||||
import { funcHostTaskId, ProjectCreatorBase } from './IProjectCreator';
|
||||
|
||||
|
@ -25,18 +26,16 @@ export class CSharpProjectCreator extends ProjectCreatorBase {
|
|||
private _runtime: ProjectRuntime;
|
||||
|
||||
public async addNonVSCodeFiles(): Promise<void> {
|
||||
await dotnetUtils.validateTemplatesInstalled();
|
||||
await dotnetUtils.validateDotnetInstalled();
|
||||
|
||||
const csProjName: string = `${path.basename(this.functionAppPath)}.csproj`;
|
||||
const overwriteExisting: boolean = await this.confirmOverwriteExisting(this.functionAppPath, csProjName);
|
||||
await cpUtils.executeCommand(
|
||||
this.outputChannel,
|
||||
this.functionAppPath,
|
||||
'dotnet',
|
||||
'new',
|
||||
dotnetUtils.funcProjectId,
|
||||
overwriteExisting ? '--force' : ''
|
||||
);
|
||||
const projectName: string = path.basename(this.functionAppPath);
|
||||
const csProjName: string = `${projectName}.csproj`;
|
||||
await this.confirmOverwriteExisting(this.functionAppPath, csProjName);
|
||||
|
||||
// tslint:disable-next-line:strict-boolean-expressions
|
||||
this._runtime = await tryGetLocalRuntimeVersion() || await promptForProjectRuntime(this.ui);
|
||||
const identity: string = `Microsoft.AzureFunctions.ProjectTemplate.CSharp.${this._runtime === ProjectRuntime.one ? '1' : '2'}.x`;
|
||||
await executeDotnetTemplateCommand(this._runtime, this.functionAppPath, 'create', '--identity', identity, '--arg:name', projectName);
|
||||
}
|
||||
|
||||
public async getRuntime(): Promise<ProjectRuntime> {
|
||||
|
|
|
@ -19,6 +19,7 @@ export enum ProjectLanguage {
|
|||
Batch = 'Batch',
|
||||
CSharp = 'C#',
|
||||
CSharpScript = 'C#Script',
|
||||
FSharp = 'F#',
|
||||
FSharpScript = 'F#Script',
|
||||
Java = 'Java',
|
||||
JavaScript = 'JavaScript',
|
||||
|
|
|
@ -38,12 +38,11 @@ import { stopFunctionApp } from './commands/stopFunctionApp';
|
|||
import { ext } from './extensionVariables';
|
||||
import { uninstallFuncCoreTools } from './funcCoreTools/uninstallFuncCoreTools';
|
||||
import { validateFuncCoreToolsIsLatest } from './funcCoreTools/validateFuncCoreToolsIsLatest';
|
||||
import { getTemplateData } from './templates/TemplateData';
|
||||
import { FunctionTemplates, getFunctionTemplates } from './templates/FunctionTemplates';
|
||||
import { FunctionAppProvider } from './tree/FunctionAppProvider';
|
||||
import { FunctionAppTreeItem } from './tree/FunctionAppTreeItem';
|
||||
import { FunctionTreeItem } from './tree/FunctionTreeItem';
|
||||
import { ProxyTreeItem } from './tree/ProxyTreeItem';
|
||||
import { dotnetUtils } from './utils/dotnetUtils';
|
||||
|
||||
export function activate(context: vscode.ExtensionContext): void {
|
||||
registerUIExtensionVariables(ext);
|
||||
|
@ -85,7 +84,9 @@ export function activate(context: vscode.ExtensionContext): void {
|
|||
await validateFunctionProjects(this, ui, outputChannel, event.added);
|
||||
});
|
||||
|
||||
const templateDataTask: Promise<void> = getTemplateDataTask(context);
|
||||
const templatesTask: Promise<void> = getFunctionTemplates().then((templates: FunctionTemplates) => {
|
||||
ext.functionTemplates = templates;
|
||||
});
|
||||
|
||||
registerCommand('azureFunctions.selectSubscriptions', () => vscode.commands.executeCommand('azure-account.selectSubscriptions'));
|
||||
registerCommand('azureFunctions.refresh', async (node?: IAzureNode) => await tree.refresh(node));
|
||||
|
@ -93,11 +94,11 @@ export function activate(context: vscode.ExtensionContext): void {
|
|||
registerCommand('azureFunctions.loadMore', async (node: IAzureNode) => await tree.loadMore(node));
|
||||
registerCommand('azureFunctions.openInPortal', async (node?: IAzureNode<FunctionAppTreeItem>) => await openInPortal(tree, node));
|
||||
registerCommand('azureFunctions.createFunction', async function (this: IActionContext, functionAppPath?: string, templateId?: string, functionName?: string, functionSettings?: {}): Promise<void> {
|
||||
await templateDataTask;
|
||||
await templatesTask;
|
||||
await createFunction(this, functionAppPath, templateId, functionName, functionSettings);
|
||||
});
|
||||
registerCommand('azureFunctions.createNewProject', async function (this: IActionContext, functionAppPath?: string, language?: string, runtime?: string, openFolder?: boolean | undefined, templateId?: string, functionName?: string, functionSettings?: {}): Promise<void> {
|
||||
await templateDataTask;
|
||||
await templatesTask;
|
||||
await createNewProject(this, functionAppPath, language, runtime, openFolder, templateId, functionName, functionSettings);
|
||||
});
|
||||
registerCommand('azureFunctions.initProjectForVSCode', async function (this: IActionContext): Promise<void> { await initProjectForVSCode(this.properties, ui, outputChannel); });
|
||||
|
@ -120,17 +121,12 @@ export function activate(context: vscode.ExtensionContext): void {
|
|||
registerCommand('azureFunctions.appSettings.decrypt', async (uri?: vscode.Uri) => await decryptLocalSettings(uri));
|
||||
registerCommand('azureFunctions.appSettings.encrypt', async (uri?: vscode.Uri) => await encryptLocalSettings(uri));
|
||||
registerCommand('azureFunctions.appSettings.delete', async (node?: IAzureNode<AppSettingTreeItem>) => await deleteNode(tree, AppSettingTreeItem.contextValue, node));
|
||||
registerCommand('azureFunctions.uninstallDotnetTemplates', async () => await dotnetUtils.uninstallTemplates());
|
||||
registerCommand('azureFunctions.debugFunctionAppOnAzure', async (node?: IAzureNode<FunctionAppTreeItem>) => await remoteDebugFunctionApp(outputChannel, ui, tree, node));
|
||||
registerCommand('azureFunctions.deleteProxy', async (node?: IAzureNode) => await deleteNode(tree, ProxyTreeItem.contextValue, node));
|
||||
registerCommand('azureFunctions.uninstallFuncCoreTools', async () => await uninstallFuncCoreTools());
|
||||
});
|
||||
}
|
||||
|
||||
async function getTemplateDataTask(context: vscode.ExtensionContext): Promise<void> {
|
||||
ext.templateData = await getTemplateData(context.globalState);
|
||||
}
|
||||
|
||||
// tslint:disable-next-line:no-empty
|
||||
export function deactivate(): void {
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
import { ExtensionContext, OutputChannel } from "vscode";
|
||||
import { AzureTreeDataProvider, IAzureUserInput } from "vscode-azureextensionui";
|
||||
import TelemetryReporter from "vscode-extension-telemetry";
|
||||
import { TemplateData } from "./templates/TemplateData";
|
||||
import { FunctionTemplates } from "./templates/FunctionTemplates";
|
||||
|
||||
/**
|
||||
* Namespace for common variables used throughout the extension. They must be initialized in the activate() method of extension.ts
|
||||
|
@ -16,6 +16,6 @@ export namespace ext {
|
|||
export let tree: AzureTreeDataProvider;
|
||||
export let outputChannel: OutputChannel;
|
||||
export let ui: IAzureUserInput;
|
||||
export let templateData: TemplateData;
|
||||
export let functionTemplates: FunctionTemplates;
|
||||
export let reporter: TelemetryReporter;
|
||||
}
|
||||
|
|
|
@ -12,12 +12,12 @@ import * as vscode from 'vscode';
|
|||
import { callWithTelemetryAndErrorHandling, DialogResponses, IActionContext, parseError } from 'vscode-azureextensionui';
|
||||
import { PackageManager, ProjectRuntime } from '../constants';
|
||||
import { ext } from '../extensionVariables';
|
||||
import { getFuncPackageManager } from '../funcCoreTools/getFuncPackageManager';
|
||||
import { getLocalFuncCoreToolsVersion } from '../funcCoreTools/getLocalFuncCoreToolsVersion';
|
||||
import { getProjectRuntimeFromVersion } from '../funcCoreTools/tryGetLocalRuntimeVersion';
|
||||
import { updateFuncCoreTools } from '../funcCoreTools/updateFuncCoreTools';
|
||||
import { localize } from '../localize';
|
||||
import { getFuncExtensionSetting, updateGlobalSetting } from '../ProjectSettings';
|
||||
import { getFuncPackageManager } from './getFuncPackageManager';
|
||||
import { getLocalFuncCoreToolsVersion } from './getLocalFuncCoreToolsVersion';
|
||||
import { getProjectRuntimeFromVersion } from './tryGetLocalRuntimeVersion';
|
||||
import { updateFuncCoreTools } from './updateFuncCoreTools';
|
||||
|
||||
export async function validateFuncCoreToolsIsLatest(): Promise<void> {
|
||||
await callWithTelemetryAndErrorHandling('azureFunctions.validateFuncCoreToolsIsLatest', async function (this: IActionContext): Promise<void> {
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ConfigBinding } from './ConfigBinding';
|
||||
import { ConfigVariables } from './ConfigVariables';
|
||||
import { Resources } from './Resources';
|
||||
|
||||
interface IConfig {
|
||||
variables: { [name: string]: string };
|
||||
bindings: object[];
|
||||
}
|
||||
|
||||
export class Config {
|
||||
public bindings: ConfigBinding[];
|
||||
constructor(data: object, resources: Resources) {
|
||||
const config: IConfig = <IConfig>data;
|
||||
const variables: ConfigVariables = new ConfigVariables(config.variables, resources);
|
||||
this.bindings = config.bindings.map((b: object) => new ConfigBinding(variables, b));
|
||||
}
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ConfigSetting } from './ConfigSetting';
|
||||
import { ConfigVariables } from './ConfigVariables';
|
||||
|
||||
interface IBinding {
|
||||
// tslint:disable-next-line:no-reserved-keywords
|
||||
type: string;
|
||||
settings: object[];
|
||||
}
|
||||
|
||||
export class ConfigBinding {
|
||||
public bindingType: string;
|
||||
public settings: ConfigSetting[];
|
||||
constructor(variables: ConfigVariables, data: object) {
|
||||
const binding: IBinding = <IBinding>data;
|
||||
this.bindingType = binding.type;
|
||||
this.settings = binding.settings.map((s: object) => new ConfigSetting(variables, s));
|
||||
}
|
||||
}
|
|
@ -1,94 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { localize } from '../localize';
|
||||
import { ConfigValidator } from './ConfigValidator';
|
||||
import { ConfigVariables } from './ConfigVariables';
|
||||
import { EnumValue } from './EnumValue';
|
||||
|
||||
export enum ValueType {
|
||||
string = 'string',
|
||||
boolean = 'boolean',
|
||||
enum = 'enum',
|
||||
checkBoxList = 'checkBoxList',
|
||||
int = 'int'
|
||||
}
|
||||
|
||||
export enum ResourceType {
|
||||
DocumentDB = 'DocumentDB',
|
||||
Storage = 'Storage',
|
||||
EventHub = 'EventHub'
|
||||
}
|
||||
|
||||
export function getResourceTypeLabel(resourceType: ResourceType): string {
|
||||
switch (resourceType) {
|
||||
case ResourceType.DocumentDB:
|
||||
return localize('azFunc.DocumentDB', 'Cosmos DB Account');
|
||||
case ResourceType.Storage:
|
||||
return localize('azFunc.Storage', 'Storage Account');
|
||||
case ResourceType.EventHub:
|
||||
return localize('azFunc.EventHub', 'Event Hub');
|
||||
default:
|
||||
return resourceType;
|
||||
}
|
||||
}
|
||||
|
||||
interface IBindingSetting {
|
||||
name: string;
|
||||
value: ValueType;
|
||||
label: string;
|
||||
defaultValue?: string;
|
||||
required: boolean;
|
||||
resource?: ResourceType;
|
||||
validators?: object[];
|
||||
// tslint:disable-next-line:no-reserved-keywords
|
||||
enum?: object[];
|
||||
}
|
||||
|
||||
export class ConfigSetting {
|
||||
private _setting: IBindingSetting;
|
||||
private _variables: ConfigVariables;
|
||||
constructor(variables: ConfigVariables, data: object) {
|
||||
this._variables = variables;
|
||||
this._setting = <IBindingSetting>data;
|
||||
}
|
||||
|
||||
public get resourceType(): ResourceType | undefined {
|
||||
return this._setting.resource;
|
||||
}
|
||||
|
||||
public get valueType(): ValueType | undefined {
|
||||
return this._setting.value;
|
||||
}
|
||||
|
||||
public get defaultValue(): string | undefined {
|
||||
return this._setting.defaultValue ? this._variables.getValue(this._setting.defaultValue) : undefined;
|
||||
}
|
||||
|
||||
public get label(): string {
|
||||
return this._variables.getValue(this._setting.label);
|
||||
}
|
||||
|
||||
public get name(): string {
|
||||
return this._variables.getValue(this._setting.name);
|
||||
}
|
||||
|
||||
public get enums(): EnumValue[] {
|
||||
return this._setting.enum ? this._setting.enum.map((ev: object) => new EnumValue(this._variables, ev)) : [];
|
||||
}
|
||||
|
||||
public validateSetting(value: string | undefined): string | undefined {
|
||||
if (this._setting.validators) {
|
||||
const validators: ConfigValidator[] = this._setting.validators.map((v: object) => new ConfigValidator(this._variables, v));
|
||||
for (const validator of validators) {
|
||||
if (!value || value.match(validator.expression) === null) {
|
||||
return validator.errorText;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ConfigVariables } from './ConfigVariables';
|
||||
|
||||
interface IConfigValidator {
|
||||
expression: string;
|
||||
errorText: string;
|
||||
}
|
||||
|
||||
export class ConfigValidator {
|
||||
private _validator: IConfigValidator;
|
||||
private _variables: ConfigVariables;
|
||||
constructor(variables: ConfigVariables, data: object) {
|
||||
this._variables = variables;
|
||||
this._validator = <IConfigValidator>data;
|
||||
}
|
||||
|
||||
public get expression(): string {
|
||||
return this._validator.expression;
|
||||
}
|
||||
|
||||
public get errorText(): string | undefined {
|
||||
return this._variables.getValue(this._validator.errorText);
|
||||
}
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Resources } from './Resources';
|
||||
|
||||
export class ConfigVariables {
|
||||
private _variables: { [name: string]: string };
|
||||
private _resources: Resources;
|
||||
constructor(variables: { [name: string]: string }, resources: Resources) {
|
||||
this._variables = variables;
|
||||
this._resources = resources;
|
||||
}
|
||||
|
||||
public getValue(data: string): string {
|
||||
const matches: RegExpMatchArray | null = data.match(/\[variables\(\'(.*)\'\)\]/);
|
||||
data = matches !== null ? this._variables[matches[1]] : data;
|
||||
|
||||
return this._resources.getValue(data);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ProjectRuntime } from '../constants';
|
||||
import { ext } from '../extensionVariables';
|
||||
import { dotnetUtils } from '../utils/dotnetUtils';
|
||||
import { downloadFile } from '../utils/fs';
|
||||
import { cliFeedJsonResponse } from '../utils/getCliFeedJson';
|
||||
import { executeDotnetTemplateCommand, getDotnetItemTemplatePath, getDotnetProjectTemplatePath } from './executeDotnetTemplateCommand';
|
||||
import { IFunctionTemplate } from './IFunctionTemplate';
|
||||
import { parseDotnetTemplates } from './parseDotnetTemplates';
|
||||
import { TemplateRetriever, TemplateType } from './TemplateRetriever';
|
||||
|
||||
export class DotnetTemplateRetriever extends TemplateRetriever {
|
||||
public templateType: TemplateType = TemplateType.Dotnet;
|
||||
private _dotnetTemplatesKey: string = 'DotnetTemplates';
|
||||
private _rawTemplates: object[];
|
||||
|
||||
public getVerifiedTemplateIds(runtime: ProjectRuntime): string[] {
|
||||
return getDotnetVerifiedTemplateIds(runtime);
|
||||
}
|
||||
|
||||
protected async getTemplatesFromCache(runtime: ProjectRuntime): Promise<IFunctionTemplate[] | undefined> {
|
||||
const cachedDotnetTemplates: object[] | undefined = ext.context.globalState.get<object[]>(this.getCacheKey(this._dotnetTemplatesKey, runtime));
|
||||
if (cachedDotnetTemplates) {
|
||||
return parseDotnetTemplates(cachedDotnetTemplates, runtime);
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
protected async getTemplatesFromCliFeed(cliFeedJson: cliFeedJsonResponse, templateVersion: string, runtime: ProjectRuntime): Promise<IFunctionTemplate[]> {
|
||||
await dotnetUtils.validateDotnetInstalled();
|
||||
|
||||
const projectFilePath: string = getDotnetProjectTemplatePath(runtime);
|
||||
await downloadFile(cliFeedJson.releases[templateVersion].projectTemplates, projectFilePath);
|
||||
|
||||
const itemFilePath: string = getDotnetItemTemplatePath(runtime);
|
||||
await downloadFile(cliFeedJson.releases[templateVersion].itemTemplates, itemFilePath);
|
||||
|
||||
this._rawTemplates = <object[]>JSON.parse(await executeDotnetTemplateCommand(runtime, undefined, 'list'));
|
||||
return parseDotnetTemplates(this._rawTemplates, runtime);
|
||||
}
|
||||
|
||||
protected async cacheTemplatesFromCliFeed(runtime: ProjectRuntime): Promise<void> {
|
||||
ext.context.globalState.update(this.getCacheKey(this._dotnetTemplatesKey, runtime), this._rawTemplates);
|
||||
}
|
||||
}
|
||||
|
||||
export function getDotnetVerifiedTemplateIds(runtime: string): string[] {
|
||||
const verifiedTemplateIds: string[] = [
|
||||
'Azure.Function.CSharp.HttpTrigger',
|
||||
'Azure.Function.CSharp.BlobTrigger',
|
||||
'Azure.Function.CSharp.QueueTrigger',
|
||||
'Azure.Function.CSharp.TimerTrigger'
|
||||
];
|
||||
|
||||
return verifiedTemplateIds.map((id: string) => {
|
||||
switch (runtime) {
|
||||
case ProjectRuntime.one:
|
||||
return `${id}.1.x`;
|
||||
case ProjectRuntime.beta:
|
||||
return `${id}.2.x`;
|
||||
default:
|
||||
throw new RangeError();
|
||||
}
|
||||
});
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ConfigVariables } from './ConfigVariables';
|
||||
|
||||
interface IEnumValue {
|
||||
value: string;
|
||||
display: string;
|
||||
}
|
||||
|
||||
export class EnumValue {
|
||||
private _enumValue: IEnumValue;
|
||||
private _variables: ConfigVariables;
|
||||
constructor(variables: ConfigVariables, data: object) {
|
||||
this._variables = variables;
|
||||
this._enumValue = <IEnumValue>data;
|
||||
}
|
||||
|
||||
get value(): string {
|
||||
return this._variables.getValue(this._enumValue.value);
|
||||
}
|
||||
|
||||
get displayName(): string {
|
||||
return this._variables.getValue(this._enumValue.display);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,168 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import { callWithTelemetryAndErrorHandling, IActionContext, parseError } from 'vscode-azureextensionui';
|
||||
import { betaReleaseVersion, ProjectLanguage, ProjectRuntime, TemplateFilter, templateVersionSetting, v1ReleaseVersion } from '../constants';
|
||||
import { ext } from '../extensionVariables';
|
||||
import { localize } from '../localize';
|
||||
import { getFuncExtensionSetting, updateGlobalSetting } from '../ProjectSettings';
|
||||
import { cliFeedJsonResponse, getFeedRuntime, tryGetCliFeedJson } from '../utils/getCliFeedJson';
|
||||
import { DotnetTemplateRetriever, getDotnetVerifiedTemplateIds } from './DotnetTemplateRetriever';
|
||||
import { IFunctionTemplate, TemplateCategory } from './IFunctionTemplate';
|
||||
import { getScriptVerifiedTemplateIds, ScriptTemplateRetriever } from './ScriptTemplateRetriever';
|
||||
import { TemplateRetriever } from './TemplateRetriever';
|
||||
|
||||
const verifiedJavaTemplates: string[] = [
|
||||
'HttpTrigger',
|
||||
'BlobTrigger',
|
||||
'QueueTrigger',
|
||||
'TimerTrigger'
|
||||
];
|
||||
|
||||
export class FunctionTemplates {
|
||||
private readonly _templatesMap: { [runtime: string]: IFunctionTemplate[] | undefined } = {};
|
||||
// if there are no templates, then there is likely no internet or a problem with the clifeed url
|
||||
private readonly _noInternetErrMsg: string = localize('retryInternet', 'There was an error in retrieving the templates. Recheck your internet connection and try again.');
|
||||
constructor(templatesMap: { [runtime: string]: IFunctionTemplate[] | undefined }) {
|
||||
this._templatesMap = templatesMap;
|
||||
}
|
||||
|
||||
public async getTemplates(language: string, runtime: string = ProjectRuntime.one, templateFilter?: string): Promise<IFunctionTemplate[]> {
|
||||
const templates: IFunctionTemplate[] | undefined = this._templatesMap[runtime];
|
||||
if (!templates) {
|
||||
throw new Error(this._noInternetErrMsg);
|
||||
}
|
||||
|
||||
if (language === ProjectLanguage.Java) {
|
||||
// Currently we leverage JS templates to get the function metadata of Java Functions.
|
||||
// Will refactor the code here when templates HTTP API is ready.
|
||||
// See issue here: https://github.com/Microsoft/vscode-azurefunctions/issues/84
|
||||
const javaTemplates: IFunctionTemplate[] = templates.filter((t: IFunctionTemplate) => t.language === ProjectLanguage.JavaScript);
|
||||
return javaTemplates.filter((t: IFunctionTemplate) => verifiedJavaTemplates.find((vt: string) => vt === removeLanguageFromId(t.id)));
|
||||
} else {
|
||||
let filterTemplates: IFunctionTemplate[] = templates.filter((t: IFunctionTemplate) => t.language.toLowerCase() === language.toLowerCase());
|
||||
switch (templateFilter) {
|
||||
case TemplateFilter.All:
|
||||
break;
|
||||
case TemplateFilter.Core:
|
||||
filterTemplates = filterTemplates.filter((t: IFunctionTemplate) => t.categories.find((c: TemplateCategory) => c === TemplateCategory.Core) !== undefined);
|
||||
break;
|
||||
case TemplateFilter.Verified:
|
||||
default:
|
||||
const verifiedTemplateIds: string[] = getScriptVerifiedTemplateIds(runtime).concat(getDotnetVerifiedTemplateIds(runtime));
|
||||
filterTemplates = filterTemplates.filter((t: IFunctionTemplate) => verifiedTemplateIds.find((vt: string) => vt === t.id));
|
||||
}
|
||||
|
||||
return filterTemplates;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export async function getFunctionTemplates(): Promise<FunctionTemplates> {
|
||||
const templatesMap: { [runtime: string]: IFunctionTemplate[] | undefined } = {};
|
||||
const cliFeedJson: cliFeedJsonResponse | undefined = await tryGetCliFeedJson();
|
||||
|
||||
const templateRetrievers: TemplateRetriever[] = [new ScriptTemplateRetriever(), new DotnetTemplateRetriever()];
|
||||
for (const templateRetriever of templateRetrievers) {
|
||||
for (const key of Object.keys(ProjectRuntime)) {
|
||||
const runtime: ProjectRuntime = <ProjectRuntime>ProjectRuntime[key];
|
||||
|
||||
await callWithTelemetryAndErrorHandling('azureFunctions.getFunctionTemplates', async function (this: IActionContext): Promise<void> {
|
||||
this.suppressErrorDisplay = true;
|
||||
this.properties.isActivationEvent = 'true';
|
||||
this.properties.runtime = runtime;
|
||||
this.properties.templateType = templateRetriever.templateType;
|
||||
const templateVersion: string | undefined = await tryGetTemplateVersionSetting(this, cliFeedJson, runtime);
|
||||
let templates: IFunctionTemplate[] | undefined;
|
||||
|
||||
// 1. Use the cached templates if they match templateVersion
|
||||
if (ext.context.globalState.get(templateRetriever.getCacheKey(TemplateRetriever.templateVersionKey, runtime)) === templateVersion) {
|
||||
templates = await templateRetriever.tryGetTemplatesFromCache(this, runtime);
|
||||
this.properties.templateSource = 'matchingCache';
|
||||
}
|
||||
|
||||
// 2. Download templates from the cli-feed if the cache doesn't match templateVersion
|
||||
if (!templates && cliFeedJson && templateVersion) {
|
||||
templates = await templateRetriever.tryGetTemplatesFromCliFeed(this, cliFeedJson, templateVersion, runtime);
|
||||
this.properties.templateSource = 'cliFeed';
|
||||
}
|
||||
|
||||
// 3. Use the cached templates, even if they don't match templateVersion
|
||||
if (!templates) {
|
||||
templates = await templateRetriever.tryGetTemplatesFromCache(this, runtime);
|
||||
this.properties.templateSource = 'mismatchCache';
|
||||
}
|
||||
|
||||
// 4. Download templates from the cli-feed using the backupVersion
|
||||
if (!templates && cliFeedJson) {
|
||||
const backupVersion: string = runtime === ProjectRuntime.one ? v1ReleaseVersion : betaReleaseVersion;
|
||||
templates = await templateRetriever.tryGetTemplatesFromCliFeed(this, cliFeedJson, backupVersion, runtime);
|
||||
this.properties.templateSource = 'backupCliFeed';
|
||||
}
|
||||
|
||||
if (templates) {
|
||||
// tslint:disable-next-line:strict-boolean-expressions
|
||||
templatesMap[runtime] = (templatesMap[runtime] || []).concat(templates);
|
||||
} else {
|
||||
// Failed to get templates for this runtime
|
||||
this.properties.templateSource = 'None';
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return new FunctionTemplates(templatesMap);
|
||||
}
|
||||
|
||||
export function removeLanguageFromId(id: string): string {
|
||||
return id.split('-')[0];
|
||||
}
|
||||
|
||||
async function tryGetTemplateVersionSetting(context: IActionContext, cliFeedJson: cliFeedJsonResponse | undefined, runtime: ProjectRuntime): Promise<string | undefined> {
|
||||
const feedRuntime: string = getFeedRuntime(runtime);
|
||||
const userTemplateVersion: string | undefined = getFuncExtensionSetting(templateVersionSetting);
|
||||
try {
|
||||
if (userTemplateVersion) {
|
||||
context.properties.userTemplateVersion = userTemplateVersion;
|
||||
}
|
||||
let templateVersion: string;
|
||||
if (cliFeedJson) {
|
||||
templateVersion = userTemplateVersion ? userTemplateVersion : cliFeedJson.tags[feedRuntime].release;
|
||||
// tslint:disable-next-line:strict-boolean-expressions
|
||||
if (!cliFeedJson.releases[templateVersion]) {
|
||||
const invalidVersion: string = localize('invalidTemplateVersion', 'Failed to retrieve Azure Functions templates for version "{0}".', templateVersion);
|
||||
const selectVersion: vscode.MessageItem = { title: localize('selectVersion', 'Select version') };
|
||||
const useLatest: vscode.MessageItem = { title: localize('useLatest', 'Use latest') };
|
||||
const warningInput: vscode.MessageItem = await ext.ui.showWarningMessage(invalidVersion, selectVersion, useLatest);
|
||||
if (warningInput === selectVersion) {
|
||||
const releaseQuickPicks: vscode.QuickPickItem[] = [];
|
||||
for (const rel of Object.keys(cliFeedJson.releases)) {
|
||||
releaseQuickPicks.push({
|
||||
label: rel,
|
||||
description: ''
|
||||
});
|
||||
}
|
||||
const input: vscode.QuickPickItem | undefined = await ext.ui.showQuickPick(releaseQuickPicks, { placeHolder: invalidVersion });
|
||||
templateVersion = input.label;
|
||||
await updateGlobalSetting(templateVersionSetting, input.label);
|
||||
} else {
|
||||
templateVersion = cliFeedJson.tags[feedRuntime].release;
|
||||
// reset user setting so that it always gets latest
|
||||
await updateGlobalSetting(templateVersionSetting, '');
|
||||
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return templateVersion;
|
||||
} catch (error) {
|
||||
// if cliJson does not have the template version being searched for, it will throw an error
|
||||
context.properties.userTemplateVersion = parseError(error).message;
|
||||
return undefined;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { localize } from '../localize';
|
||||
|
||||
export enum ValueType {
|
||||
string = 'string',
|
||||
boolean = 'boolean',
|
||||
enum = 'enum',
|
||||
checkBoxList = 'checkBoxList',
|
||||
int = 'int'
|
||||
}
|
||||
|
||||
export enum ResourceType {
|
||||
DocumentDB = 'DocumentDB',
|
||||
Storage = 'Storage',
|
||||
EventHub = 'EventHub'
|
||||
}
|
||||
|
||||
export function getResourceTypeLabel(resourceType: ResourceType): string {
|
||||
switch (resourceType) {
|
||||
case ResourceType.DocumentDB:
|
||||
return localize('azFunc.DocumentDB', 'Cosmos DB Account');
|
||||
case ResourceType.Storage:
|
||||
return localize('azFunc.Storage', 'Storage Account');
|
||||
case ResourceType.EventHub:
|
||||
return localize('azFunc.EventHub', 'Event Hub');
|
||||
default:
|
||||
return resourceType;
|
||||
}
|
||||
}
|
||||
|
||||
export interface IEnumValue {
|
||||
value: string;
|
||||
displayName: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Describes a setting used when creating a function trigger (i.e. 'AuthorizationLevel' for an HttpTrigger or 'Schedule' for a TimerTrigger)
|
||||
*/
|
||||
export interface IFunctionSetting {
|
||||
resourceType: ResourceType | undefined;
|
||||
valueType: ValueType | undefined;
|
||||
defaultValue: string | undefined;
|
||||
enums: IEnumValue[];
|
||||
label: string;
|
||||
name: string;
|
||||
validateSetting(value: string | undefined): string | undefined;
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IFunctionSetting } from './IFunctionSetting';
|
||||
|
||||
export enum TemplateCategory {
|
||||
Core = '$temp_category_core'
|
||||
}
|
||||
|
||||
/**
|
||||
* Describes a template used for creating a function trigger (i.e. an HttpTrigger or TimerTrigger)
|
||||
*/
|
||||
export interface IFunctionTemplate {
|
||||
id: string;
|
||||
name: string;
|
||||
defaultFunctionName: string;
|
||||
language: string;
|
||||
isHttpTrigger: boolean;
|
||||
userPromptedSettings: IFunctionSetting[];
|
||||
categories: TemplateCategory[];
|
||||
}
|
|
@ -1,9 +1,16 @@
|
|||
# Azure Function Templates
|
||||
|
||||
The code in this folder is used to parse and model the [function templates](https://github.com/Azure/azure-webjobs-sdk-templates) provided by the [Azure Functions portal](https://functions.azure.com/signin). The portal provides template data in three parts: templates.json, bindingconfig.json, and resources.json. See below for an example of the schema for the TimerTrigger template
|
||||
The code in this folder is used to parse and model the [function templates](https://github.com/Azure/azure-webjobs-sdk-templates) provided by the [Azure Functions CLI Feed](https://aka.ms/V00v5v). The Functions CLI Feed provides a central location to get the latest version of all templates used for functions. Currently, this repo leverages the following templates:
|
||||
|
||||
* [Script Templates](#script-templates) (i.e. JavaScript, C#Script, and Python)
|
||||
* [.NET Templates](#.net-templates) (i.e. C#)
|
||||
|
||||
## Script Templates
|
||||
|
||||
Script templates are retrieved from the 'templateApiZip' property in the CLI Feed. The zip contains data in three parts: templates.json, bindingconfig.json, and resources.json. See below for an example of the schema for the TimerTrigger template:
|
||||
|
||||
### Templates.json
|
||||
|
||||
## Templates.json
|
||||
[https://functions.azure.com/api/templates?runtime=~2](https://functions.azure.com/api/templates?runtime=~2)
|
||||
```json
|
||||
[
|
||||
{
|
||||
|
@ -43,8 +50,8 @@ The code in this folder is used to parse and model the [function templates](http
|
|||
]
|
||||
```
|
||||
|
||||
## BindingConfig.json
|
||||
[https://functions.azure.com/api/bindingconfig?runtime=~2](https://functions.azure.com/api/bindingconfig?runtime=~2)
|
||||
### BindingConfig.json
|
||||
|
||||
```json
|
||||
{
|
||||
"$schema": "<TBD>",
|
||||
|
@ -94,8 +101,8 @@ The code in this folder is used to parse and model the [function templates](http
|
|||
}
|
||||
```
|
||||
|
||||
## Resources.json
|
||||
[https://functions.azure.com/api/resources?runtime=~2&name=en-us](https://functions.azure.com/api/resources?runtime=~2&name=en-us)
|
||||
### Resources.json
|
||||
|
||||
```json
|
||||
{
|
||||
"lang": {},
|
||||
|
@ -113,3 +120,47 @@ The code in this folder is used to parse and model the [function templates](http
|
|||
}
|
||||
}
|
||||
```
|
||||
|
||||
## .NET Templates
|
||||
|
||||
.NET templates are retrieved from the 'itemTemplates' and 'projectTemplates' properties in the CLI Feed. These properties reference two nuget packages. We then leverage the 'Microsoft.TemplateEngine.JsonCli' dll which provides a JSON-based way to interact with .NET templates.
|
||||
|
||||
The following is an example command used to list templates:
|
||||
|
||||
```
|
||||
dotnet <path to extension>/resources/dotnetJsonCli/Microsoft.TemplateEngine.JsonCli.dll --require <path to extension>/resources/dotnetTemplates/itemTemplates-~1.nupkg --require <path to extension>/resources/dotnetTemplates/projectTemplates-~1.nupkg --operation list
|
||||
```
|
||||
|
||||
Example format for the Timer Trigger:
|
||||
|
||||
```json
|
||||
{
|
||||
"Author": "Microsoft",
|
||||
"Classifications": [
|
||||
"Azure Function"
|
||||
],
|
||||
"DefaultName": "TimerTriggerCSharp",
|
||||
"Identity": "Azure.Function.CSharp.TimerTrigger.1.x",
|
||||
"GroupIdentity": "Azure.Function.TimerTrigger",
|
||||
"Name": "TimerTrigger",
|
||||
"ShortName": "Timer",
|
||||
"Parameters": [
|
||||
{
|
||||
"Documentation": "Enter a cron expression of the format '{second} {minute} {hour} {day} {month} {day of week}' to specify the schedule.",
|
||||
"Name": "Schedule",
|
||||
"Priority": 0,
|
||||
"Type": null,
|
||||
"IsName": false,
|
||||
"DefaultValue": "0 */5 * * * *",
|
||||
"DataType": null,
|
||||
"Choices": null
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
And the following is an example command for creating a template:
|
||||
|
||||
```
|
||||
dotnet <path to extension>/resources/dotnetJsonCli/Microsoft.TemplateEngine.JsonCli.dll --require <path to extension>/resources/dotnetTemplates/itemTemplates-beta.nupkg --require <path to extension>/resources/dotnetTemplates/projectTemplates-beta.nupkg --operation create --identity Azure.Function.CSharp.TimerTrigger.2.x --arg:Schedule 0 */5 * * * * --arg:name TimerTriggerCSharp --arg:namespace Company.Function
|
||||
```
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
interface IResources {
|
||||
en: { [key: string]: string };
|
||||
}
|
||||
|
||||
export class Resources {
|
||||
private _resources: IResources;
|
||||
constructor(data: object) {
|
||||
this._resources = <IResources>data;
|
||||
}
|
||||
|
||||
public getValue(data: string): string {
|
||||
const matches: RegExpMatchArray | null = data.match(/\$(.*)/);
|
||||
|
||||
return matches !== null ? this._resources.en[matches[1]] : data;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as extract from 'extract-zip';
|
||||
import * as fse from 'fs-extra';
|
||||
import * as os from 'os';
|
||||
import * as path from 'path';
|
||||
import { ProjectRuntime } from '../constants';
|
||||
import { ext } from '../extensionVariables';
|
||||
import { downloadFile } from '../utils/fs';
|
||||
import { cliFeedJsonResponse } from '../utils/getCliFeedJson';
|
||||
import { IFunctionTemplate } from './IFunctionTemplate';
|
||||
import { parseScriptTemplates } from './parseScriptTemplates';
|
||||
import { TemplateRetriever, TemplateType } from './TemplateRetriever';
|
||||
|
||||
export class ScriptTemplateRetriever extends TemplateRetriever {
|
||||
public templateType: TemplateType = TemplateType.Script;
|
||||
private _templatesKey: string = 'FunctionTemplates';
|
||||
private _configKey: string = 'FunctionTemplateConfig';
|
||||
private _resourcesKey: string = 'FunctionTemplateResources';
|
||||
private _tempPath: string = path.join(os.tmpdir(), 'vscode-azurefunctions-templates');
|
||||
private _rawResources: object;
|
||||
private _rawTemplates: object[];
|
||||
private _rawConfig: object;
|
||||
|
||||
public getVerifiedTemplateIds(runtime: ProjectRuntime): string[] {
|
||||
return getScriptVerifiedTemplateIds(runtime);
|
||||
}
|
||||
|
||||
protected async getTemplatesFromCache(runtime: ProjectRuntime): Promise<IFunctionTemplate[] | undefined> {
|
||||
const cachedResources: object | undefined = ext.context.globalState.get<object>(this.getCacheKey(this._resourcesKey, runtime));
|
||||
const cachedTemplates: object[] | undefined = ext.context.globalState.get<object[]>(this.getCacheKey(this._templatesKey, runtime));
|
||||
const cachedConfig: object | undefined = ext.context.globalState.get<object>(this.getCacheKey(this._configKey, runtime));
|
||||
if (cachedResources && cachedTemplates && cachedConfig) {
|
||||
return parseScriptTemplates(cachedResources, cachedTemplates, cachedConfig);
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
protected async getTemplatesFromCliFeed(cliFeedJson: cliFeedJsonResponse, templateVersion: string, _runtime: ProjectRuntime): Promise<IFunctionTemplate[]> {
|
||||
try {
|
||||
const filePath: string = path.join(this._tempPath, `templates-${templateVersion}.zip`);
|
||||
await downloadFile(cliFeedJson.releases[templateVersion].templateApiZip, filePath);
|
||||
|
||||
await new Promise(async (resolve: () => void, reject: (e: Error) => void): Promise<void> => {
|
||||
// tslint:disable-next-line:no-unsafe-any
|
||||
extract(filePath, { dir: this._tempPath }, (err: Error) => {
|
||||
// tslint:disable-next-line:strict-boolean-expressions
|
||||
if (err) {
|
||||
reject(err);
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
|
||||
// only Resources.json has a capital letter
|
||||
this._rawResources = <object>await fse.readJSON(path.join(this._tempPath, 'resources', 'Resources.json'));
|
||||
this._rawTemplates = <object[]>await fse.readJSON(path.join(this._tempPath, 'templates', 'templates.json'));
|
||||
this._rawConfig = <object>await fse.readJSON(path.join(this._tempPath, 'bindings', 'bindings.json'));
|
||||
|
||||
return parseScriptTemplates(this._rawResources, this._rawTemplates, this._rawConfig);
|
||||
} finally {
|
||||
if (await fse.pathExists(this._tempPath)) {
|
||||
await fse.remove(this._tempPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected async cacheTemplatesFromCliFeed(runtime: ProjectRuntime): Promise<void> {
|
||||
ext.context.globalState.update(this.getCacheKey(this._templatesKey, runtime), this._rawTemplates);
|
||||
ext.context.globalState.update(this.getCacheKey(this._configKey, runtime), this._rawConfig);
|
||||
ext.context.globalState.update(this.getCacheKey(this._resourcesKey, runtime), this._rawResources);
|
||||
}
|
||||
}
|
||||
|
||||
export function getScriptVerifiedTemplateIds(runtime: string): string[] {
|
||||
let verifiedTemplateIds: string[] = [
|
||||
'BlobTrigger-JavaScript',
|
||||
'HttpTrigger-JavaScript',
|
||||
'QueueTrigger-JavaScript',
|
||||
'TimerTrigger-JavaScript'
|
||||
];
|
||||
|
||||
if (runtime === ProjectRuntime.one) {
|
||||
verifiedTemplateIds = verifiedTemplateIds.concat([
|
||||
'GenericWebHook-JavaScript',
|
||||
'GitHubWebHook-JavaScript',
|
||||
'HttpTriggerWithParameters-JavaScript',
|
||||
'ManualTrigger-JavaScript'
|
||||
]);
|
||||
}
|
||||
|
||||
return verifiedTemplateIds;
|
||||
}
|
|
@ -1,68 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ProjectLanguage } from '../constants';
|
||||
import { FunctionConfig } from '../FunctionConfig';
|
||||
import { Resources } from './Resources';
|
||||
|
||||
interface ITemplate {
|
||||
id: string;
|
||||
// tslint:disable-next-line:no-reserved-keywords
|
||||
function: {};
|
||||
metadata: ITemplateMetadata;
|
||||
files: { [filename: string]: string };
|
||||
}
|
||||
|
||||
interface ITemplateMetadata {
|
||||
defaultFunctionName: string;
|
||||
name: string;
|
||||
language: ProjectLanguage;
|
||||
userPrompt?: string[];
|
||||
category: TemplateCategory[];
|
||||
}
|
||||
|
||||
export enum TemplateCategory {
|
||||
Core = '$temp_category_core'
|
||||
}
|
||||
|
||||
export class Template {
|
||||
public readonly functionConfig: FunctionConfig;
|
||||
|
||||
private _template: ITemplate;
|
||||
private _resources: Resources;
|
||||
constructor(template: object, resources: Resources) {
|
||||
this._template = <ITemplate>template;
|
||||
this._resources = resources;
|
||||
this.functionConfig = new FunctionConfig(this._template.function);
|
||||
}
|
||||
|
||||
public get id(): string {
|
||||
return this._template.id;
|
||||
}
|
||||
|
||||
public get name(): string {
|
||||
return this._resources.getValue(this._template.metadata.name);
|
||||
}
|
||||
|
||||
public get defaultFunctionName(): string {
|
||||
return this._template.metadata.defaultFunctionName;
|
||||
}
|
||||
|
||||
public get language(): ProjectLanguage {
|
||||
return this._template.metadata.language;
|
||||
}
|
||||
|
||||
public isCategory(category: TemplateCategory): boolean {
|
||||
return this._template.metadata.category.find((c: TemplateCategory) => c === category) !== undefined;
|
||||
}
|
||||
|
||||
public get userPromptedSettings(): string[] {
|
||||
return this._template.metadata.userPrompt ? this._template.metadata.userPrompt : [];
|
||||
}
|
||||
|
||||
public get templateFiles(): { [filename: string]: string } {
|
||||
return this._template.files;
|
||||
}
|
||||
}
|
|
@ -1,323 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as extract from 'extract-zip';
|
||||
import * as fse from 'fs-extra';
|
||||
import * as os from 'os';
|
||||
import * as path from 'path';
|
||||
import * as vscode from 'vscode';
|
||||
import { callWithTelemetryAndErrorHandling, IActionContext, parseError } from 'vscode-azureextensionui';
|
||||
import { betaReleaseVersion, ProjectLanguage, ProjectRuntime, TemplateFilter, templateVersionSetting, v1ReleaseVersion } from '../constants';
|
||||
import { ext } from '../extensionVariables';
|
||||
import { localize } from '../localize';
|
||||
import { getFuncExtensionSetting, updateGlobalSetting } from '../ProjectSettings';
|
||||
import { downloadFile } from '../utils/fs';
|
||||
import { cliFeedJsonResponse, getFeedRuntime, tryGetCliFeedJson } from '../utils/getCliFeedJson';
|
||||
import { Config } from './Config';
|
||||
import { ConfigBinding } from './ConfigBinding';
|
||||
import { ConfigSetting } from './ConfigSetting';
|
||||
import { Resources } from './Resources';
|
||||
import { Template, TemplateCategory } from './Template';
|
||||
|
||||
export type parsedTemplates = [Template[], Config];
|
||||
const templatesKey: string = 'FunctionTemplates';
|
||||
const configKey: string = 'FunctionTemplateConfig';
|
||||
const resourcesKey: string = 'FunctionTemplateResources';
|
||||
const templateVersionKey: string = 'templateVersion';
|
||||
const tempPath: string = path.join(os.tmpdir(), 'vscode-azurefunctions-templates');
|
||||
|
||||
const verifiedTemplates: string[] = [
|
||||
'BlobTrigger-JavaScript',
|
||||
'GenericWebHook-JavaScript',
|
||||
'GitHubWebHook-JavaScript',
|
||||
'HttpTrigger-JavaScript',
|
||||
'HttpTriggerWithParameters-JavaScript',
|
||||
'ManualTrigger-JavaScript',
|
||||
'QueueTrigger-JavaScript',
|
||||
'TimerTrigger-JavaScript'
|
||||
];
|
||||
|
||||
const verifiedCSharpTemplates: string[] = [
|
||||
'HttpTrigger-CSharp',
|
||||
'BlobTrigger-CSharp',
|
||||
'QueueTrigger-CSharp',
|
||||
'TimerTrigger-CSharp'
|
||||
];
|
||||
|
||||
const verifiedJavaTemplates: string[] = [
|
||||
'HttpTrigger',
|
||||
'BlobTrigger',
|
||||
'QueueTrigger',
|
||||
'TimerTrigger'
|
||||
];
|
||||
/**
|
||||
* Main container for all template data retrieved from the Azure Functions Portal. See README.md for more info and example of the schema.
|
||||
* We cache the template data retrieved from the portal so that the user can create functions offline.
|
||||
*/
|
||||
export class TemplateData {
|
||||
private readonly _templatesMap: { [runtime: string]: Template[] | undefined } = {};
|
||||
private readonly _configMap: { [runtime: string]: Config | undefined } = {};
|
||||
// if there are no templates, then there is likely no internet or a problem with the clifeed url
|
||||
private readonly _noInternetErrMsg: string = localize('retryInternet', 'There was an error in retrieving the templates. Recheck your internet connection and try again.');
|
||||
constructor(templatesMap: { [runtime: string]: Template[] | undefined }, configMap: { [runtime: string]: Config | undefined }) {
|
||||
this._templatesMap = templatesMap;
|
||||
this._configMap = configMap;
|
||||
}
|
||||
|
||||
public async getTemplates(language: string, runtime: string = ProjectRuntime.one, templateFilter?: string): Promise<Template[]> {
|
||||
const templates: Template[] | undefined = this._templatesMap[runtime];
|
||||
if (!templates) {
|
||||
throw new Error(this._noInternetErrMsg);
|
||||
}
|
||||
|
||||
if (language === ProjectLanguage.Java) {
|
||||
// Currently we leverage JS templates to get the function metadata of Java Functions.
|
||||
// Will refactor the code here when templates HTTP API is ready.
|
||||
// See issue here: https://github.com/Microsoft/vscode-azurefunctions/issues/84
|
||||
const javaTemplates: Template[] = templates.filter((t: Template) => t.language === ProjectLanguage.JavaScript);
|
||||
return javaTemplates.filter((t: Template) => verifiedJavaTemplates.find((vt: string) => vt === removeLanguageFromId(t.id)));
|
||||
} else if (language === ProjectLanguage.CSharp) {
|
||||
// https://github.com/Microsoft/vscode-azurefunctions/issues/179
|
||||
return templates.filter((t: Template) => verifiedCSharpTemplates.some((id: string) => id === t.id));
|
||||
} else {
|
||||
switch (language) {
|
||||
case ProjectLanguage.CSharpScript:
|
||||
case ProjectLanguage.FSharpScript:
|
||||
// The functions portal only supports script languages, so it doesn't have the notion of 'C#' vs 'C#Script'
|
||||
language = language.replace('Script', '');
|
||||
break;
|
||||
default:
|
||||
}
|
||||
|
||||
let filterTemplates: Template[] = templates.filter((t: Template) => t.language.toLowerCase() === language.toLowerCase());
|
||||
switch (templateFilter) {
|
||||
case TemplateFilter.All:
|
||||
break;
|
||||
case TemplateFilter.Core:
|
||||
filterTemplates = filterTemplates.filter((t: Template) => t.isCategory(TemplateCategory.Core));
|
||||
break;
|
||||
case TemplateFilter.Verified:
|
||||
default:
|
||||
filterTemplates = filterTemplates.filter((t: Template) => verifiedTemplates.find((vt: string) => vt === t.id));
|
||||
}
|
||||
|
||||
return filterTemplates;
|
||||
}
|
||||
}
|
||||
|
||||
public async getSetting(runtime: ProjectRuntime, bindingType: string, settingName: string): Promise<ConfigSetting | undefined> {
|
||||
const config: Config | undefined = this._configMap[runtime];
|
||||
if (!config) {
|
||||
throw new Error(this._noInternetErrMsg);
|
||||
}
|
||||
const binding: ConfigBinding | undefined = config.bindings.find((b: ConfigBinding) => b.bindingType === bindingType);
|
||||
if (binding) {
|
||||
return binding.settings.find((bs: ConfigSetting) => bs.name === settingName);
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function verifyTemplatesByRuntime(templates: Template[], runtime: ProjectRuntime): void {
|
||||
if (runtime === ProjectRuntime.one) {
|
||||
for (const verifiedTemplateId of verifiedTemplates) {
|
||||
if (!templates.some((t: Template) => t.id === verifiedTemplateId)) {
|
||||
throw new Error(localize('failedToFindJavaScriptTemplate', 'Failed to find verified template with id "{0}".', verifiedTemplateId));
|
||||
}
|
||||
}
|
||||
|
||||
for (const verifiedTemplateId of verifiedCSharpTemplates) {
|
||||
if (!templates.some((t: Template) => t.id === verifiedTemplateId)) {
|
||||
throw new Error(localize('failedToFindCSharpTemplate', 'Failed to find verified template with id "{0}".', verifiedTemplateId));
|
||||
}
|
||||
}
|
||||
} else if (runtime === ProjectRuntime.beta) {
|
||||
for (const verifiedTemplateId of verifiedCSharpTemplates) {
|
||||
if (!templates.some((t: Template) => t.id === verifiedTemplateId)) {
|
||||
throw new Error(localize('failedToFindCSharpTemplate', 'Failed to find verified template with id "{0}".', verifiedTemplateId));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export async function getTemplateData(globalState?: vscode.Memento): Promise<TemplateData> {
|
||||
const templatesMap: { [runtime: string]: Template[] | undefined } = {};
|
||||
const configMap: { [runtime: string]: Config | undefined } = {};
|
||||
const cliFeedJson: cliFeedJsonResponse | undefined = await tryGetCliFeedJson();
|
||||
for (const key of Object.keys(ProjectRuntime)) {
|
||||
await callWithTelemetryAndErrorHandling('azureFunctions.getTemplateData', async function (this: IActionContext): Promise<void> {
|
||||
this.suppressErrorDisplay = true;
|
||||
this.properties.isActivationEvent = 'true';
|
||||
const runtime: ProjectRuntime = <ProjectRuntime>ProjectRuntime[key];
|
||||
this.properties.runtime = runtime;
|
||||
const templateVersion: string | undefined = await tryGetTemplateVersionSetting(this, cliFeedJson, runtime);
|
||||
let parsedTemplatesByRuntime: parsedTemplates | undefined;
|
||||
|
||||
// 1. Use the cached templates if they match templateVersion
|
||||
if (globalState && globalState.get(`${templateVersionKey}-${runtime}`) === templateVersion) {
|
||||
parsedTemplatesByRuntime = await tryGetParsedTemplateDataFromCache(this, runtime, globalState);
|
||||
this.properties.templateSource = 'matchingCache';
|
||||
}
|
||||
|
||||
// 2. Download templates from the cli-feed if the cache doesn't match templateVersion
|
||||
if (!parsedTemplatesByRuntime && cliFeedJson && templateVersion) {
|
||||
parsedTemplatesByRuntime = await tryGetParsedTemplateDataFromCliFeed(this, cliFeedJson, templateVersion, runtime, globalState);
|
||||
this.properties.templateSource = 'cliFeed';
|
||||
}
|
||||
|
||||
// 3. Use the cached templates, even if they don't match templateVersion
|
||||
if (!parsedTemplatesByRuntime && globalState) {
|
||||
parsedTemplatesByRuntime = await tryGetParsedTemplateDataFromCache(this, runtime, globalState);
|
||||
this.properties.templateSource = 'mismatchCache';
|
||||
}
|
||||
|
||||
// 4. Download templates from the cli-feed using the backupVersion
|
||||
if (!parsedTemplatesByRuntime && cliFeedJson) {
|
||||
const backupVersion: string = runtime === ProjectRuntime.one ? v1ReleaseVersion : betaReleaseVersion;
|
||||
parsedTemplatesByRuntime = await tryGetParsedTemplateDataFromCliFeed(this, cliFeedJson, backupVersion, runtime, globalState);
|
||||
this.properties.templateSource = 'backupCliFeed';
|
||||
}
|
||||
|
||||
if (parsedTemplatesByRuntime) {
|
||||
[templatesMap[runtime], configMap[runtime]] = parsedTemplatesByRuntime;
|
||||
} else {
|
||||
// Failed to get templates for this runtime
|
||||
this.properties.templateSource = 'None';
|
||||
}
|
||||
});
|
||||
}
|
||||
return new TemplateData(templatesMap, configMap);
|
||||
}
|
||||
|
||||
async function tryGetParsedTemplateDataFromCache(context: IActionContext, runtime: ProjectRuntime, globalState: vscode.Memento): Promise<parsedTemplates | undefined> {
|
||||
try {
|
||||
const cachedResources: object | undefined = globalState.get<object>(getRuntimeKey(resourcesKey, runtime));
|
||||
const cachedTemplates: object[] | undefined = globalState.get<object[]>(getRuntimeKey(templatesKey, runtime));
|
||||
const cachedConfig: object | undefined = globalState.get<object>(getRuntimeKey(configKey, runtime));
|
||||
if (cachedResources && cachedTemplates && cachedConfig) {
|
||||
return parseTemplates(cachedResources, cachedTemplates, cachedConfig);
|
||||
}
|
||||
} catch (error) {
|
||||
context.properties.cacheError = parseError(error).message;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
async function tryGetParsedTemplateDataFromCliFeed(context: IActionContext, cliFeedJson: cliFeedJsonResponse, templateVersion: string, runtime: ProjectRuntime, globalState?: vscode.Memento): Promise<parsedTemplates | undefined> {
|
||||
try {
|
||||
context.properties.templateVersion = templateVersion;
|
||||
await downloadAndExtractTemplates(cliFeedJson.releases[templateVersion].templateApiZip, templateVersion);
|
||||
// only Resources.json has a capital letter
|
||||
const rawResources: object = <object>await fse.readJSON(path.join(tempPath, 'resources', 'Resources.json'));
|
||||
const rawTemplates: object[] = <object[]>await fse.readJSON(path.join(tempPath, 'templates', 'templates.json'));
|
||||
const rawConfig: object = <object>await fse.readJSON(path.join(tempPath, 'bindings', 'bindings.json'));
|
||||
|
||||
const parsedTemplatesByRuntime: parsedTemplates = parseTemplates(rawResources, rawTemplates, rawConfig);
|
||||
verifyTemplatesByRuntime(parsedTemplatesByRuntime[0], runtime);
|
||||
if (globalState) {
|
||||
globalState.update(`${templateVersionKey}-${runtime}`, templateVersion);
|
||||
globalState.update(getRuntimeKey(templatesKey, runtime), rawTemplates);
|
||||
globalState.update(getRuntimeKey(configKey, runtime), rawConfig);
|
||||
globalState.update(getRuntimeKey(resourcesKey, runtime), rawResources);
|
||||
}
|
||||
return parsedTemplatesByRuntime;
|
||||
|
||||
} catch (error) {
|
||||
context.properties.cliFeedError = parseError(error).message;
|
||||
return undefined;
|
||||
} finally {
|
||||
if (await fse.pathExists(tempPath)) {
|
||||
await fse.remove(tempPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getRuntimeKey(baseKey: string, runtime: ProjectRuntime): string {
|
||||
return runtime === ProjectRuntime.one ? baseKey : `${baseKey}.${runtime}`;
|
||||
}
|
||||
|
||||
function parseTemplates(rawResources: object, rawTemplates: object[], rawConfig: object): parsedTemplates {
|
||||
const resources: Resources = new Resources(rawResources);
|
||||
const templates: Template[] = [];
|
||||
for (const rawTemplate of rawTemplates) {
|
||||
try {
|
||||
templates.push(new Template(rawTemplate, resources));
|
||||
} catch (error) {
|
||||
// Ignore errors so that a single poorly formed template does not affect other templates
|
||||
}
|
||||
}
|
||||
return [templates, new Config(rawConfig, resources)];
|
||||
}
|
||||
|
||||
export function removeLanguageFromId(id: string): string {
|
||||
return id.split('-')[0];
|
||||
}
|
||||
|
||||
async function downloadAndExtractTemplates(templateUrl: string, release: string): Promise<{}> {
|
||||
const filePath: string = path.join(tempPath, `templates-${release}.zip`);
|
||||
ext.outputChannel.appendLine(localize('downloadTemplates', 'Downloading "v{0}" templates zip file. . .', release));
|
||||
await fse.ensureDir(tempPath);
|
||||
await downloadFile(templateUrl, filePath);
|
||||
|
||||
return new Promise(async (resolve: () => void, reject: (e: Error) => void): Promise<void> => {
|
||||
// tslint:disable-next-line:no-unsafe-any
|
||||
extract(filePath, { dir: tempPath }, (err: Error) => {
|
||||
// tslint:disable-next-line:strict-boolean-expressions
|
||||
if (err) {
|
||||
reject(err);
|
||||
}
|
||||
ext.outputChannel.appendLine(localize('templatesExtracted', 'Template files extracted.'));
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export async function tryGetTemplateVersionSetting(context: IActionContext, cliFeedJson: cliFeedJsonResponse | undefined, runtime: ProjectRuntime): Promise<string | undefined> {
|
||||
const feedRuntime: string = getFeedRuntime(runtime);
|
||||
const userTemplateVersion: string | undefined = getFuncExtensionSetting(templateVersionSetting);
|
||||
try {
|
||||
if (userTemplateVersion) {
|
||||
context.properties.userTemplateVersion = userTemplateVersion;
|
||||
}
|
||||
let templateVersion: string;
|
||||
if (cliFeedJson) {
|
||||
templateVersion = userTemplateVersion ? userTemplateVersion : cliFeedJson.tags[feedRuntime].release;
|
||||
// tslint:disable-next-line:strict-boolean-expressions
|
||||
if (!cliFeedJson.releases[templateVersion]) {
|
||||
const invalidVersion: string = localize('invalidTemplateVersion', 'Failed to retrieve Azure Functions templates for version "{0}".', templateVersion);
|
||||
const selectVersion: vscode.MessageItem = { title: localize('selectVersion', 'Select version') };
|
||||
const useLatest: vscode.MessageItem = { title: localize('useLatest', 'Use latest') };
|
||||
const warningInput: vscode.MessageItem = await ext.ui.showWarningMessage(invalidVersion, selectVersion, useLatest);
|
||||
if (warningInput === selectVersion) {
|
||||
const releaseQuickPicks: vscode.QuickPickItem[] = [];
|
||||
for (const rel of Object.keys(cliFeedJson.releases)) {
|
||||
releaseQuickPicks.push({
|
||||
label: rel,
|
||||
description: ''
|
||||
});
|
||||
}
|
||||
const input: vscode.QuickPickItem | undefined = await ext.ui.showQuickPick(releaseQuickPicks, { placeHolder: invalidVersion });
|
||||
templateVersion = input.label;
|
||||
await updateGlobalSetting(templateVersionSetting, input.label);
|
||||
} else {
|
||||
templateVersion = cliFeedJson.tags[feedRuntime].release;
|
||||
// reset user setting so that it always gets latest
|
||||
await updateGlobalSetting(templateVersionSetting, '');
|
||||
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return templateVersion;
|
||||
} catch (error) {
|
||||
// if cliJson does not have the template version being searched for, it will throw an error
|
||||
context.properties.userTemplateVersion = parseError(error).message;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IActionContext, parseError } from 'vscode-azureextensionui';
|
||||
import { ProjectRuntime } from '../constants';
|
||||
import { ext } from '../extensionVariables';
|
||||
import { localize } from '../localize';
|
||||
import { cliFeedJsonResponse } from '../utils/getCliFeedJson';
|
||||
import { IFunctionTemplate } from './IFunctionTemplate';
|
||||
|
||||
export enum TemplateType {
|
||||
Script = 'Script',
|
||||
Dotnet = '.NET'
|
||||
}
|
||||
|
||||
export abstract class TemplateRetriever {
|
||||
public static templateVersionKey: string = 'templateVersion';
|
||||
public abstract templateType: TemplateType;
|
||||
|
||||
public async tryGetTemplatesFromCache(context: IActionContext, runtime: ProjectRuntime): Promise<IFunctionTemplate[] | undefined> {
|
||||
try {
|
||||
return await this.getTemplatesFromCache(runtime);
|
||||
} catch (error) {
|
||||
const errorMessage: string = parseError(error).message;
|
||||
ext.outputChannel.appendLine(errorMessage);
|
||||
context.properties.cacheError = errorMessage;
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
public async tryGetTemplatesFromCliFeed(context: IActionContext, cliFeedJson: cliFeedJsonResponse, templateVersion: string, runtime: ProjectRuntime): Promise<IFunctionTemplate[] | undefined> {
|
||||
try {
|
||||
context.properties.templateVersion = templateVersion;
|
||||
ext.outputChannel.appendLine(localize('updatingTemplates', 'Updating {0} templates for runtime "{1}" to version "{2}"...', this.templateType, runtime, templateVersion));
|
||||
const templates: IFunctionTemplate[] = await this.getTemplatesFromCliFeed(cliFeedJson, templateVersion, runtime);
|
||||
await this.verifyTemplates(templates, runtime);
|
||||
ext.context.globalState.update(this.getCacheKey(TemplateRetriever.templateVersionKey, runtime), templateVersion);
|
||||
await this.cacheTemplatesFromCliFeed(runtime);
|
||||
ext.outputChannel.appendLine(localize('updatedTemplates', 'Successfully updated templates.'));
|
||||
return templates;
|
||||
} catch (error) {
|
||||
const errorMessage: string = parseError(error).message;
|
||||
ext.outputChannel.appendLine(errorMessage);
|
||||
context.properties.cliFeedError = errorMessage;
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds runtime and templateType information to a key to ensure there are no collisions in the cache
|
||||
* For backwards compatability, the original runtime and templateType will not have this information
|
||||
*/
|
||||
public getCacheKey(key: string, runtime: ProjectRuntime): string {
|
||||
if (runtime !== ProjectRuntime.one) {
|
||||
key = `${key}.${runtime}`;
|
||||
}
|
||||
|
||||
if (this.templateType !== TemplateType.Script) {
|
||||
key = `${key}.${this.templateType}`;
|
||||
}
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
protected abstract getTemplatesFromCache(runtime: ProjectRuntime): Promise<IFunctionTemplate[] | undefined>;
|
||||
protected abstract getTemplatesFromCliFeed(cliFeedJson: cliFeedJsonResponse, templateVersion: string, runtime: ProjectRuntime): Promise<IFunctionTemplate[]>;
|
||||
protected abstract cacheTemplatesFromCliFeed(runtime: ProjectRuntime): Promise<void>;
|
||||
protected abstract getVerifiedTemplateIds(runtime: ProjectRuntime): string[];
|
||||
|
||||
private async verifyTemplates(templates: IFunctionTemplate[], runtime: ProjectRuntime): Promise<void> {
|
||||
const verifiedTemplateIds: string[] = this.getVerifiedTemplateIds(runtime);
|
||||
|
||||
for (const verifiedTemplateId of verifiedTemplateIds) {
|
||||
if (!templates.some((t: IFunctionTemplate) => t.id === verifiedTemplateId)) {
|
||||
throw new Error(localize('failedToVerifiedTemplate', 'Failed to find verified template with id "{0}".', verifiedTemplateId));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as path from 'path';
|
||||
import { ProjectRuntime } from '../constants';
|
||||
import { ext } from "../extensionVariables";
|
||||
import { cpUtils } from "../utils/cpUtils";
|
||||
|
||||
export async function executeDotnetTemplateCommand(runtime: ProjectRuntime, workingDirectory: string | undefined, operation: 'list' | 'create', ...args: string[]): Promise<string> {
|
||||
const jsonDllPath: string = ext.context.asAbsolutePath(path.join('resources', 'dotnetJsonCli', 'Microsoft.TemplateEngine.JsonCli.dll'));
|
||||
return await cpUtils.executeCommand(undefined, workingDirectory, 'dotnet', jsonDllPath, '--require', getDotnetItemTemplatePath(runtime), '--require', getDotnetProjectTemplatePath(runtime), '--operation', operation, ...args);
|
||||
}
|
||||
|
||||
export function getDotnetTemplatesPath(): string {
|
||||
return ext.context.asAbsolutePath(path.join('resources', 'dotnetTemplates'));
|
||||
}
|
||||
|
||||
export function getDotnetItemTemplatePath(runtime: ProjectRuntime): string {
|
||||
return path.join(getDotnetTemplatesPath(), `itemTemplates-${runtime}.nupkg`);
|
||||
}
|
||||
|
||||
export function getDotnetProjectTemplatePath(runtime: ProjectRuntime): string {
|
||||
return path.join(getDotnetTemplatesPath(), `projectTemplates-${runtime}.nupkg`);
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ProjectLanguage, ProjectRuntime } from '../constants';
|
||||
import { IFunctionSetting, ValueType } from './IFunctionSetting';
|
||||
import { IFunctionTemplate, TemplateCategory } from './IFunctionTemplate';
|
||||
|
||||
/**
|
||||
* Describes a dotnet template before it has been parsed
|
||||
*/
|
||||
interface IRawTemplate {
|
||||
DefaultName: string;
|
||||
Name: string;
|
||||
Identity: string;
|
||||
Parameters: {}[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Describes a dotnet template setting before it has been parsed
|
||||
*/
|
||||
interface IRawSetting {
|
||||
Documentation: string | undefined;
|
||||
Name: string;
|
||||
DefaultValue: string | undefined;
|
||||
DataType: string | undefined;
|
||||
Choices: {
|
||||
[key: string]: string;
|
||||
} | undefined;
|
||||
}
|
||||
|
||||
function parseDotnetSetting(rawSetting: IRawSetting): IFunctionSetting {
|
||||
return {
|
||||
name: rawSetting.Name,
|
||||
resourceType: undefined, // Dotnet templates do not give us resourceType information
|
||||
valueType: rawSetting.DataType === 'choice' ? ValueType.enum : ValueType.string,
|
||||
defaultValue: rawSetting.DefaultValue,
|
||||
label: rawSetting.Name,
|
||||
enums: rawSetting.Choices ? Object.keys(rawSetting.Choices).map((key: string) => { return { value: key, displayName: key }; }) : [],
|
||||
validateSetting: (): undefined => { return undefined; } // Dotnet templates do not give us validation information
|
||||
};
|
||||
}
|
||||
|
||||
function parseDotnetTemplate(rawTemplate: IRawTemplate): IFunctionTemplate {
|
||||
const userPromptedSettings: IFunctionSetting[] = [];
|
||||
for (const rawSetting of rawTemplate.Parameters) {
|
||||
const setting: IFunctionSetting = parseDotnetSetting(<IRawSetting>rawSetting);
|
||||
// Exclude some of the default parameters like 'name' and 'namespace' that apply for every function and are handled separately
|
||||
if (!/^(name|namespace|type|language)$/i.test(setting.name)) {
|
||||
userPromptedSettings.push(setting);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
isHttpTrigger: rawTemplate.Name.toLowerCase().startsWith('http') || rawTemplate.Name.toLowerCase().endsWith('webhook'),
|
||||
id: rawTemplate.Identity,
|
||||
name: rawTemplate.Name,
|
||||
defaultFunctionName: rawTemplate.DefaultName,
|
||||
language: ProjectLanguage.CSharp,
|
||||
userPromptedSettings: userPromptedSettings,
|
||||
categories: [TemplateCategory.Core] // Dotnet templates do not have category information, so display all templates as if they are in the 'core' category
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses templates used by the .NET CLI
|
||||
* This basically converts the 'raw' templates in the externally defined JSON format to a common and understood format (IFunctionTemplate) used by this extension
|
||||
*/
|
||||
export function parseDotnetTemplates(rawTemplates: object[], runtime: ProjectRuntime): IFunctionTemplate[] {
|
||||
const templates: IFunctionTemplate[] = [];
|
||||
for (const rawTemplate of rawTemplates) {
|
||||
try {
|
||||
const template: IFunctionTemplate = parseDotnetTemplate(<IRawTemplate>rawTemplate);
|
||||
if (template.id.startsWith('Azure.Function.CSharp.') &&
|
||||
((runtime === ProjectRuntime.one && template.id.includes('1')) || (runtime === ProjectRuntime.beta && template.id.includes('2')))) {
|
||||
templates.push(template);
|
||||
}
|
||||
} catch (error) {
|
||||
// Ignore errors so that a single poorly formed template does not affect other templates
|
||||
}
|
||||
}
|
||||
return templates;
|
||||
}
|
|
@ -0,0 +1,195 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { isString } from 'util';
|
||||
import { ProjectLanguage } from '../constants';
|
||||
import { FunctionConfig } from '../FunctionConfig';
|
||||
import { IEnumValue, IFunctionSetting, ResourceType, ValueType } from './IFunctionSetting';
|
||||
import { IFunctionTemplate, TemplateCategory } from './IFunctionTemplate';
|
||||
|
||||
/**
|
||||
* Describes a script template before it has been parsed
|
||||
*/
|
||||
interface IRawTemplate {
|
||||
id: string;
|
||||
// tslint:disable-next-line:no-reserved-keywords
|
||||
function: {};
|
||||
metadata: {
|
||||
defaultFunctionName: string;
|
||||
name: string;
|
||||
language: ProjectLanguage;
|
||||
userPrompt?: string[];
|
||||
category: TemplateCategory[];
|
||||
};
|
||||
files: { [filename: string]: string };
|
||||
}
|
||||
|
||||
/**
|
||||
* Describes a script template setting before it has been parsed
|
||||
*/
|
||||
interface IRawSetting {
|
||||
name: string;
|
||||
value: ValueType;
|
||||
label: string;
|
||||
defaultValue?: string;
|
||||
required: boolean;
|
||||
resource?: ResourceType;
|
||||
validators?: {
|
||||
expression: string;
|
||||
errorText: string;
|
||||
}[];
|
||||
// tslint:disable-next-line:no-reserved-keywords
|
||||
enum?: {
|
||||
value: string;
|
||||
display: string;
|
||||
}[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Describes script template config to be used for parsing
|
||||
*/
|
||||
interface IConfig {
|
||||
variables: IVariables;
|
||||
bindings: {
|
||||
// tslint:disable-next-line:no-reserved-keywords
|
||||
type: string;
|
||||
settings: object[];
|
||||
}[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Describes script template variables to be used for parsing
|
||||
*/
|
||||
interface IVariables { [name: string]: string; }
|
||||
|
||||
/**
|
||||
* Describes script template resources to be used for parsing
|
||||
*/
|
||||
interface IResources { en: { [key: string]: string }; }
|
||||
|
||||
// tslint:disable-next-line:no-any
|
||||
function getVariableValue(resources: IResources, variables: IVariables, data: string): string {
|
||||
if (!isString(data)) {
|
||||
// This evaluates to a non-string value in rare cases, in which case we just return the value as-is
|
||||
return data;
|
||||
}
|
||||
|
||||
const matches: RegExpMatchArray | null = data.match(/\[variables\(\'(.*)\'\)\]/);
|
||||
data = matches !== null ? variables[matches[1]] : data;
|
||||
|
||||
return getResourceValue(resources, <string>data);
|
||||
}
|
||||
|
||||
function getResourceValue(resources: IResources, data: string): string {
|
||||
const matches: RegExpMatchArray | null = data.match(/\$(.*)/);
|
||||
return matches !== null ? resources.en[matches[1]] : data;
|
||||
}
|
||||
|
||||
function parseScriptSetting(data: object, resources: IResources, variables: IVariables): IFunctionSetting {
|
||||
const rawSetting: IRawSetting = <IRawSetting>data;
|
||||
const enums: IEnumValue[] = [];
|
||||
if (rawSetting.enum) {
|
||||
for (const ev of rawSetting.enum) {
|
||||
enums.push({
|
||||
value: getVariableValue(resources, variables, ev.value),
|
||||
displayName: getVariableValue(resources, variables, ev.display)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
name: getVariableValue(resources, variables, rawSetting.name),
|
||||
resourceType: rawSetting.resource,
|
||||
valueType: rawSetting.value,
|
||||
defaultValue: rawSetting.defaultValue ? getVariableValue(resources, variables, rawSetting.defaultValue) : undefined,
|
||||
label: getVariableValue(resources, variables, rawSetting.label),
|
||||
enums: enums,
|
||||
validateSetting: (value: string | undefined): string | undefined => {
|
||||
if (rawSetting.validators) {
|
||||
for (const validator of rawSetting.validators) {
|
||||
if (!value || value.match(validator.expression) === null) {
|
||||
return getVariableValue(resources, variables, validator.errorText);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function parseScriptTemplate(rawTemplate: IRawTemplate, resources: IResources, commonSettings: IConfig): IScriptFunctionTemplate {
|
||||
const commonSettingsMap: { [inBindingType: string]: IFunctionSetting[] | undefined } = {};
|
||||
for (const binding of commonSettings.bindings) {
|
||||
commonSettingsMap[binding.type] = binding.settings.map((setting: object) => parseScriptSetting(setting, resources, commonSettings.variables));
|
||||
}
|
||||
|
||||
const functionConfig: FunctionConfig = new FunctionConfig(rawTemplate.function);
|
||||
|
||||
let language: ProjectLanguage = rawTemplate.metadata.language;
|
||||
// The templateApiZip only supports script languages, and thus incorrectly defines 'C#Script' as 'C#', etc.
|
||||
switch (language) {
|
||||
case ProjectLanguage.CSharp:
|
||||
language = ProjectLanguage.CSharpScript;
|
||||
break;
|
||||
case ProjectLanguage.FSharp:
|
||||
language = ProjectLanguage.FSharpScript;
|
||||
break;
|
||||
default:
|
||||
}
|
||||
|
||||
const userPromptedSettings: IFunctionSetting[] = [];
|
||||
if (rawTemplate.metadata.userPrompt) {
|
||||
for (const settingName of rawTemplate.metadata.userPrompt) {
|
||||
const settings: IFunctionSetting[] | undefined = commonSettingsMap[functionConfig.inBindingType];
|
||||
if (settings) {
|
||||
const setting: IFunctionSetting | undefined = settings.find((bs: IFunctionSetting) => bs.name === settingName);
|
||||
if (setting) {
|
||||
const functionSpecificDefaultValue: string | undefined = functionConfig.inBinding[setting.name];
|
||||
if (functionSpecificDefaultValue) {
|
||||
// overwrite common default value with the function-specific default value
|
||||
setting.defaultValue = functionSpecificDefaultValue;
|
||||
}
|
||||
userPromptedSettings.push(setting);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
functionConfig: functionConfig,
|
||||
isHttpTrigger: functionConfig.isHttpTrigger,
|
||||
id: rawTemplate.id,
|
||||
functionType: functionConfig.inBindingType,
|
||||
name: getResourceValue(resources, rawTemplate.metadata.name),
|
||||
defaultFunctionName: rawTemplate.metadata.defaultFunctionName,
|
||||
language: language,
|
||||
userPromptedSettings: userPromptedSettings,
|
||||
templateFiles: rawTemplate.files,
|
||||
categories: rawTemplate.metadata.category
|
||||
};
|
||||
}
|
||||
|
||||
export interface IScriptFunctionTemplate extends IFunctionTemplate {
|
||||
templateFiles: { [filename: string]: string };
|
||||
functionType: string;
|
||||
functionConfig: FunctionConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses templates contained in the templateApiZip of the functions cli feed. This contains all 'script' templates, including JavaScript, C#Script, Python, etc.
|
||||
* This basically converts the 'raw' templates in the externally defined JSON format to a common and understood format (IFunctionTemplate) used by this extension
|
||||
*/
|
||||
export function parseScriptTemplates(rawResources: object, rawTemplates: object[], rawConfig: object): IFunctionTemplate[] {
|
||||
const templates: IFunctionTemplate[] = [];
|
||||
for (const rawTemplate of rawTemplates) {
|
||||
try {
|
||||
templates.push(parseScriptTemplate(<IRawTemplate>rawTemplate, <IResources>rawResources, <IConfig>rawConfig));
|
||||
} catch (error) {
|
||||
// Ignore errors so that a single poorly formed template does not affect other templates
|
||||
}
|
||||
}
|
||||
return templates;
|
||||
}
|
|
@ -14,7 +14,7 @@ import { addExtensionUserAgent, AzureTreeDataProvider, AzureWizard, IActionConte
|
|||
import { ArgumentError } from '../errors';
|
||||
import { ext } from '../extensionVariables';
|
||||
import { localize } from '../localize';
|
||||
import { getResourceTypeLabel, ResourceType } from '../templates/ConfigSetting';
|
||||
import { getResourceTypeLabel, ResourceType } from '../templates/IFunctionSetting';
|
||||
|
||||
function parseResourceId(id: string): RegExpMatchArray {
|
||||
const matches: RegExpMatchArray | null = id.match(/\/subscriptions\/(.*)\/resourceGroups\/(.*)\/providers\/(.*)\/(.*)/);
|
||||
|
|
|
@ -3,115 +3,15 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as fse from 'fs-extra';
|
||||
import * as os from 'os';
|
||||
import * as path from 'path';
|
||||
import { QuickPickOptions } from "vscode";
|
||||
import { callWithTelemetryAndErrorHandling, IActionContext, IAzureQuickPickItem } from 'vscode-azureextensionui';
|
||||
import { ProjectRuntime } from '../constants';
|
||||
import { ext } from '../extensionVariables';
|
||||
import { tryGetLocalRuntimeVersion } from '../funcCoreTools/tryGetLocalRuntimeVersion';
|
||||
import { localize } from "../localize";
|
||||
import { tryGetTemplateVersionSetting } from '../templates/TemplateData';
|
||||
import { cpUtils } from "./cpUtils";
|
||||
import * as fsUtil from './fs';
|
||||
import { cliFeedJsonResponse, getFeedRuntime, tryGetCliFeedJson } from './getCliFeedJson';
|
||||
|
||||
const projectPackageId: string = 'microsoft.azurefunctions.projecttemplates';
|
||||
const functionsPackageId: string = 'azure.functions.templates';
|
||||
const templatesKey: string = 'cSharpFunctionsTemplates';
|
||||
|
||||
async function validateDotnetInstalled(): Promise<void> {
|
||||
try {
|
||||
await cpUtils.executeCommand(undefined, undefined, 'dotnet', '--version');
|
||||
} catch (error) {
|
||||
throw new Error(localize('dotnetNotInstalled', 'You must have the .NET CLI installed to perform this operation.'));
|
||||
}
|
||||
}
|
||||
|
||||
export namespace dotnetUtils {
|
||||
export const funcProjectId: string = 'azureFunctionsProjectTemplates';
|
||||
|
||||
export async function validateTemplatesInstalled(): Promise<void> {
|
||||
await validateDotnetInstalled();
|
||||
|
||||
const listOutput: string = await cpUtils.executeCommand(undefined, undefined, 'dotnet', 'new', '--list');
|
||||
const templatesInstalled: boolean = listOutput.includes(funcProjectId) && listOutput.includes('HttpTrigger');
|
||||
|
||||
export async function validateDotnetInstalled(): Promise<void> {
|
||||
try {
|
||||
await callWithTelemetryAndErrorHandling('azureFunctions.validateDotnetTemplatesInstalled', async function (this: IActionContext): Promise<void> {
|
||||
this.rethrowError = true;
|
||||
this.suppressErrorDisplay = true;
|
||||
this.properties.templatesInstalled = String(templatesInstalled);
|
||||
|
||||
const templatesVersion: string | undefined = templatesInstalled ? ext.context.globalState.get(templatesKey) : undefined;
|
||||
this.properties.installedVersion = <string>templatesVersion;
|
||||
const cliFeedJson: cliFeedJsonResponse | undefined = await tryGetCliFeedJson();
|
||||
if (!cliFeedJson) {
|
||||
throw new Error(localize('retryInternet', 'There was an error in retrieving the templates. Recheck your internet connection and try again.'));
|
||||
}
|
||||
|
||||
let runtime: ProjectRuntime | undefined = await tryGetLocalRuntimeVersion();
|
||||
if (runtime === undefined) {
|
||||
const picks: IAzureQuickPickItem<ProjectRuntime>[] = Object.keys(ProjectRuntime).map((key: string) => {
|
||||
const val: ProjectRuntime = <ProjectRuntime>ProjectRuntime[key];
|
||||
return {
|
||||
label: cliFeedJson.tags[getFeedRuntime(val)].displayName,
|
||||
description: '',
|
||||
data: val
|
||||
};
|
||||
});
|
||||
const options: QuickPickOptions = { placeHolder: localize('pickTemplateVersion', 'Select the template version to install') };
|
||||
runtime = (await ext.ui.showQuickPick(picks, options)).data;
|
||||
}
|
||||
|
||||
const latestRelease: string = await tryGetTemplateVersionSetting(this, cliFeedJson, runtime) || cliFeedJson.tags[getFeedRuntime(runtime)].release;
|
||||
this.properties.latestVersion = latestRelease;
|
||||
if (templatesVersion !== latestRelease) {
|
||||
ext.outputChannel.show();
|
||||
ext.outputChannel.appendLine(localize('updatingTemplates', 'Updating .NET templates for Azure Functions...'));
|
||||
if (templatesInstalled) {
|
||||
await uninstallTemplates();
|
||||
}
|
||||
|
||||
const tempFolder: string = path.join(os.tmpdir(), fsUtil.getRandomHexString());
|
||||
await fse.ensureDir(tempFolder);
|
||||
try {
|
||||
ext.outputChannel.appendLine(localize('installFuncProject', 'Installing "{0}"', projectPackageId));
|
||||
const projectTemplatePath: string = path.join(tempFolder, `${projectPackageId}.nupkg`);
|
||||
await fsUtil.downloadFile(cliFeedJson.releases[latestRelease].projectTemplates, projectTemplatePath);
|
||||
await cpUtils.executeCommand(undefined, undefined, 'dotnet', 'new', '--install', projectTemplatePath);
|
||||
|
||||
ext.outputChannel.appendLine(localize('installFuncs', 'Installing "{0}"', functionsPackageId));
|
||||
const functionsTemplatePath: string = path.join(tempFolder, `${functionsPackageId}.nupkg`);
|
||||
await fsUtil.downloadFile(cliFeedJson.releases[latestRelease].itemTemplates, functionsTemplatePath);
|
||||
await cpUtils.executeCommand(undefined, undefined, 'dotnet', 'new', '--install', functionsTemplatePath);
|
||||
|
||||
ext.context.globalState.update(templatesKey, latestRelease);
|
||||
} finally {
|
||||
await fse.remove(tempFolder);
|
||||
}
|
||||
}
|
||||
});
|
||||
await cpUtils.executeCommand(undefined, undefined, 'dotnet', '--version');
|
||||
} catch (error) {
|
||||
if (templatesInstalled) {
|
||||
// If the user already has some version of the templates installed, ignore errors and let them continue
|
||||
return;
|
||||
} else {
|
||||
throw error;
|
||||
}
|
||||
throw new Error(localize('dotnetNotInstalled', 'You must have the .NET CLI installed to perform this operation.'));
|
||||
}
|
||||
}
|
||||
|
||||
export async function uninstallTemplates(): Promise<void> {
|
||||
await validateDotnetInstalled();
|
||||
|
||||
ext.outputChannel.show();
|
||||
ext.outputChannel.appendLine(localize('uninstallFuncProject', 'Uninstalling "{0}"', projectPackageId));
|
||||
await cpUtils.executeCommand(undefined, undefined, 'dotnet', 'new', '--uninstall', projectPackageId);
|
||||
ext.outputChannel.appendLine(localize('uninstallFuncs', 'Uninstalling "{0}"', functionsPackageId));
|
||||
await cpUtils.executeCommand(undefined, undefined, 'dotnet', 'new', '--uninstall', functionsPackageId);
|
||||
ext.outputChannel.appendLine(localize('finishedUninstallingTemplates', 'Finished uninstalling Azure Functions templates.'));
|
||||
ext.context.globalState.update(templatesKey, undefined);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -108,6 +108,7 @@ export async function downloadFile(url: string, filePath: string): Promise<void>
|
|||
uri: url
|
||||
};
|
||||
|
||||
await fse.ensureDir(path.dirname(filePath));
|
||||
request(templateOptions, (err: Error) => {
|
||||
// tslint:disable-next-line:strict-boolean-expressions
|
||||
if (err) {
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
// tslint:disable:typedef
|
||||
// tslint:disable:strict-boolean-expressions
|
||||
|
||||
import * as path from 'path';
|
||||
import { ExtensionContext, Memento } from 'vscode';
|
||||
|
||||
class TestMemento implements Memento {
|
||||
|
@ -31,7 +32,7 @@ export class TestExtensionContext implements ExtensionContext {
|
|||
constructor() {
|
||||
this.globalState = new TestMemento();
|
||||
}
|
||||
public asAbsolutePath(_relativePath: string): string {
|
||||
throw new Error('Method not implemented.');
|
||||
public asAbsolutePath(relativePath: string): string {
|
||||
return path.join(__dirname, '..', '..', relativePath);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,18 +14,18 @@ import { createFunction } from '../../src/commands/createFunction/createFunction
|
|||
import { ProjectLanguage, projectLanguageSetting, ProjectRuntime, projectRuntimeSetting, TemplateFilter, templateFilterSetting } from '../../src/constants';
|
||||
import { ext } from '../../src/extensionVariables';
|
||||
import { getGlobalFuncExtensionSetting, updateGlobalSetting } from '../../src/ProjectSettings';
|
||||
import { getTemplateData, TemplateData } from '../../src/templates/TemplateData';
|
||||
import { FunctionTemplates, getFunctionTemplates } from '../../src/templates/FunctionTemplates';
|
||||
import * as fsUtil from '../../src/utils/fs';
|
||||
|
||||
let backupTemplateData: TemplateData;
|
||||
let funcPortalTemplateData: TemplateData | undefined;
|
||||
let backupTemplates: FunctionTemplates;
|
||||
let latestTemplates: FunctionTemplates | undefined;
|
||||
|
||||
// tslint:disable-next-line:no-function-expression
|
||||
suiteSetup(async function (this: IHookCallbackContext): Promise<void> {
|
||||
this.timeout(30 * 1000);
|
||||
// Ensure template data is initialized before any 'Create Function' test is run
|
||||
backupTemplateData = <TemplateData>(await getTemplateData(undefined));
|
||||
funcPortalTemplateData = <TemplateData>(await getTemplateData(undefined));
|
||||
// Ensure templates are initialized before any 'Create Function' test is run
|
||||
backupTemplates = <FunctionTemplates>(await getFunctionTemplates());
|
||||
latestTemplates = <FunctionTemplates>(await getFunctionTemplates());
|
||||
// https://github.com/Microsoft/vscode-azurefunctions/issues/334
|
||||
});
|
||||
|
||||
|
@ -76,13 +76,13 @@ export abstract class FunctionTesterBase implements vscode.Disposable {
|
|||
}
|
||||
|
||||
public async testCreateFunction(templateName: string, ...inputs: (string | undefined)[]): Promise<void> {
|
||||
if (funcPortalTemplateData) {
|
||||
await this.testCreateFunctionInternal(funcPortalTemplateData, this.funcPortalTestFolder, templateName, inputs.slice());
|
||||
if (latestTemplates) {
|
||||
await this.testCreateFunctionInternal(latestTemplates, this.funcPortalTestFolder, templateName, inputs.slice());
|
||||
} else {
|
||||
assert.fail('Failed to find templates from functions portal.');
|
||||
}
|
||||
|
||||
await this.testCreateFunctionInternal(backupTemplateData, this.backupTestFolder, templateName, inputs.slice());
|
||||
await this.testCreateFunctionInternal(backupTemplates, this.backupTestFolder, templateName, inputs.slice());
|
||||
}
|
||||
|
||||
public abstract async validateFunction(testFolder: string, funcName: string): Promise<void>;
|
||||
|
@ -97,7 +97,7 @@ export abstract class FunctionTesterBase implements vscode.Disposable {
|
|||
]);
|
||||
}
|
||||
|
||||
private async testCreateFunctionInternal(templateData: TemplateData, testFolder: string, templateName: string, inputs: (string | undefined)[]): Promise<void> {
|
||||
private async testCreateFunctionInternal(templates: FunctionTemplates, testFolder: string, templateName: string, inputs: (string | undefined)[]): Promise<void> {
|
||||
// Setup common inputs
|
||||
const funcName: string = templateName.replace(/ /g, '');
|
||||
inputs.unshift(funcName); // Specify the function name
|
||||
|
@ -108,7 +108,7 @@ export abstract class FunctionTesterBase implements vscode.Disposable {
|
|||
}
|
||||
|
||||
ext.ui = new TestUserInput(inputs);
|
||||
ext.templateData = templateData;
|
||||
ext.functionTemplates = templates;
|
||||
await createFunction(<IActionContext>{ properties: {}, measurements: {} });
|
||||
assert.equal(inputs.length, 0, 'Not all inputs were used.');
|
||||
|
||||
|
|
|
@ -9,7 +9,6 @@ import { IHookCallbackContext, ISuiteCallbackContext } from 'mocha';
|
|||
import * as path from 'path';
|
||||
import * as vscode from 'vscode';
|
||||
import { ProjectLanguage, ProjectRuntime } from '../../src/constants';
|
||||
import { dotnetUtils } from '../../src/utils/dotnetUtils';
|
||||
import { FunctionTesterBase } from './FunctionTesterBase';
|
||||
|
||||
class CSharpFunctionTester extends FunctionTesterBase {
|
||||
|
@ -31,7 +30,6 @@ suite('Create C# Function Tests', async function (this: ISuiteCallbackContext):
|
|||
suiteSetup(async function (this: IHookCallbackContext): Promise<void> {
|
||||
this.timeout(120 * 1000);
|
||||
await csTester.initAsync();
|
||||
await dotnetUtils.validateTemplatesInstalled();
|
||||
});
|
||||
|
||||
// tslint:disable-next-line:no-function-expression
|
||||
|
@ -40,7 +38,7 @@ suite('Create C# Function Tests', async function (this: ISuiteCallbackContext):
|
|||
await csTester.dispose();
|
||||
});
|
||||
|
||||
const blobTrigger: string = 'Blob trigger';
|
||||
const blobTrigger: string = 'BlobTrigger';
|
||||
test(blobTrigger, async () => {
|
||||
await csTester.testCreateFunction(
|
||||
blobTrigger,
|
||||
|
@ -50,7 +48,7 @@ suite('Create C# Function Tests', async function (this: ISuiteCallbackContext):
|
|||
);
|
||||
});
|
||||
|
||||
const httpTrigger: string = 'HTTP trigger';
|
||||
const httpTrigger: string = 'HttpTrigger';
|
||||
test(httpTrigger, async () => {
|
||||
await csTester.testCreateFunction(
|
||||
httpTrigger,
|
||||
|
@ -59,7 +57,7 @@ suite('Create C# Function Tests', async function (this: ISuiteCallbackContext):
|
|||
);
|
||||
});
|
||||
|
||||
const queueTrigger: string = 'Queue trigger';
|
||||
const queueTrigger: string = 'QueueTrigger';
|
||||
test(queueTrigger, async () => {
|
||||
await csTester.testCreateFunction(
|
||||
queueTrigger,
|
||||
|
@ -69,7 +67,7 @@ suite('Create C# Function Tests', async function (this: ISuiteCallbackContext):
|
|||
);
|
||||
});
|
||||
|
||||
const timerTrigger: string = 'Timer trigger';
|
||||
const timerTrigger: string = 'TimerTrigger';
|
||||
test(timerTrigger, async () => {
|
||||
await csTester.testCreateFunction(
|
||||
timerTrigger,
|
||||
|
@ -79,11 +77,13 @@ suite('Create C# Function Tests', async function (this: ISuiteCallbackContext):
|
|||
});
|
||||
|
||||
test('createFunction API', async () => {
|
||||
const templateId: string = 'HttpTrigger-CSharp';
|
||||
// Intentionally testing IoTHub trigger since a partner team plans to use that
|
||||
const templateId: string = 'Azure.Function.CSharp.IotHubTrigger.2.x';
|
||||
const functionName: string = 'createFunctionApi';
|
||||
const namespace: string = 'Company.Function';
|
||||
const authLevel: string = 'Anonymous';
|
||||
await vscode.commands.executeCommand('azureFunctions.createFunction', csTester.funcPortalTestFolder, templateId, functionName, { namespace, authLevel });
|
||||
const iotPath: string = 'messages/events';
|
||||
const connection: string = 'IoTHub_Setting';
|
||||
await vscode.commands.executeCommand('azureFunctions.createFunction', csTester.funcPortalTestFolder, templateId, functionName, { namespace: namespace, Path: iotPath, Connection: connection });
|
||||
await csTester.validateFunction(csTester.funcPortalTestFolder, functionName);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -14,7 +14,6 @@ import { createNewProject } from '../src/commands/createNewProject/createNewProj
|
|||
import { ProjectLanguage } from '../src/constants';
|
||||
import { ext } from '../src/extensionVariables';
|
||||
import { funcToolsInstalled } from '../src/funcCoreTools/validateFuncCoreToolsInstalled';
|
||||
import { dotnetUtils } from '../src/utils/dotnetUtils';
|
||||
import * as fsUtil from '../src/utils/fs';
|
||||
import { validateVSCodeProjectFiles } from './initProjectForVSCode.test';
|
||||
|
||||
|
@ -30,7 +29,6 @@ suite('Create New Project Tests', async function (this: ISuiteCallbackContext):
|
|||
suiteSetup(async function (this: IHookCallbackContext): Promise<void> {
|
||||
this.timeout(120 * 1000);
|
||||
await fse.ensureDir(testFolderPath);
|
||||
await dotnetUtils.validateTemplatesInstalled();
|
||||
});
|
||||
|
||||
suiteTeardown(async () => {
|
||||
|
|
|
@ -6,44 +6,46 @@
|
|||
import * as assert from 'assert';
|
||||
import { IHookCallbackContext } from 'mocha';
|
||||
import { JavaProjectCreator } from '../src/commands/createNewProject/JavaProjectCreator';
|
||||
import { JavaScriptProjectCreator } from '../src/commands/createNewProject/JavaScriptProjectCreator';
|
||||
import { ProjectLanguage, ProjectRuntime, TemplateFilter } from '../src/constants';
|
||||
import { Template } from '../src/templates/Template';
|
||||
import { getTemplateData, TemplateData } from '../src/templates/TemplateData';
|
||||
import { FunctionTemplates, getFunctionTemplates } from '../src/templates/FunctionTemplates';
|
||||
import { IFunctionTemplate } from '../src/templates/IFunctionTemplate';
|
||||
|
||||
let backupTemplateData: TemplateData;
|
||||
let funcPortalTemplateData: TemplateData | undefined;
|
||||
let backupTemplates: FunctionTemplates;
|
||||
let latestTemplates: FunctionTemplates | undefined;
|
||||
|
||||
// tslint:disable-next-line:no-function-expression
|
||||
suiteSetup(async function (this: IHookCallbackContext): Promise<void> {
|
||||
this.timeout(30 * 1000);
|
||||
backupTemplateData = <TemplateData>(await getTemplateData(undefined));
|
||||
funcPortalTemplateData = <TemplateData>(await getTemplateData(undefined));
|
||||
backupTemplates = <FunctionTemplates>(await getFunctionTemplates());
|
||||
latestTemplates = <FunctionTemplates>(await getFunctionTemplates());
|
||||
// https://github.com/Microsoft/vscode-azurefunctions/issues/334
|
||||
});
|
||||
|
||||
suite('Template Data Tests', async () => {
|
||||
suite('Template Count Tests', async () => {
|
||||
test('Valid templates count', async () => {
|
||||
if (funcPortalTemplateData) {
|
||||
await validateTemplateData(funcPortalTemplateData);
|
||||
if (latestTemplates) {
|
||||
await validateTemplateCounts(latestTemplates);
|
||||
} else {
|
||||
assert.fail('Failed to find templates from functions portal.');
|
||||
}
|
||||
|
||||
await validateTemplateData(backupTemplateData);
|
||||
await validateTemplateCounts(backupTemplates);
|
||||
});
|
||||
});
|
||||
|
||||
async function validateTemplateData(templateData: TemplateData): Promise<void> {
|
||||
const jsTemplates: Template[] = await templateData.getTemplates(ProjectLanguage.JavaScript, JavaScriptProjectCreator.defaultRuntime, TemplateFilter.Verified);
|
||||
assert.equal(jsTemplates.length, 8, 'Unexpected JavaScript templates count.');
|
||||
async function validateTemplateCounts(templates: FunctionTemplates): Promise<void> {
|
||||
const jsTemplatesv1: IFunctionTemplate[] = await templates.getTemplates(ProjectLanguage.JavaScript, ProjectRuntime.one, TemplateFilter.Verified);
|
||||
assert.equal(jsTemplatesv1.length, 8, 'Unexpected JavaScript v1 templates count.');
|
||||
|
||||
const javaTemplates: Template[] = await templateData.getTemplates(ProjectLanguage.Java, JavaProjectCreator.defaultRuntime, TemplateFilter.Verified);
|
||||
const jsTemplatesv2: IFunctionTemplate[] = await templates.getTemplates(ProjectLanguage.JavaScript, ProjectRuntime.beta, TemplateFilter.Verified);
|
||||
assert.equal(jsTemplatesv2.length, 4, 'Unexpected JavaScript v2 templates count.');
|
||||
|
||||
const javaTemplates: IFunctionTemplate[] = await templates.getTemplates(ProjectLanguage.Java, JavaProjectCreator.defaultRuntime, TemplateFilter.Verified);
|
||||
assert.equal(javaTemplates.length, 4, 'Unexpected Java templates count.');
|
||||
|
||||
const cSharpTemplates: Template[] = await templateData.getTemplates(ProjectLanguage.CSharp, ProjectRuntime.one, TemplateFilter.Verified);
|
||||
const cSharpTemplates: IFunctionTemplate[] = await templates.getTemplates(ProjectLanguage.CSharp, ProjectRuntime.one, TemplateFilter.Verified);
|
||||
assert.equal(cSharpTemplates.length, 4, 'Unexpected CSharp (.NET Framework) templates count.');
|
||||
|
||||
const cSharpTemplatesv2: Template[] = await templateData.getTemplates(ProjectLanguage.CSharp, ProjectRuntime.beta, TemplateFilter.Verified);
|
||||
const cSharpTemplatesv2: IFunctionTemplate[] = await templates.getTemplates(ProjectLanguage.CSharp, ProjectRuntime.beta, TemplateFilter.Verified);
|
||||
assert.equal(cSharpTemplatesv2.length, 4, 'Unexpected CSharp (.NET Core) templates count.');
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче