using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Web.Hosting; using Orchard.Commands; using Orchard.Data.Migration.Generator; using Orchard.CodeGeneration.Services; using Orchard.Data.Migration.Schema; using Orchard.Environment.Extensions; using Orchard.Environment.Extensions.Models; namespace Orchard.CodeGeneration.Commands { [OrchardFeature("Generate")] public class CodeGenerationCommands : DefaultOrchardCommandHandler { private readonly IExtensionManager _extensionManager; private readonly ISchemaCommandGenerator _schemaCommandGenerator; private const string ModuleName = "CodeGeneration"; public CodeGenerationCommands( IExtensionManager extensionManager, ISchemaCommandGenerator schemaCommandGenerator) { _extensionManager = extensionManager; _schemaCommandGenerator = schemaCommandGenerator; } [OrchardSwitch] public bool IncludeInSolution { get; set; } [CommandHelp("generate create datamigration \r\n\t" + "Create a new Data Migration class")] [CommandName("generate create datamigration")] public void CreateDataMigration(string featureName) { Context.Output.WriteLine(T("Creating Data Migration for {0}", featureName)); ExtensionDescriptor extensionDescriptor = _extensionManager.AvailableExtensions().FirstOrDefault(extension => extension.ExtensionType == "Module" && extension.Features.Any(feature => String.Equals(feature.Name, featureName, StringComparison.OrdinalIgnoreCase))); if (extensionDescriptor == null) { Context.Output.WriteLine(T("Creating data migration failed: target Feature {0} could not be found.", featureName)); return; } string dataMigrationsPath = HostingEnvironment.MapPath("~/Modules/" + extensionDescriptor.Name + "/DataMigrations/"); string dataMigrationPath = dataMigrationsPath + extensionDescriptor.DisplayName + "DataMigration.cs"; string templatesPath = HostingEnvironment.MapPath("~/Modules/Orchard." + ModuleName + "/CodeGenerationTemplates/"); string moduleCsProjPath = HostingEnvironment.MapPath(string.Format("~/Modules/{0}/{0}.csproj", extensionDescriptor.Name)); if (!Directory.Exists(dataMigrationsPath)) { Directory.CreateDirectory(dataMigrationsPath); } if (File.Exists(dataMigrationPath)) { Context.Output.WriteLine(T("Data migration already exists in target Module {0}.", extensionDescriptor.Name)); return; } List commands = _schemaCommandGenerator.GetCreateFeatureCommands(featureName, false).ToList(); var stringWriter = new StringWriter(); var interpreter = new CodeGenerationCommandInterpreter(stringWriter); foreach (var command in commands) { interpreter.Visit(command); stringWriter.WriteLine(); } string dataMigrationText = File.ReadAllText(templatesPath + "DataMigration.txt"); dataMigrationText = dataMigrationText.Replace("$$FeatureName$$", featureName); dataMigrationText = dataMigrationText.Replace("$$ClassName$$", extensionDescriptor.DisplayName); dataMigrationText = dataMigrationText.Replace("$$Commands$$", stringWriter.ToString()); File.WriteAllText(dataMigrationPath, dataMigrationText); string projectFileText = File.ReadAllText(moduleCsProjPath); // The string searches in solution/project files can be made aware of comment lines. if ( projectFileText.Contains("\r\n ", "DataMigrations\\" + extensionDescriptor.DisplayName + "DataMigration.cs"); projectFileText = projectFileText.Insert(projectFileText.LastIndexOf("\r\n \r\n \r\n ", "DataMigrations\\" + extensionDescriptor.DisplayName + "DataMigration.cs"); projectFileText = projectFileText.Insert(projectFileText.LastIndexOf(""), itemGroupReference); } File.WriteAllText(moduleCsProjPath, projectFileText); TouchSolution(); Context.Output.WriteLine(T("Data migration created successfully in Module {0}", extensionDescriptor.Name)); } [CommandHelp("generate create module [/IncludeInSolution:true|false]\r\n\t" + "Create a new Orchard module")] [CommandName("generate create module")] [OrchardSwitches("IncludeInSolution")] public void CreateModule(string moduleName) { Context.Output.WriteLine(T("Creating Module {0}", moduleName)); if ( _extensionManager.AvailableExtensions().Any(extension => extension.ExtensionType == "Module" && String.Equals(moduleName, extension.DisplayName, StringComparison.OrdinalIgnoreCase)) ) { Context.Output.WriteLine(T("Creating Module {0} failed: a module of the same name already exists", moduleName)); return; } IntegrateModule(moduleName); Context.Output.WriteLine(T("Module {0} created successfully", moduleName)); } [CommandHelp("generate create controller \r\n\t" + "Create a new Orchard controller in a module")] [CommandName("generate create controller")] public void CreateController(string moduleName, string controllerName) { Context.Output.WriteLine(T("Creating Controller {0} in Module {1}", controllerName, moduleName)); ExtensionDescriptor extensionDescriptor = _extensionManager.AvailableExtensions().FirstOrDefault(extension => extension.ExtensionType == "Module" && string.Equals(moduleName, extension.DisplayName, StringComparison.OrdinalIgnoreCase)); if (extensionDescriptor == null) { Context.Output.WriteLine(T("Creating Controller {0} failed: target Module {1} could not be found.", controllerName, moduleName)); return; } string moduleControllersPath = HostingEnvironment.MapPath("~/Modules/" + extensionDescriptor.Name + "/Controllers/"); string controllerPath = moduleControllersPath + controllerName + ".cs"; string moduleCsProjPath = HostingEnvironment.MapPath(string.Format("~/Modules/{0}/{0}.csproj", extensionDescriptor.Name)); string templatesPath = HostingEnvironment.MapPath("~/Modules/Orchard." + ModuleName + "/CodeGenerationTemplates/"); if (!Directory.Exists(moduleControllersPath)) { Directory.CreateDirectory(moduleControllersPath); } if (File.Exists(controllerPath)) { Context.Output.WriteLine(T("Controller {0} already exists in target Module {1}.", controllerName, moduleName)); return; } string controllerText = File.ReadAllText(templatesPath + "Controller.txt"); controllerText = controllerText.Replace("$$ModuleName$$", moduleName); controllerText = controllerText.Replace("$$ControllerName$$", controllerName); File.WriteAllText(controllerPath, controllerText); string projectFileText = File.ReadAllText(moduleCsProjPath); // The string searches in solution/project files can be made aware of comment lines. if (projectFileText.Contains("\r\n ", "Controllers\\" + controllerName + ".cs"); projectFileText = projectFileText.Insert(projectFileText.LastIndexOf("\r\n \r\n \r\n ", "Controllers\\" + controllerName + ".cs"); projectFileText = projectFileText.Insert(projectFileText.LastIndexOf(""), itemGroupReference); } File.WriteAllText(moduleCsProjPath, projectFileText); Context.Output.WriteLine(T("Controller {0} created successfully in Module {1}", controllerName, moduleName)); TouchSolution(); } private void IntegrateModule(string moduleName) { string rootWebProjectPath = HostingEnvironment.MapPath("~/Orchard.Web.csproj"); string projectGuid = Guid.NewGuid().ToString().ToUpper(); CreateFilesFromTemplates(moduleName, projectGuid); // The string searches in solution/project files can be made aware of comment lines. if (IncludeInSolution) { // Add project to Orchard.sln string solutionPath = Directory.GetParent(rootWebProjectPath).Parent.FullName + "\\Orchard.sln"; if (File.Exists(solutionPath)) { string projectReference = string.Format( "EndProject\r\nProject(\"{{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}}\") = \"{0}\", \"Orchard.Web\\Modules\\{0}\\{0}.csproj\", \"{{{1}}}\"\r\n", moduleName, projectGuid); string projectConfiguationPlatforms = string.Format( "GlobalSection(ProjectConfigurationPlatforms) = postSolution\r\n\t\t{{{0}}}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\r\n\t\t{{{0}}}.Debug|Any CPU.Build.0 = Debug|Any CPU\r\n\t\t{{{0}}}.Release|Any CPU.ActiveCfg = Release|Any CPU\r\n\t\t{{{0}}}.Release|Any CPU.Build.0 = Release|Any CPU\r\n", projectGuid); string solutionText = File.ReadAllText(solutionPath); solutionText = solutionText.Insert(solutionText.LastIndexOf("EndProject\r\n"), projectReference); solutionText = solutionText.Replace("GlobalSection(ProjectConfigurationPlatforms) = postSolution\r\n", projectConfiguationPlatforms); solutionText = solutionText.Insert(solutionText.LastIndexOf("EndGlobalSection"), "\t{" + projectGuid + "} = {E9C9F120-07BA-4DFB-B9C3-3AFB9D44C9D5}\r\n\t"); File.WriteAllText(solutionPath, solutionText); TouchSolution(); } else { Context.Output.WriteLine(T("Warning: Solution file could not be found at {0}", solutionPath)); } } } private static void CreateFilesFromTemplates(string moduleName, string projectGuid) { string modulePath = HostingEnvironment.MapPath("~/Modules/" + moduleName + "/"); string propertiesPath = modulePath + "Properties"; string templatesPath = HostingEnvironment.MapPath("~/Modules/Orchard." + ModuleName + "/CodeGenerationTemplates/"); Directory.CreateDirectory(modulePath); Directory.CreateDirectory(propertiesPath); Directory.CreateDirectory(modulePath + "Controllers"); Directory.CreateDirectory(modulePath + "Views"); File.WriteAllText(modulePath + "\\Views\\Web.config", File.ReadAllText(templatesPath + "ViewsWebConfig.txt")); Directory.CreateDirectory(modulePath + "Models"); Directory.CreateDirectory(modulePath + "Scripts"); string templateText = File.ReadAllText(templatesPath + "ModuleAssemblyInfo.txt"); templateText = templateText.Replace("$$ModuleName$$", moduleName); templateText = templateText.Replace("$$ModuleTypeLibGuid$$", Guid.NewGuid().ToString()); File.WriteAllText(propertiesPath + "\\AssemblyInfo.cs", templateText); File.WriteAllText(modulePath + "\\Web.config", File.ReadAllText(templatesPath + "ModuleWebConfig.txt")); templateText = File.ReadAllText(templatesPath + "ModuleManifest.txt"); templateText = templateText.Replace("$$ModuleName$$", moduleName); File.WriteAllText(modulePath + "\\Module.txt", templateText); templateText = File.ReadAllText(templatesPath + "\\ModuleCsProj.txt"); templateText = templateText.Replace("$$ModuleName$$", moduleName); templateText = templateText.Replace("$$ModuleProjectGuid$$", projectGuid); File.WriteAllText(modulePath + "\\" + moduleName + ".csproj", templateText); } private void TouchSolution() { string rootWebProjectPath = HostingEnvironment.MapPath("~/Orchard.Web.csproj"); string solutionPath = Directory.GetParent(rootWebProjectPath).Parent.FullName + "\\Orchard.sln"; if (!File.Exists(solutionPath)) { Context.Output.WriteLine(T("Warning: Solution file could not be found at {0}", solutionPath)); return; } try { File.SetLastWriteTime(solutionPath, DateTime.Now); } catch { Context.Output.WriteLine(T("An unexpected error occured while trying to refresh the Visual Studio solution. Please reload it.")); } } } }