231 lines
5.9 KiB
C#
231 lines
5.9 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using EnvDTE;
|
|
using EnvDTE80;
|
|
using Microsoft.VisualStudio.TemplateWizard;
|
|
|
|
namespace Matrix42.Extensions.Scaffolder.Wizard
|
|
{
|
|
public class ExtensionProjectsWizard : IWizard
|
|
{
|
|
private DTE2 _dte;
|
|
private Project _placeholderProject;
|
|
private string _extensionNamespace = string.Empty;
|
|
private List<ProjectDefinition> _projects = new List<ProjectDefinition>();
|
|
private string _solutionDirectory = string.Empty;
|
|
|
|
public void RunStarted(
|
|
object automationObject,
|
|
Dictionary<string, string> replacementsDictionary,
|
|
WizardRunKind runKind,
|
|
object[] customParams)
|
|
{
|
|
_dte = automationObject as DTE2
|
|
?? throw new InvalidOperationException("DTE2 not available.");
|
|
|
|
using (var form = new WizardForm())
|
|
{
|
|
var result = form.ShowDialog();
|
|
if (result != System.Windows.Forms.DialogResult.OK)
|
|
throw new WizardBackoutException();
|
|
|
|
_extensionNamespace = form.ExtensionNamespace;
|
|
_projects = new List<ProjectDefinition>(form.Projects);
|
|
}
|
|
}
|
|
|
|
// 🔹 This is the method that was missing
|
|
public void BeforeOpeningFile(ProjectItem projectItem)
|
|
{
|
|
// We don't need to do anything before a file is opened.
|
|
// Leave empty on purpose.
|
|
}
|
|
|
|
public void ProjectFinishedGenerating(Project project)
|
|
{
|
|
_placeholderProject = project;
|
|
}
|
|
|
|
public void ProjectItemFinishedGenerating(ProjectItem projectItem)
|
|
{
|
|
}
|
|
|
|
public void RunFinished()
|
|
{
|
|
var solution = _dte.Solution;
|
|
_solutionDirectory = Path.GetDirectoryName(solution.FullName);
|
|
|
|
if (string.IsNullOrEmpty(_solutionDirectory))
|
|
return;
|
|
|
|
// Remove placeholder project from solution and disk
|
|
if (_placeholderProject != null)
|
|
{
|
|
var placeholderPath = _placeholderProject.FullName;
|
|
solution.Remove(_placeholderProject);
|
|
TryDeleteDirectorySafe(Path.GetDirectoryName(placeholderPath));
|
|
}
|
|
|
|
// Drop Directory.Build.props
|
|
var propsTemplatePath = Path.Combine(
|
|
GetExtensionInstallPath(),
|
|
"ProjectTemplates",
|
|
"Directory.Build.props.template");
|
|
|
|
if (File.Exists(propsTemplatePath))
|
|
{
|
|
var destProps = Path.Combine(_solutionDirectory, "Directory.Build.props");
|
|
if (!File.Exists(destProps))
|
|
File.Copy(propsTemplatePath, destProps, overwrite: false);
|
|
}
|
|
|
|
foreach (var proj in _projects)
|
|
{
|
|
CreateProjectFromDefinition(solution, proj);
|
|
}
|
|
}
|
|
|
|
public bool ShouldAddProjectItem(string filePath) => true;
|
|
|
|
private void CreateProjectFromDefinition(Solution solution, ProjectDefinition def)
|
|
{
|
|
var projectName = def.GetProjectName(_extensionNamespace);
|
|
var projectNamespace = def.GetNamespace(_extensionNamespace);
|
|
var projectDir = Path.Combine(_solutionDirectory, projectName);
|
|
|
|
Directory.CreateDirectory(projectDir);
|
|
|
|
var csprojPath = Path.Combine(projectDir, projectName + ".csproj");
|
|
var runtimeIds = def.GetRuntimeIdentifiers();
|
|
var tfm = "net8.0"; // default target framework
|
|
|
|
var csprojContent = GenerateCsproj(def.Type, tfm, runtimeIds, projectNamespace);
|
|
File.WriteAllText(csprojPath, csprojContent);
|
|
|
|
var codeFilePath = Path.Combine(
|
|
projectDir,
|
|
def.Type == ProjectType.WebApi ? "Program.cs" : "Class1.cs");
|
|
|
|
var codeContent = GenerateCodeFile(def.Type, projectNamespace);
|
|
File.WriteAllText(codeFilePath, codeContent);
|
|
|
|
solution.AddFromFile(csprojPath);
|
|
}
|
|
|
|
private string GenerateCsproj(
|
|
ProjectType type,
|
|
string tfm,
|
|
string runtimeIds,
|
|
string rootNamespace)
|
|
{
|
|
var outputType = type == ProjectType.WebApi ? "Exe" : "Library";
|
|
var sdk = type == ProjectType.WebApi ? "Microsoft.NET.Sdk.Web" : "Microsoft.NET.Sdk";
|
|
|
|
var ridBlock = string.IsNullOrWhiteSpace(runtimeIds)
|
|
? string.Empty
|
|
: $" <RuntimeIdentifiers>{runtimeIds}</RuntimeIdentifiers>{Environment.NewLine}";
|
|
|
|
return
|
|
$@"<Project Sdk=""{sdk}"">
|
|
<PropertyGroup>
|
|
<TargetFramework>{tfm}</TargetFramework>
|
|
<OutputType>{outputType}</OutputType>
|
|
<RootNamespace>{rootNamespace}</RootNamespace>
|
|
</PropertyGroup>
|
|
|
|
<PropertyGroup>
|
|
{ridBlock} </PropertyGroup>
|
|
|
|
<ItemGroup>
|
|
<PackageReference Include=""Matrix42.Extensions.SDK"" Version=""1.0.0"" />
|
|
</ItemGroup>
|
|
</Project>
|
|
";
|
|
}
|
|
|
|
private string GenerateCodeFile(ProjectType type, string ns)
|
|
{
|
|
switch (type)
|
|
{
|
|
case ProjectType.WebApi:
|
|
return
|
|
$@"using Microsoft.AspNetCore.Builder;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using Microsoft.Extensions.Hosting;
|
|
using Matrix42.Extensions.SDK;
|
|
|
|
namespace {ns}
|
|
{{
|
|
public class Program
|
|
{{
|
|
public static void Main(string[] args)
|
|
{{
|
|
var builder = WebApplication.CreateBuilder(args);
|
|
|
|
builder.Services.AddControllers();
|
|
// TODO: configure Matrix42.Extensions.SDK services
|
|
|
|
var app = builder.Build();
|
|
app.MapControllers();
|
|
|
|
app.Run();
|
|
}}
|
|
}}
|
|
}}";
|
|
case ProjectType.Contracts:
|
|
return
|
|
$@"namespace {ns}
|
|
{{
|
|
// Place your contracts (DTOs, interfaces) here
|
|
public class SampleContract
|
|
{{
|
|
public string Id {{ get; set; }} = string.Empty;
|
|
}}
|
|
}}";
|
|
case ProjectType.BizLogic:
|
|
return
|
|
$@"using Matrix42.Extensions.SDK;
|
|
|
|
namespace {ns}
|
|
{{
|
|
// Place your business logic services here
|
|
public class SampleService
|
|
{{
|
|
public string SayHello() => ""Hello from {ns}"";
|
|
}}
|
|
}}";
|
|
case ProjectType.Custom:
|
|
default:
|
|
return
|
|
$@"namespace {ns}
|
|
{{
|
|
// Custom project for your extension
|
|
public class CustomEntry
|
|
{{
|
|
public string Name {{ get; set; }} = ""Custom"";
|
|
}}
|
|
}}";
|
|
}
|
|
}
|
|
|
|
private string GetExtensionInstallPath()
|
|
{
|
|
var asmPath = typeof(ExtensionProjectsWizard).Assembly.Location;
|
|
return Path.GetDirectoryName(asmPath);
|
|
}
|
|
|
|
private void TryDeleteDirectorySafe(string path)
|
|
{
|
|
try
|
|
{
|
|
if (!string.IsNullOrWhiteSpace(path) && Directory.Exists(path))
|
|
Directory.Delete(path, recursive: true);
|
|
}
|
|
catch
|
|
{
|
|
// ignore
|
|
}
|
|
}
|
|
}
|
|
} |