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:
Johannes Bader 2017-04-27 10:20:30 -07:00 коммит произвёл GitHub
Родитель 0b57a801da
Коммит 6348004f94
18 изменённых файлов: 208 добавлений и 301 удалений

Просмотреть файл

@ -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)