зеркало из https://github.com/Azure/autorest.git
Updates, fixes, features (cont.) (#2203)
* cleanup * last for today * regen sanit. * wip * cleanup * de-race AR.NET (the SD singleton...) * fix compare script * shift x-ms-cgs responsibilities * cleanup * artifact emitter as pull in point * OMG why * err update * full stack trace anonymization * fix mocha build break * more mocha fixd * removed deprecated tests (putting defaults in service definitions doesn't play well with validation) * for Laurent
This commit is contained in:
Родитель
0b57a801da
Коммит
6348004f94
|
@ -1,22 +1,23 @@
|
|||
FATAL: System.ArgumentException: Reference path 'Cowball' does not exist in the definition section of the Swagger document.
|
||||
at AutoRest.Swagger.SchemaResolver.DereferenceInner(String referencePath, List`1 visitedReferences) in SchemaResolver.cs:line 354
|
||||
at AutoRest.Swagger.SchemaResolver.Dereference(String referencePath) in SchemaResolver.cs:line 323
|
||||
at AutoRest.Swagger.SchemaResolver.Unwrap(Schema schema) in SchemaResolver.cs:line 71
|
||||
at AutoRest.Swagger.SwaggerModeler.Unwrap(SwaggerParameter swaggerParameter) in SwaggerModeler.cs:line 401
|
||||
at AutoRest.Swagger.ParameterBuilder.BuildServiceType(String serviceTypeName) in ParameterBuilder.cs:line 69
|
||||
at AutoRest.Swagger.ParameterBuilder.Build() in ParameterBuilder.cs:line 47
|
||||
at AutoRest.Swagger.OperationBuilder.BuildMethodParameters(Method method) in OperationBuilder.cs:line 212
|
||||
at AutoRest.Swagger.OperationBuilder.BuildMethod(HttpMethod httpMethod, String url, String methodName, String methodGroup) in OperationBuilder.cs:line 94
|
||||
at AutoRest.Swagger.SwaggerModeler.BuildMethod(HttpMethod httpMethod, String url, String name, Operation operation) in SwaggerModeler.cs:line 326
|
||||
at AutoRest.Swagger.SwaggerModeler.Build(ServiceDefinition serviceDefinition) in SwaggerModeler.cs:line 134
|
||||
at Modeler.<ProcessInternal>d__1.MoveNext() in Modeler.cs:line 37
|
||||
at ...
|
||||
at ...
|
||||
at ...
|
||||
at ...
|
||||
at ...
|
||||
at ...
|
||||
at ...
|
||||
at ...
|
||||
at ...
|
||||
at ...
|
||||
at ...
|
||||
--- End of stack trace from previous location where exception was thrown ---
|
||||
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
|
||||
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
|
||||
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
|
||||
at NewPlugin.<Process>d__11.MoveNext() in NewPlugin.cs:line 67
|
||||
Error: Plugin modeler failed.
|
||||
at ...
|
||||
at ...
|
||||
at ...
|
||||
at ...
|
||||
at ...
|
||||
at ...
|
||||
at ...
|
||||
at ...
|
||||
FATAL: modeler - FAILED
|
||||
Error: Plugin modeler reported failure.
|
||||
at ...
|
||||
at ...
|
||||
at ...
|
||||
at ...
|
||||
|
|
|
@ -31,7 +31,7 @@ if( -not $lastAutorest ) {
|
|||
# $null = &"$PSScriptRoot\NuGet.exe" install autorest -source https://www.myget.org/F/autorest/api/v3/index.json -prerelease -Version 0.17.3-Nightly20161101 -outputdirectory $baseFolder
|
||||
|
||||
# get autorest nightly exe
|
||||
$lastAutoRest = (dir "$PSScriptRoot\..\src\core\AutoRest\bin\Debug\netcoreapp1.0\node_modules\autorest-core\app.js").FullName
|
||||
$lastAutoRest = (Get-ChildItem "$PSScriptRoot\..\src\core\AutoRest\bin\Debug\netcoreapp1.0\node_modules\autorest-core\app.js").FullName
|
||||
}
|
||||
|
||||
if( -not (resolve-path $lastAutoRest -ea 0 )) {
|
||||
|
@ -39,7 +39,7 @@ if( -not (resolve-path $lastAutoRest -ea 0 )) {
|
|||
}
|
||||
|
||||
if( -not $newAutoRest ) {
|
||||
$newAutorest = (dir "$PSScriptRoot\..\src\core\AutoRest\bin\Debug\netcoreapp1.0\node_modules\autorest-core\app.js").FullName
|
||||
$newAutorest = (Get-ChildItem "$PSScriptRoot\..\src\core\AutoRest\bin\Debug\netcoreapp1.0\node_modules\autorest-core\app.js").FullName
|
||||
}
|
||||
|
||||
if( -not (resolve-path $newAutorest -ea 0 )) {
|
||||
|
|
|
@ -81,7 +81,7 @@ export async function CreateConfiguration(baseFolderUri: string, inputScope: Dat
|
|||
|
||||
if (usedCodeGenerator === "ruby" || usedCodeGenerator === "python" || usedCodeGenerator === "go") {
|
||||
result["package-version"] = switches["pv"] || switches["packageversion"] || undefined;
|
||||
result["package-name"] = switches["pn"] || switches["packagename"] || GetFilenameWithoutExtension(inputFile).replace(/[^a-zA-Z0-9-_]/g, "").replace(/-/g, '_').replace(/([a-z])([A-Z])/g, "$1_$2").toLowerCase();
|
||||
result["package-name"] = switches["pn"] || switches["packagename"] || undefined;
|
||||
}
|
||||
|
||||
result["output-file"] = switches["outputfilename"] || undefined;
|
||||
|
|
|
@ -168,6 +168,9 @@ export class AutoRest extends EventEmitter {
|
|||
|
||||
this.Message.Dispatch({ Channel: Channel.Debug, Text: `Starting Process() Run Pipeline.` });
|
||||
|
||||
if (view.InputFileUris.length === 0) {
|
||||
throw new Exception("No input files provided.\n\nUse --help to get help information.", 0);
|
||||
}
|
||||
const result = await Promise.race([
|
||||
RunPipeline(view, <IFileSystem>this.fileSystem),
|
||||
new Promise((_, rej) => view.CancellationToken.onCancellationRequested(() => rej("Cancellation requested.")))]);
|
||||
|
|
|
@ -190,9 +190,10 @@ export class ConfigurationView {
|
|||
.Select(each => new DirectiveView(each));
|
||||
}
|
||||
|
||||
public get InputFileUris(): Iterable<string> {
|
||||
public get InputFileUris(): string[] {
|
||||
return From<string>(ValuesOf<string>(this.config["input-file"]))
|
||||
.Select(each => this.ResolveAsPath(each));
|
||||
.Select(each => this.ResolveAsPath(each))
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
public get OutputFolderUri(): string {
|
||||
|
|
|
@ -12,6 +12,13 @@ export class OperationCanceledException extends Exception {
|
|||
}
|
||||
}
|
||||
|
||||
export class OutstandingTaskAlreadyCompletedException extends Exception {
|
||||
constructor() {
|
||||
super("The OutstandingTaskAwaiter is already completed, may not Enter() again.", 1);
|
||||
Object.setPrototypeOf(this, OutstandingTaskAlreadyCompletedException.prototype);
|
||||
}
|
||||
}
|
||||
|
||||
export class OperationAbortedException extends Exception {
|
||||
constructor() {
|
||||
super("Error occurred. Exiting.", 1);
|
||||
|
|
|
@ -3,14 +3,21 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { OutstandingTaskAlreadyCompletedException } from './exception';
|
||||
|
||||
export class OutstandingTaskAwaiter {
|
||||
private locked: boolean = false;
|
||||
private outstandingTasks: Promise<any>[] = [];
|
||||
|
||||
public async Wait(): Promise<void> {
|
||||
this.locked = true;
|
||||
await Promise.all(this.outstandingTasks);
|
||||
}
|
||||
|
||||
public async Await<T>(task: Promise<T>): Promise<T> {
|
||||
if (this.locked) {
|
||||
throw new OutstandingTaskAlreadyCompletedException();
|
||||
}
|
||||
this.outstandingTasks.push(task);
|
||||
return task;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Lazy, LazyPromise } from '../lazy';
|
||||
import { Stringify, YAMLNode } from "../ref/yaml";
|
||||
import { IdentitySourceMapping } from "../source-map/merging";
|
||||
import { Channel } from "../message";
|
||||
import { ConfigurationView } from "../configuration";
|
||||
import { DataHandleRead, DataStoreViewReadonly } from "../data-store/data-store";
|
||||
|
||||
function IsOutputArtifactOrMapRequested(config: ConfigurationView, artifactType: string) {
|
||||
return config.IsOutputArtifactRequested(artifactType) || config.IsOutputArtifactRequested(artifactType + ".map");
|
||||
}
|
||||
function IsOutputArtifactVariantRequested(config: ConfigurationView, artifactType: string) {
|
||||
return IsOutputArtifactOrMapRequested(config, artifactType)
|
||||
|| IsOutputArtifactOrMapRequested(config, artifactType + ".yaml")
|
||||
|| IsOutputArtifactOrMapRequested(config, artifactType + ".json");
|
||||
}
|
||||
|
||||
async function EmitArtifactInternal(config: ConfigurationView, artifactType: string, uri: string, handle: DataHandleRead): Promise<void> {
|
||||
config.Message({ Channel: Channel.Debug, Text: `Emitting '${artifactType}' at ${uri}` });
|
||||
if (config.IsOutputArtifactRequested(artifactType)) {
|
||||
config.GeneratedFile.Dispatch({
|
||||
type: artifactType,
|
||||
uri: uri,
|
||||
content: handle.ReadData()
|
||||
});
|
||||
}
|
||||
if (config.IsOutputArtifactRequested(artifactType + ".map")) {
|
||||
config.GeneratedFile.Dispatch({
|
||||
type: artifactType + ".map",
|
||||
uri: uri + ".map",
|
||||
content: JSON.stringify(handle.ReadMetadata().inputSourceMap.Value, null, 2)
|
||||
});
|
||||
}
|
||||
}
|
||||
let emitCtr = 0;
|
||||
async function EmitArtifact(config: ConfigurationView, artifactType: string, uri: string, handle: DataHandleRead, isObject: boolean): Promise<void> {
|
||||
await EmitArtifactInternal(config, artifactType, uri, handle);
|
||||
|
||||
if (isObject) {
|
||||
const scope = config.DataStore.CreateScope("emitObjectArtifact");
|
||||
const object = new Lazy<any>(() => handle.ReadObject<any>());
|
||||
const ast = new Lazy<YAMLNode>(() => handle.ReadYamlAst());
|
||||
|
||||
if (IsOutputArtifactOrMapRequested(config, artifactType + ".yaml")) {
|
||||
const hw = await scope.Write(`${++emitCtr}.yaml`);
|
||||
const h = await hw.WriteData(Stringify(object.Value), IdentitySourceMapping(handle.key, ast.Value), [handle]);
|
||||
await EmitArtifactInternal(config, artifactType + ".yaml", uri + ".yaml", h);
|
||||
}
|
||||
if (IsOutputArtifactOrMapRequested(config, artifactType + ".json")) {
|
||||
const hw = await scope.Write(`${++emitCtr}.json`);
|
||||
const h = await hw.WriteData(JSON.stringify(object.Value, null, 2), IdentitySourceMapping(handle.key, ast.Value), [handle]);
|
||||
await EmitArtifactInternal(config, artifactType + ".json", uri + ".json", h);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export async function EmitArtifacts(config: ConfigurationView, artifactType: string, uriResolver: (key: string) => string, lazyScope: LazyPromise<DataStoreViewReadonly>, isObject: boolean): Promise<void> {
|
||||
if (IsOutputArtifactVariantRequested(config, artifactType)) {
|
||||
const scope = await lazyScope;
|
||||
for (const key of await scope.Enum()) {
|
||||
const file = await scope.ReadStrict(key);
|
||||
await EmitArtifact(config, artifactType, uriResolver(file.key), file, isObject);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,85 +3,29 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Lazy, LazyPromise } from "../lazy";
|
||||
import { Stringify, YAMLNode } from '../ref/yaml';
|
||||
import { LazyPromise } from "../lazy";
|
||||
import { OutstandingTaskAwaiter } from "../outstanding-task-awaiter";
|
||||
import { AutoRestPlugin } from "./plugin-endpoint";
|
||||
import { Manipulator } from "./manipulation";
|
||||
import { ProcessCodeModel } from "./commonmark-documentation";
|
||||
import { IdentitySourceMapping } from "../source-map/merging";
|
||||
import { Channel, Message, SourceLocation, Range } from "../message";
|
||||
import { Channel } from "../message";
|
||||
import { MultiPromise } from "../multi-promise";
|
||||
import { GetFilename, ResolveUri } from "../ref/uri";
|
||||
import { ConfigurationView } from "../configuration";
|
||||
import { DataHandleRead, DataStoreView, DataStoreViewReadonly, QuickScope } from "../data-store/data-store";
|
||||
import { AutoRestDotNetPlugin } from "./plugins/autorest-dotnet";
|
||||
import { GetAutoRestDotNetPlugin } from "./plugins/autorest-dotnet";
|
||||
import { ComposeSwaggers, LoadLiterateSwaggers } from "./swagger-loader";
|
||||
import { From } from "../ref/linq";
|
||||
import { IFileSystem } from "../file-system";
|
||||
import { Exception } from "../exception";
|
||||
import { EmitArtifacts } from "./artifact-emitter";
|
||||
|
||||
export type DataPromise = MultiPromise<DataHandleRead>;
|
||||
|
||||
async function emitArtifactInternal(config: ConfigurationView, artifactType: string, uri: string, handle: DataHandleRead): Promise<void> {
|
||||
config.Message({ Channel: Channel.Debug, Text: `Emitting '${artifactType}' at ${uri}` });
|
||||
if (config.IsOutputArtifactRequested(artifactType)) {
|
||||
config.GeneratedFile.Dispatch({
|
||||
type: artifactType,
|
||||
uri: uri,
|
||||
content: handle.ReadData()
|
||||
});
|
||||
}
|
||||
if (config.IsOutputArtifactRequested(artifactType + ".map")) {
|
||||
config.GeneratedFile.Dispatch({
|
||||
type: artifactType + ".map",
|
||||
uri: uri + ".map",
|
||||
content: JSON.stringify(handle.ReadMetadata().inputSourceMap.Value, null, 2)
|
||||
});
|
||||
}
|
||||
}
|
||||
let emitCtr = 0;
|
||||
async function emitArtifact(config: ConfigurationView, artifactType: string, uri: string, handle: DataHandleRead, isObject: boolean): Promise<void> {
|
||||
await emitArtifactInternal(config, artifactType, uri, handle);
|
||||
|
||||
if (isObject) {
|
||||
const scope = config.DataStore.CreateScope("emitObjectArtifact");
|
||||
const object = new Lazy<any>(() => handle.ReadObject<any>());
|
||||
const ast = new Lazy<YAMLNode>(() => handle.ReadYamlAst());
|
||||
|
||||
if (config.IsOutputArtifactRequested(artifactType + ".yaml")
|
||||
|| config.IsOutputArtifactRequested(artifactType + ".yaml.map")) {
|
||||
|
||||
const hw = await scope.Write(`${++emitCtr}.yaml`);
|
||||
const h = await hw.WriteData(Stringify(object.Value), IdentitySourceMapping(handle.key, ast.Value), [handle]);
|
||||
await emitArtifactInternal(config, artifactType + ".yaml", uri + ".yaml", h);
|
||||
}
|
||||
if (config.IsOutputArtifactRequested(artifactType + ".json")
|
||||
|| config.IsOutputArtifactRequested(artifactType + ".json.map")) {
|
||||
|
||||
const hw = await scope.Write(`${++emitCtr}.json`);
|
||||
const h = await hw.WriteData(JSON.stringify(object.Value, null, 2), IdentitySourceMapping(handle.key, ast.Value), [handle]);
|
||||
await emitArtifactInternal(config, artifactType + ".json", uri + ".json", h);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function emitArtifacts(config: ConfigurationView, artifactType: string, uriResolver: (key: string) => string, scope: DataStoreViewReadonly, isObject: boolean): Promise<void> {
|
||||
for (const key of await scope.Enum()) {
|
||||
const file = await scope.ReadStrict(key);
|
||||
await emitArtifact(config, artifactType, uriResolver(file.key), file, isObject);
|
||||
}
|
||||
}
|
||||
|
||||
type PipelinePlugin = (config: ConfigurationView, input: DataStoreViewReadonly, working: DataStoreView, output: DataStoreView) => Promise<void>;
|
||||
type PipelineNode = { id: string, outputArtifact: string, plugin: PipelinePlugin, inputs: PipelineNode[] };
|
||||
|
||||
function CreatePluginLoader(): PipelinePlugin {
|
||||
return async (config, input, working, output) => {
|
||||
let inputs = From(config.InputFileUris).ToArray();
|
||||
if (inputs.length === 0) {
|
||||
throw new Exception("No input files provided.\n\nUse --help to get help information.", 0);
|
||||
}
|
||||
let inputs = config.InputFileUris;
|
||||
const swaggers = await LoadLiterateSwaggers(
|
||||
config,
|
||||
input,
|
||||
|
@ -115,7 +59,7 @@ function CreatePluginComposer(): PipelinePlugin {
|
|||
await (await output.Write("swagger-document")).Forward(swagger);
|
||||
};
|
||||
}
|
||||
function CreatePluginExternal(host: PromiseLike<AutoRestPlugin>, pluginName: string): PipelinePlugin {
|
||||
function CreatePluginExternal(host: PromiseLike<AutoRestPlugin>, pluginName: string, fullKeys: boolean = true): PipelinePlugin {
|
||||
return async (config, input, working, output) => {
|
||||
const plugin = await host;
|
||||
const pluginNames = await plugin.GetPluginNames(config.CancellationToken);
|
||||
|
@ -124,12 +68,14 @@ function CreatePluginExternal(host: PromiseLike<AutoRestPlugin>, pluginName: str
|
|||
}
|
||||
|
||||
// forward input scope (relative/absolute key mess...)
|
||||
const inputx = new QuickScope(await Promise.all((await input.Enum()).map(x => input.ReadStrict(x))));
|
||||
if (fullKeys) {
|
||||
input = new QuickScope(await Promise.all((await input.Enum()).map(x => input.ReadStrict(x))));
|
||||
}
|
||||
|
||||
const result = await plugin.Process(
|
||||
pluginName,
|
||||
key => config.GetEntry(key as any),
|
||||
inputx,
|
||||
input,
|
||||
output,
|
||||
config.Message.bind(config),
|
||||
config.CancellationToken);
|
||||
|
@ -150,13 +96,11 @@ function CreateCommonmarkProcessor(): PipelinePlugin {
|
|||
}
|
||||
|
||||
export async function RunPipeline(config: ConfigurationView, fileSystem: IFileSystem): Promise<void> {
|
||||
const cancellationToken = config.CancellationToken;
|
||||
const processMessage = config.Message.bind(config);
|
||||
const barrier = new OutstandingTaskAwaiter();
|
||||
|
||||
// externals:
|
||||
const oavPluginHost = new LazyPromise(async () => await AutoRestPlugin.FromModule(`${__dirname}/plugins/openapi-validation-tools`));
|
||||
const autoRestDotNet = new LazyPromise(async () => await AutoRestDotNetPlugin.Get().pluginEndpoint);
|
||||
const autoRestDotNet = new LazyPromise(async () => await GetAutoRestDotNetPlugin());
|
||||
|
||||
// TODO: enhance with custom declared plugins
|
||||
const plugins: { [name: string]: PipelinePlugin } = {
|
||||
|
@ -175,7 +119,7 @@ export async function RunPipeline(config: ConfigurationView, fileSystem: IFileSy
|
|||
"go": CreatePluginExternal(autoRestDotNet, "go"),
|
||||
"java": CreatePluginExternal(autoRestDotNet, "java"),
|
||||
"azureresourceschema": CreatePluginExternal(autoRestDotNet, "azureresourceschema"),
|
||||
"csharp-simplifier": CreatePluginExternal(autoRestDotNet, "csharp-simplifier"),
|
||||
"csharp-simplifier": CreatePluginExternal(autoRestDotNet, "csharp-simplifier", false),
|
||||
|
||||
"commonmarker": CreateCommonmarkProcessor()
|
||||
};
|
||||
|
@ -214,13 +158,11 @@ export async function RunPipeline(config: ConfigurationView, fileSystem: IFileSy
|
|||
const scopeComposedSwagger = await RunPlugin(config, "compose", scopeLoadedSwaggersTransformed);
|
||||
const scopeComposedSwaggerTransformed = await RunPlugin(config, "transform", scopeComposedSwagger);
|
||||
|
||||
const swagger = await scopeComposedSwaggerTransformed.ReadStrict((await scopeComposedSwaggerTransformed.Enum())[0]);
|
||||
|
||||
{
|
||||
const relPath =
|
||||
config.GetEntry("output-file") || // TODO: overthink
|
||||
(config.GetEntry("namespace") ? config.GetEntry("namespace") : GetFilename([...config.InputFileUris][0]).replace(/\.json$/, ""));
|
||||
barrier.Await(emitArtifacts(config, "swagger-document", _ => ResolveUri(config.OutputFolderUri, relPath), scopeComposedSwaggerTransformed, true));
|
||||
(config.GetEntry("namespace") ? config.GetEntry("namespace") : GetFilename(config.InputFileUris[0]).replace(/\.json$/, ""));
|
||||
barrier.Await(EmitArtifacts(config, "swagger-document", _ => ResolveUri(config.OutputFolderUri, relPath), new LazyPromise(async () => scopeComposedSwaggerTransformed), true));
|
||||
}
|
||||
|
||||
if (!config.DisableValidation) {
|
||||
|
@ -240,42 +182,28 @@ export async function RunPipeline(config: ConfigurationView, fileSystem: IFileSy
|
|||
|
||||
// code generators
|
||||
if (usedCodeGenerators.length > 0) {
|
||||
// modeler
|
||||
let codeModel = await AutoRestDotNetPlugin.Get().Model(swagger, config.DataStore.CreateScope("model"),
|
||||
{
|
||||
namespace: config.GetEntry("namespace")
|
||||
},
|
||||
processMessage);
|
||||
const scopeCodeModel = await RunPlugin(config, "modeler", scopeComposedSwaggerTransformed);
|
||||
const scopeCodeModelCommonmark = await RunPlugin(config, "commonmarker", scopeCodeModel);
|
||||
|
||||
// GFMer
|
||||
const codeModelGFM = await ProcessCodeModel(codeModel, config.DataStore.CreateScope("modelgfm"));
|
||||
|
||||
let pluginCtr = 0;
|
||||
for (const usedCodeGenerator of usedCodeGenerators) {
|
||||
for (const genConfig of config.GetPluginViews(usedCodeGenerator)) {
|
||||
const manipulator = new Manipulator(genConfig);
|
||||
const processMessage = genConfig.Message.bind(genConfig);
|
||||
const scope = genConfig.DataStore.CreateScope("plugin_" + ++pluginCtr);
|
||||
|
||||
barrier.Await((async () => {
|
||||
// TRANSFORM
|
||||
const codeModelTransformed = await manipulator.Process(codeModelGFM, scope.CreateScope("transform"), "/code-model-v1.yaml");
|
||||
const scopeCodeModelTransformed = await RunPlugin(genConfig, "transform", scopeCodeModelCommonmark);
|
||||
|
||||
await emitArtifactInternal(genConfig, "code-model-v1", ResolveUri(config.OutputFolderUri, "code-model.yaml"), codeModelTransformed);
|
||||
await EmitArtifacts(genConfig, "code-model-v1", _ => ResolveUri(genConfig.OutputFolderUri, "code-model.yaml"), new LazyPromise(async () => scopeCodeModelTransformed), false);
|
||||
|
||||
let generatedFileScope = await AutoRestDotNetPlugin.Get().GenerateCode(genConfig, usedCodeGenerator, swagger, codeModelTransformed, scope.CreateScope("generate"), processMessage);
|
||||
const inputScope = new QuickScope([
|
||||
await scopeComposedSwaggerTransformed.ReadStrict((await scopeComposedSwaggerTransformed.Enum())[0]),
|
||||
await scopeCodeModelTransformed.ReadStrict((await scopeCodeModelTransformed.Enum())[0])
|
||||
]);
|
||||
let generatedFileScope = await RunPlugin(genConfig, usedCodeGenerator, inputScope);
|
||||
|
||||
// C# simplifier
|
||||
if (usedCodeGenerator === "csharp") {
|
||||
generatedFileScope = await AutoRestDotNetPlugin.Get().SimplifyCSharpCode(generatedFileScope, scope.CreateScope("simplify"), processMessage);
|
||||
generatedFileScope = await RunPlugin(genConfig, "csharp-simplifier", generatedFileScope);
|
||||
}
|
||||
|
||||
for (const fileName of await generatedFileScope.Enum()) {
|
||||
const handle = await generatedFileScope.ReadStrict(fileName);
|
||||
const relPath = decodeURIComponent(handle.key.split("/output/")[1]);
|
||||
const outputFileUri = ResolveUri(genConfig.OutputFolderUri, relPath);
|
||||
await emitArtifactInternal(genConfig, `source-file-${usedCodeGenerator}`, outputFileUri, handle);
|
||||
}
|
||||
await EmitArtifacts(genConfig, `source-file-${usedCodeGenerator}`, key => ResolveUri(genConfig.OutputFolderUri, decodeURIComponent(key.split("/output/")[1])), new LazyPromise(async () => generatedFileScope), false);
|
||||
})());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,108 +1,13 @@
|
|||
import { ConfigurationView } from '../../autorest-core';
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { AutoRestConfigurationImpl } from "../../configuration";
|
||||
import { ChildProcess } from "child_process";
|
||||
import { EventEmitter } from "../../events";
|
||||
import { CancellationToken } from "../../ref/cancallation";
|
||||
import { LazyPromise } from '../../lazy';
|
||||
import { SpawnJsonRpcAutoRest } from "../../../interop/autorest-dotnet";
|
||||
import { AutoRestPlugin } from "../plugin-endpoint";
|
||||
import { DataHandleRead, DataStoreViewReadonly, QuickScope, DataStoreView } from "../../data-store/data-store";
|
||||
import { Message } from "../../message";
|
||||
|
||||
export class AutoRestDotNetPlugin extends EventEmitter {
|
||||
private static instance: AutoRestDotNetPlugin | null;
|
||||
public static Get(): AutoRestDotNetPlugin { return AutoRestDotNetPlugin.instance ? AutoRestDotNetPlugin.instance : (AutoRestDotNetPlugin.instance = new AutoRestDotNetPlugin()); }
|
||||
|
||||
private childProc: ChildProcess;
|
||||
public pluginEndpoint: Promise<AutoRestPlugin>;
|
||||
|
||||
private constructor() {
|
||||
super();
|
||||
this.childProc = SpawnJsonRpcAutoRest();
|
||||
this.pluginEndpoint = AutoRestPlugin.FromChildProcess(this.childProc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Probes whether the extension even supports the requested plugin.
|
||||
*/
|
||||
public async CautiousProcess(
|
||||
pluginName: string,
|
||||
configuration: (key: string) => any,
|
||||
inputScope: DataStoreViewReadonly,
|
||||
outputScope: DataStoreView,
|
||||
onMessage: (message: Message) => void): Promise<void> {
|
||||
|
||||
const ep = await this.pluginEndpoint;
|
||||
|
||||
// probe
|
||||
const pluginNames = await ep.GetPluginNames(CancellationToken.None);
|
||||
if (pluginNames.indexOf(pluginName) === -1) {
|
||||
throw new Error(`The AutoRest dotnet extension does not offer a plugin called '${pluginName}'.`);
|
||||
}
|
||||
// process
|
||||
const success = await ep.Process(pluginName, configuration, inputScope, outputScope, onMessage, CancellationToken.None);
|
||||
if (!success) {
|
||||
throw new Error(`Plugin ${pluginName} failed.`);
|
||||
}
|
||||
}
|
||||
|
||||
public async Validate(swagger: DataHandleRead, workingScope: DataStoreView, onMessage: (message: Message) => void): Promise<void> {
|
||||
const outputScope = workingScope.CreateScope("output");
|
||||
await this.CautiousProcess("azure-validator", _ => { }, new QuickScope([swagger]), outputScope, onMessage);
|
||||
}
|
||||
|
||||
public async GenerateCode(
|
||||
config: ConfigurationView,
|
||||
language: string,
|
||||
swaggerDocument: DataHandleRead,
|
||||
codeModel: DataHandleRead,
|
||||
workingScope: DataStoreView,
|
||||
onMessage: (message: Message) => void): Promise<DataStoreViewReadonly> {
|
||||
|
||||
const rawSwagger = await swaggerDocument.ReadObject<any>();
|
||||
const getXmsCodeGenSetting = (name: string) => (() => { try { return rawSwagger.info["x-ms-code-generation-settings"][name]; } catch (e) { return null; } })();
|
||||
const settings: AutoRestConfigurationImpl =
|
||||
Object.assign(
|
||||
{ // stuff that comes in via `x-ms-code-generation-settings`
|
||||
"override-client-name": getXmsCodeGenSetting("name"),
|
||||
"use-internal-constructors": getXmsCodeGenSetting("internalConstructors"),
|
||||
"use-datetimeoffset": getXmsCodeGenSetting("useDateTimeOffset"),
|
||||
"payload-flattening-threshold": getXmsCodeGenSetting("ft"),
|
||||
"sync-methods": getXmsCodeGenSetting("syncMethods")
|
||||
},
|
||||
config.Raw);
|
||||
|
||||
const outputScope = workingScope.CreateScope("output");
|
||||
await this.CautiousProcess(language, key => (settings as any)[key], new QuickScope([swaggerDocument, codeModel]), outputScope, onMessage);
|
||||
return outputScope;
|
||||
}
|
||||
|
||||
public async SimplifyCSharpCode(
|
||||
inputScope: DataStoreViewReadonly,
|
||||
workingScope: DataStoreView,
|
||||
onMessage: (message: Message) => void): Promise<DataStoreViewReadonly> {
|
||||
|
||||
const outputScope = workingScope.CreateScope("output");
|
||||
await this.CautiousProcess(`csharp-simplifier`, _ => null, inputScope, outputScope, onMessage);
|
||||
return outputScope;
|
||||
}
|
||||
|
||||
public async Model(
|
||||
swagger: DataHandleRead,
|
||||
workingScope: DataStoreView,
|
||||
settings: { namespace: string },
|
||||
onMessage: (message: Message) => void): Promise<DataHandleRead> {
|
||||
|
||||
const outputScope = workingScope.CreateScope("output");
|
||||
await this.CautiousProcess("modeler", key => (settings as any)[key], new QuickScope([swagger]), outputScope, onMessage);
|
||||
const results = await outputScope.Enum();
|
||||
if (results.length !== 1) {
|
||||
throw new Error(`Modeler plugin produced '${results.length}' items. Only expected one (the code model).`);
|
||||
}
|
||||
return await outputScope.ReadStrict(results[0]);
|
||||
}
|
||||
const instance = new LazyPromise<AutoRestPlugin>(() => AutoRestPlugin.FromChildProcess(SpawnJsonRpcAutoRest()));
|
||||
export function GetAutoRestDotNetPlugin(): PromiseLike<AutoRestPlugin> {
|
||||
return instance;
|
||||
}
|
||||
|
|
|
@ -60,7 +60,7 @@ import { PumpMessagesToConsole } from './test-utility';
|
|||
|
||||
const config = await autoRest.view;
|
||||
assert.strictEqual(config.GetEntry("azure-arm"), true);
|
||||
assert.strictEqual([...config.InputFileUris].length, 1);
|
||||
assert.strictEqual(config.InputFileUris.length, 1);
|
||||
|
||||
const messages: Message[] = [];
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ import { AutoRest } from "../lib/autorest-core";
|
|||
import { CancellationToken } from "../lib/ref/cancallation";
|
||||
import { CreateFolderUri, ResolveUri } from "../lib/ref/uri";
|
||||
import { Message, Channel } from "../lib/message";
|
||||
import { AutoRestDotNetPlugin } from "../lib/pipeline/plugins/autorest-dotnet";
|
||||
import { GetAutoRestDotNetPlugin } from "../lib/pipeline/plugins/autorest-dotnet";
|
||||
import { AutoRestPlugin } from "../lib/pipeline/plugin-endpoint";
|
||||
import { DataStore, QuickScope } from '../lib/data-store/data-store';
|
||||
import { LoadLiterateSwagger } from "../lib/pipeline/swagger-loader";
|
||||
|
@ -77,10 +77,11 @@ import { LoadLiterateSwagger } from "../lib/pipeline/swagger-loader";
|
|||
dataStore.CreateScope("loader"));
|
||||
|
||||
// call validator
|
||||
const autorestPlugin = AutoRestDotNetPlugin.Get();
|
||||
const autorestPlugin = await GetAutoRestDotNetPlugin();
|
||||
const pluginScope = dataStore.CreateScope("plugin");
|
||||
const messages: Message[] = [];
|
||||
const resultScope = await autorestPlugin.CautiousProcess("azure-validator", _ => { }, new QuickScope([swagger]), pluginScope, m => messages.push(m));
|
||||
const result = await autorestPlugin.Process("azure-validator", _ => { }, new QuickScope([swagger]), pluginScope, m => messages.push(m), CancellationToken.None);
|
||||
assert.strictEqual(result, true);
|
||||
|
||||
// check results
|
||||
assert.notEqual(messages.length, 0);
|
||||
|
@ -106,9 +107,10 @@ import { LoadLiterateSwagger } from "../lib/pipeline/swagger-loader";
|
|||
dataStore.CreateScope("loader"));
|
||||
|
||||
// call modeler
|
||||
const autorestPlugin = AutoRestDotNetPlugin.Get();
|
||||
const autorestPlugin = await GetAutoRestDotNetPlugin();
|
||||
const pluginScope = dataStore.CreateScope("plugin");
|
||||
await autorestPlugin.CautiousProcess("modeler", key => { return ({ namespace: "SomeNamespace" } as any)[key]; }, new QuickScope([swagger]), pluginScope, m => null);
|
||||
const result = await autorestPlugin.Process("modeler", key => { return ({ namespace: "SomeNamespace" } as any)[key]; }, new QuickScope([swagger]), pluginScope, m => null, CancellationToken.None);
|
||||
assert.strictEqual(result, true);
|
||||
const results = await pluginScope.Enum();
|
||||
if (results.length !== 1) {
|
||||
throw new Error(`Modeler plugin produced '${results.length}' items. Only expected one (the code model).`);
|
||||
|
@ -144,15 +146,16 @@ import { LoadLiterateSwagger } from "../lib/pipeline/swagger-loader";
|
|||
const codeModelHandle = await inputScope.ReadStrict(codeModelUri);
|
||||
|
||||
// call generator
|
||||
const autorestPlugin = AutoRestDotNetPlugin.Get();
|
||||
const pluginScope = dataStore.CreateScope("plugin");
|
||||
const resultScope = await autorestPlugin.GenerateCode(
|
||||
config,
|
||||
const autorestPlugin = await GetAutoRestDotNetPlugin();
|
||||
const resultScope = dataStore.CreateScope("output");
|
||||
const result = await autorestPlugin.Process(
|
||||
"csharp",
|
||||
swagger,
|
||||
codeModelHandle,
|
||||
pluginScope,
|
||||
m => null);
|
||||
key => config.GetEntry(key as any),
|
||||
new QuickScope([swagger, codeModelHandle]),
|
||||
resultScope,
|
||||
m => null,
|
||||
CancellationToken.None);
|
||||
assert.strictEqual(result, true);
|
||||
|
||||
// check results
|
||||
const results = await resultScope.Enum();
|
||||
|
|
|
@ -99,7 +99,7 @@ namespace AutoRest.Extensions
|
|||
|
||||
if (!string.IsNullOrEmpty(parametersJson))
|
||||
{
|
||||
var serviceDefinition = ServiceDefinition.Instance;
|
||||
var serviceDefinition = Singleton<ServiceDefinition>.Instance ?? ServiceDefinition.Instance;
|
||||
var jsonSettings = new JsonSerializerSettings
|
||||
{
|
||||
TypeNameHandling = TypeNameHandling.None,
|
||||
|
|
|
@ -8,6 +8,9 @@ using AutoRest.Core.Extensibility;
|
|||
using AutoRest.Core;
|
||||
using AutoRest.Core.Parsing;
|
||||
using System.Linq;
|
||||
using AutoRest.Swagger.Model;
|
||||
using AutoRest.Swagger;
|
||||
using static AutoRest.Core.Utilities.DependencyInjection;
|
||||
|
||||
public class Generator : NewPlugin
|
||||
{
|
||||
|
@ -18,17 +21,40 @@ public class Generator : NewPlugin
|
|||
this.codeGenerator = codeGenerator;
|
||||
}
|
||||
|
||||
private T GetXmsCodeGenSetting<T>(ServiceDefinition sd, string name)
|
||||
{
|
||||
try
|
||||
{
|
||||
return (T)Convert.ChangeType(
|
||||
sd.Info.CodeGenerationSettings.Extensions[name],
|
||||
typeof(T).GenericTypeArguments.Length == 0 ? typeof(T) : typeof(T).GenericTypeArguments[0] // un-nullable
|
||||
);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return default(T);
|
||||
}
|
||||
}
|
||||
|
||||
protected override async Task<bool> ProcessInternal()
|
||||
{
|
||||
var files = await ListInputs();
|
||||
if (files.Length != 2)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var sd = Singleton<ServiceDefinition>.Instance = SwaggerParser.Parse("", await ReadFile(files[0]));
|
||||
|
||||
// get internal name
|
||||
var language = new[] {
|
||||
"CSharp",
|
||||
"Ruby",
|
||||
"NodeJS",
|
||||
"Python",
|
||||
"Go",
|
||||
"Java",
|
||||
"AzureResourceSchema" }
|
||||
"CSharp",
|
||||
"Ruby",
|
||||
"NodeJS",
|
||||
"Python",
|
||||
"Go",
|
||||
"Java",
|
||||
"AzureResourceSchema" }
|
||||
.Where(x => x.ToLowerInvariant() == codeGenerator)
|
||||
.FirstOrDefault();
|
||||
|
||||
|
@ -43,8 +69,8 @@ public class Generator : NewPlugin
|
|||
new Settings
|
||||
{
|
||||
Namespace = await GetValue("namespace"),
|
||||
ClientName = await GetValue("override-client-name"),
|
||||
PayloadFlatteningThreshold = await GetValue<int?>("payload-flattening-threshold") ?? 0,
|
||||
ClientName = GetXmsCodeGenSetting<string>(sd, "name") ?? await GetValue("override-client-name"),
|
||||
PayloadFlatteningThreshold = GetXmsCodeGenSetting<int?>(sd, "ft") ?? await GetValue<int?>("payload-flattening-threshold") ?? 0,
|
||||
AddCredentials = await GetValue<bool?>("add-credentials") ?? false,
|
||||
};
|
||||
var header = await GetValue("license-header");
|
||||
|
@ -52,9 +78,9 @@ public class Generator : NewPlugin
|
|||
{
|
||||
Settings.Instance.Header = header;
|
||||
}
|
||||
Settings.Instance.CustomSettings.Add("InternalConstructors", await GetValue<bool?>("use-internal-constructors") ?? false);
|
||||
Settings.Instance.CustomSettings.Add("SyncMethods", await GetValue("sync-methods") ?? "essential");
|
||||
Settings.Instance.CustomSettings.Add("UseDateTimeOffset", await GetValue<bool?>("use-datetimeoffset") ?? false);
|
||||
Settings.Instance.CustomSettings.Add("InternalConstructors", GetXmsCodeGenSetting<bool?>(sd, "internalConstructors") ?? await GetValue<bool?>("use-internal-constructors") ?? false);
|
||||
Settings.Instance.CustomSettings.Add("SyncMethods", GetXmsCodeGenSetting<string>(sd, "syncMethods") ?? await GetValue("sync-methods") ?? "essential");
|
||||
Settings.Instance.CustomSettings.Add("UseDateTimeOffset", GetXmsCodeGenSetting<bool?>(sd, "useDateTimeOffset") ?? await GetValue<bool?>("use-datetimeoffset") ?? false);
|
||||
if (codeGenerator == "ruby" || codeGenerator == "python")
|
||||
{
|
||||
// TODO: sort out matters here entirely instead of relying on Input being read somewhere...
|
||||
|
@ -65,12 +91,6 @@ public class Generator : NewPlugin
|
|||
}
|
||||
|
||||
// process
|
||||
var files = await ListInputs();
|
||||
if (files.Length != 2)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var plugin = ExtensionsLoader.GetPlugin(
|
||||
(await GetValue<bool?>("azure-arm") ?? false ? "Azure." : "") +
|
||||
language +
|
||||
|
|
|
@ -638,9 +638,8 @@ task 'regenerate-samples', '', (done) ->
|
|||
(find path.join(each.path, ".."))
|
||||
.filter((file) -> file.match(/.(map|txt)$/))
|
||||
.forEach((file) ->
|
||||
sed "-i", /\bfile:\/\/[^\s]*\/autorest/g, "", file # blame locations
|
||||
sed "-i", /(at .* in )([^\s]*(\/|\\))/g, "$1", file # exception stack traces (.cs)
|
||||
sed "-i", /at .* \(.*\)/g, "at ...", file # exception stack traces (.ts)
|
||||
sed "-i", /\bfile:\/\/[^\s]*\/autorest[^\/\\]*/g, "", file # blame locations
|
||||
sed "-i", /\sat .*/g, "at ...", file # exception stack traces
|
||||
)
|
||||
next null
|
||||
, true # don't fail on failures (since we wanna record them)
|
||||
|
|
|
@ -56,23 +56,6 @@ namespace AutoRest.Swagger.Tests
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that raising the version number does not result in a strict comparison.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void UpdatedMajorVersionNumberNotStrict()
|
||||
{
|
||||
var messages = CompareSwagger("version_check_01.json").ToArray();
|
||||
Assert.NotEmpty(messages.Where(m => m.Id > 0 && m.Severity == Category.Warning));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void UpdatedMinorVersionNumberNotStrict()
|
||||
{
|
||||
var messages = CompareSwagger("version_check_03.json").ToArray();
|
||||
Assert.NotEmpty(messages.Where(m => m.Id > 0 && m.Severity == Category.Warning));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that not raising the version number results in a strict comparison.
|
||||
/// </summary>
|
||||
|
@ -96,18 +79,6 @@ namespace AutoRest.Swagger.Tests
|
|||
Assert.Equal(Category.Error, reversed.First().Severity);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that if you remove a supported protocol when updating the specification, it's caught.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void ProtocolMissing()
|
||||
{
|
||||
var messages = CompareSwagger("version_check_01.json").ToArray();
|
||||
var missing = messages.Where(m => m.Id == ComparisonMessages.ProtocolNoLongerSupported.Id);
|
||||
Assert.NotEmpty(missing);
|
||||
Assert.Equal(Category.Warning, missing.First().Severity);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that if you remove a supported request body format, it's caught.
|
||||
/// </summary>
|
||||
|
|
|
@ -33,8 +33,6 @@ namespace AutoRest.Swagger
|
|||
{
|
||||
throw new ArgumentNullException("settings");
|
||||
}
|
||||
|
||||
DefaultProtocol = TransferProtocolScheme.Http;
|
||||
}
|
||||
|
||||
public override string Name
|
||||
|
@ -52,11 +50,6 @@ namespace AutoRest.Swagger
|
|||
/// </summary>
|
||||
public CodeModel CodeModel { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Default protocol when no protocol is specified in the schema
|
||||
/// </summary>
|
||||
public TransferProtocolScheme DefaultProtocol { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Builds service model from swagger file.
|
||||
/// </summary>
|
||||
|
@ -242,14 +235,6 @@ namespace AutoRest.Swagger
|
|||
CodeModel.ModelsName = Settings.ModelsName;
|
||||
CodeModel.ApiVersion = ServiceDefinition.Info.Version;
|
||||
CodeModel.Documentation = ServiceDefinition.Info.Description;
|
||||
if (ServiceDefinition.Schemes == null || ServiceDefinition.Schemes.Count != 1)
|
||||
{
|
||||
ServiceDefinition.Schemes = new List<TransferProtocolScheme> { DefaultProtocol };
|
||||
}
|
||||
if (string.IsNullOrEmpty(ServiceDefinition.Host))
|
||||
{
|
||||
ServiceDefinition.Host = "localhost";
|
||||
}
|
||||
CodeModel.BaseUrl = string.Format(CultureInfo.InvariantCulture, "{0}://{1}{2}",
|
||||
ServiceDefinition.Schemes[0].ToString().ToLower(),
|
||||
ServiceDefinition.Host, ServiceDefinition.BasePath);
|
||||
|
|
|
@ -168,6 +168,14 @@ namespace AutoRest.Swagger
|
|||
Uri filePath = null;
|
||||
Uri.TryCreate(path, UriKind.RelativeOrAbsolute, out filePath);
|
||||
swaggerService.FilePath = filePath;
|
||||
if (swaggerService.Schemes == null || swaggerService.Schemes.Count != 1)
|
||||
{
|
||||
swaggerService.Schemes = new List<TransferProtocolScheme> { TransferProtocolScheme.Http };
|
||||
}
|
||||
if (string.IsNullOrEmpty(swaggerService.Host))
|
||||
{
|
||||
swaggerService.Host = "localhost";
|
||||
}
|
||||
return swaggerService;
|
||||
}
|
||||
catch (JsonException ex)
|
||||
|
|
Загрузка…
Ссылка в новой задаче