private int Scaffold( ScaffoldOptions settings, ScaffoldInterceptors?interceptors, string provider, string?providerLocation, string connectionString, string?additionalConnectionString, string output, bool overwrite) { using var dc = GetConnection(provider, providerLocation, connectionString, additionalConnectionString, out var secondaryConnection); using var sdc = secondaryConnection; if (dc == null) { return(StatusCodes.EXPECTED_ERROR); } var language = LanguageProviders.CSharp; var legacyProvider = new LegacySchemaProvider(dc, settings.Schema, language); ISchemaProvider schemaProvider = legacyProvider; ITypeMappingProvider typeMappingsProvider = legacyProvider; if (sdc != null) { var secondLegacyProvider = new LegacySchemaProvider(sdc, settings.Schema, language); schemaProvider = new MergedAccessSchemaProvider(legacyProvider, secondLegacyProvider); typeMappingsProvider = new AggregateTypeMappingsProvider(legacyProvider, secondLegacyProvider); } var generator = new Scaffolder(LanguageProviders.CSharp, HumanizerNameConverter.Instance, settings, interceptors); var dataModel = generator.LoadDataModel(schemaProvider, typeMappingsProvider); var sqlBuilder = dc.DataProvider.CreateSqlBuilder(dc.MappingSchema); var files = generator.GenerateCodeModel( sqlBuilder, dataModel, MetadataBuilders.GetAttributeBasedMetadataBuilder(generator.Language, sqlBuilder), SqlBoolEqualityConverter.Create(generator.Language)); var sourceCode = generator.GenerateSourceCode(files); Directory.CreateDirectory(output); for (var i = 0; i < sourceCode.Length; i++) { // TODO: add file name normalization/deduplication? var fileName = Path.Combine(output, sourceCode[i].FileName); if (File.Exists(fileName) && !overwrite) { Console.WriteLine($"File '{fileName}' already exists. Specify '--overwrite true' option if you want to ovrerwrite existing files"); return(StatusCodes.EXPECTED_ERROR); } File.WriteAllText(fileName, sourceCode[i].Code); } return(StatusCodes.SUCCESS); }
/// <summary> /// Configure scaffolder options object. /// </summary> /// <param name="options">CLI options.</param> /// <returns>Scaffold settings or <c>null</c> on error.</returns> private static ScaffoldOptions?ProcessScaffoldOptions(Dictionary <CliOption, object?> options) { ScaffoldOptions settings; // before reading other options load base settings object if (options.Remove(General.OptionsTemplate, out var value) && value is "t4") { settings = ScaffoldOptions.T4(); } else { settings = ScaffoldOptions.Default(); } // process scaffold options ProcessSchemaOptions(options, settings.Schema); ProcessDataModelOptions(options, settings.DataModel); ProcessCodeGenOptions(options, settings.CodeGeneration); return(settings); }
/// <summary> /// Loads interceptors from assembly from specified path. /// </summary> /// <param name="assemblyPath">Path to assembly with interceptors.</param> /// <returns>Status of operation and loaded interceptors (on failure).</returns> private (int resultCode, ScaffoldInterceptors?interceptors) LoadInterceptorsFromAssembly(string assemblyPath, ScaffoldOptions options) { // as loaded assembly could have additional sideload references, we should try to handle them var assemblyFolder = Path.GetDirectoryName(Path.GetFullPath(assemblyPath)) !; // try to load side-assemblies from same folder // TODO: Verbose logging Console.WriteLine($"AssemblyResolve path: {assemblyFolder}"); Assembly assembly; try { assembly = Assembly.LoadFrom(assemblyPath); } catch (Exception ex) { Console.Error.WriteLine($"Failed to load assembly with interceptors from '{assemblyPath}': {ex}"); return(StatusCodes.INVALID_ARGUMENTS, null); } SetupInterceptorsDependencyResolver(assemblyFolder, assembly); return(LoadInterceptorsFromAssembly(assemblyPath, assembly, options)); }
/// <summary> /// Load interceptors from file at provided path. It could be assembly with interceptors if path must ends with .dll extension /// or T4 template otherwise. /// </summary> /// <param name="interceptorsPath">Path to interceptors file.</param> /// <returns>Method execution status and interceptors instance on success.</returns> private (int resultCode, ScaffoldInterceptors?interceptors) LoadInterceptors(string interceptorsPath, ScaffoldOptions options) { if (Path.GetExtension(interceptorsPath).Equals(".dll", StringComparison.OrdinalIgnoreCase)) { return(LoadInterceptorsFromAssembly(interceptorsPath, options)); } return(LoadInterceptorsFromT4(interceptorsPath, options)); }
/// <summary> /// Compile and execute T4 template, provided by user. /// </summary> /// <param name="t4templatePath">Path to T4 template.</param> /// <returns>Template processing status and interceptors instance on success.</returns> private (int resultCode, ScaffoldInterceptors?interceptors) LoadInterceptorsFromT4(string t4templatePath, ScaffoldOptions options) { // load template source and assembly references from T4 file var status = PreprocessTemplate(t4templatePath, out var refs, out var templateCode, out var imports); if (status != StatusCodes.SUCCESS) { return(status, null); } // compile template and load interceptors assembly (status, var assembly) = CompileTemplateAndLoadAssembly(templateCode, refs, imports); if (status != StatusCodes.SUCCESS) { return(status, null); } // instantiate interceptors instance return(LoadInterceptorsFromAssembly(t4templatePath, assembly !, options)); }
/// <summary> /// Locate and create instance of interceptors from <paramref name="assembly"/>. /// </summary> /// <param name="sourcePath">Interceptors source path (T4 template path or assembly path) for logging purposes.</param> /// <param name="assembly">Assembly with interceptors class.</param> /// <returns>Method execution status and interceptors instance on success.</returns> private static (int resultCode, ScaffoldInterceptors?interceptors) LoadInterceptorsFromAssembly(string sourcePath, Assembly assembly, ScaffoldOptions options) { Type?interceptorsType = null; foreach (var type in assembly.GetTypes()) { if (Inherits(type, typeof(ScaffoldInterceptors))) { // only one interceptors class allowed if (interceptorsType != null) { Console.Error.WriteLine($"'{sourcePath}' contains multiple interceptor types: {interceptorsType}, {interceptorsType}"); return(StatusCodes.EXPECTED_ERROR, null); } interceptorsType = type; } } // interceptors class not found? if (interceptorsType == null) { Console.Error.WriteLine($"Cannot find interceptor class in '{sourcePath}'"); return(StatusCodes.EXPECTED_ERROR, null); } // try options constructor first object[]? args = null; var ctor = interceptorsType.GetConstructor(new[] { typeof(ScaffoldOptions) }); if (ctor == null) { // try default constructor ctor = interceptorsType.GetConstructor(Array.Empty <Type>()); } else { args = new[] { options }; } if (ctor == null) { Console.Error.WriteLine($"Interceptor class '{interceptorsType}' missing default constrtuctor"); return(StatusCodes.EXPECTED_ERROR, null); } try { return(StatusCodes.SUCCESS, (ScaffoldInterceptors)Activator.CreateInstance(interceptorsType, args) !); } catch (Exception ex) { Console.Error.WriteLine($"Failed to create instance of interceptor '{interceptorsType}': {ex}"); return(StatusCodes.EXPECTED_ERROR, null); } }