232 lines
7.5 KiB
C#
232 lines
7.5 KiB
C#
using Matrix42.Extensions.Scaffolder.Core.ProjectGenerators;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
|
|
namespace Matrix42.Extensions.Scaffolder.Core;
|
|
|
|
public sealed class ExtensionScaffolder : IExtensionScaffolder
|
|
{
|
|
private readonly DefaultProjectGenerator _projectGenerator = new();
|
|
|
|
public IReadOnlyList<string> Generate(ExtensionScaffoldingOptions options)
|
|
{
|
|
if (options is null)
|
|
throw new ArgumentNullException(nameof(options));
|
|
|
|
|
|
if (string.IsNullOrWhiteSpace(options.ExtensionPath)) throw new ArgumentException("ExtensionPath must be set.", nameof(options));
|
|
|
|
if (string.IsNullOrWhiteSpace(options.ExtensionNamespace)) throw new ArgumentException("ExtensionNamespace must be set.", nameof(options));
|
|
|
|
if (options.Projects == null) throw new ArgumentException("Projects must be set.", nameof(options));
|
|
|
|
var result = new List<string>();
|
|
|
|
PrepareRootStructure(options);
|
|
PrepareBasePackage(options);
|
|
var solutionDir = PrepareSolutionFolder(options);
|
|
PrepareRootArtifacts(options);
|
|
PrepareSolutionFiles(options, solutionDir);
|
|
|
|
foreach (var def in options.Projects)
|
|
{
|
|
var csprojPath = _projectGenerator.GenerateProject(options, def);
|
|
result.Add(csprojPath);
|
|
}
|
|
|
|
GenerateSolutionFile(options, solutionDir, result);
|
|
|
|
return result;
|
|
}
|
|
|
|
private void PrepareRootStructure(ExtensionScaffoldingOptions options)
|
|
{
|
|
Directory.CreateDirectory(options.ExtensionPath);
|
|
}
|
|
|
|
private void PrepareBasePackage(ExtensionScaffoldingOptions options)
|
|
{
|
|
var basePackageDir = Path.Combine(options.ExtensionPath, "BasePackage");
|
|
Directory.CreateDirectory(basePackageDir);
|
|
|
|
var packageJsonPath = Path.Combine(basePackageDir, "package.json");
|
|
if (!File.Exists(packageJsonPath))
|
|
{
|
|
var json = GetDefaultPackageJson(options);
|
|
File.WriteAllText(packageJsonPath, json);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates /Solutions/{ns} and returns that path (solution-level folder).
|
|
/// </summary>
|
|
private string PrepareSolutionFolder(ExtensionScaffoldingOptions options)
|
|
{
|
|
var solutionDir = Path.Combine(options.ExtensionPath, "Solutions", options.ExtensionNamespace);
|
|
Directory.CreateDirectory(solutionDir);
|
|
return solutionDir;
|
|
}
|
|
|
|
private void PrepareRootArtifacts(ExtensionScaffoldingOptions options)
|
|
{
|
|
/*var azurePath = Path.Combine(options.ExtensionPath, "azure-pipelines-ci.yml");
|
|
if (!File.Exists(azurePath))
|
|
{
|
|
File.WriteAllText(azurePath, Templates.AzurePipelinesYml);
|
|
}*/
|
|
|
|
var azurePath = Path.Combine(options.ExtensionPath, "azure-pipelines-ci.yaml");
|
|
if (!File.Exists(azurePath))
|
|
{
|
|
var repoName = new DirectoryInfo(options.ExtensionPath).Name;
|
|
|
|
var content = Templates.GetAzurePiplineCi();
|
|
var replacedContent = content.Replace("{repoName}", repoName).Replace("{ns}", options.ExtensionNamespace);
|
|
File.WriteAllText(azurePath, replacedContent);
|
|
}
|
|
|
|
var gitignorePath = Path.Combine(options.ExtensionPath, ".gitignore");
|
|
if (!File.Exists(gitignorePath))
|
|
{
|
|
File.WriteAllText(gitignorePath, Templates.Gitignore);
|
|
}
|
|
|
|
/*var veracodePath = Path.Combine(options.ExtensionPath, "PrepareVeracodeScan.cmd");
|
|
if (!File.Exists(veracodePath))
|
|
{
|
|
var content = Templates.PrepareVeracodeScanCmd.Replace("{ns}", options.ExtensionNamespace);
|
|
File.WriteAllText(veracodePath, content);
|
|
}*/
|
|
|
|
var targetsPath = Path.Combine(options.ExtensionPath, "Extension.Assemblies.targets");
|
|
if (!File.Exists(targetsPath))
|
|
{
|
|
var content = Templates.GetMatrix42AssembliesTargets();
|
|
File.WriteAllText(targetsPath, content);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Solution-level files that should live next to the .sln (e.g. BuildEvent.cmd).
|
|
/// </summary>
|
|
private void PrepareSolutionFiles(ExtensionScaffoldingOptions options, string solutionDir)
|
|
{
|
|
var buildEventPath = Path.Combine(solutionDir, "BuildEvent.cmd");
|
|
if (!File.Exists(buildEventPath))
|
|
{
|
|
var content = Templates.BuildEventCmdTemplate.Replace("{ns}", options.ExtensionNamespace);
|
|
File.WriteAllText(buildEventPath, content);
|
|
}
|
|
|
|
// If later you want to actually create the .sln here (for console scenario),
|
|
// this is the right place as well.
|
|
}
|
|
|
|
private static string GetDefaultPackageJson(ExtensionScaffoldingOptions options) =>
|
|
$@"{{
|
|
""Id"": ""{options.ExtensionId}"",
|
|
""Vendor"": ""Not Specified"",
|
|
""Name"": ""{options.ExtensionNamespace}"",
|
|
""Version"": ""1.0"",
|
|
""Prerequisites"": {{
|
|
""MinimalRequiredProductVersion"": ""26.1.0"",
|
|
""DependentPackages"": []
|
|
}},
|
|
""SetupDirectives"": {{
|
|
""MaintenanceMode"": false,
|
|
""RecycleWebApplication"": false,
|
|
""RestartM42WindowsServices"": false
|
|
}},
|
|
""Sandboxed"": true
|
|
}}";
|
|
|
|
/// <summary>
|
|
/// Creates {ns}.sln under solutionDir and adds all csproj files to it.
|
|
/// </summary>
|
|
private void GenerateSolutionFile(
|
|
ExtensionScaffoldingOptions options,
|
|
string solutionDir,
|
|
IReadOnlyList<string> projectPaths)
|
|
{
|
|
if (projectPaths == null || projectPaths.Count == 0)
|
|
return;
|
|
|
|
var solutionName = options.ExtensionNamespace;
|
|
var slnPath = Path.Combine(solutionDir, solutionName + ".sln");
|
|
|
|
// Basic VS solution header
|
|
var lines = new List<string>();
|
|
lines.Add("Microsoft Visual Studio Solution File, Format Version 12.00");
|
|
lines.Add("# Visual Studio Version 17");
|
|
lines.Add("VisualStudioVersion = 17.0.31912.275");
|
|
lines.Add("MinimumVisualStudioVersion = 10.0.40219.1");
|
|
|
|
// C# project type GUID
|
|
const string csProjTypeGuid = "{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}";
|
|
|
|
// Collect project GUIDs
|
|
var projectEntries = new List<Tuple<string, string, string>>();
|
|
// (projGuid, projName, relativePath)
|
|
|
|
foreach (var projPath in projectPaths)
|
|
{
|
|
var projName = Path.GetFileNameWithoutExtension(projPath);
|
|
var relativePath = GetRelativePath(solutionDir, projPath);
|
|
var projGuid = "{" + Guid.NewGuid().ToString().ToUpperInvariant() + "}";
|
|
|
|
projectEntries.Add(Tuple.Create(projGuid, projName, relativePath));
|
|
|
|
lines.Add(string.Format(
|
|
"Project(\"{0}\") = \"{1}\", \"{2}\", \"{3}\"",
|
|
csProjTypeGuid,
|
|
projName,
|
|
relativePath,
|
|
projGuid));
|
|
lines.Add("EndProject");
|
|
}
|
|
|
|
// Global section (configs + project configs)
|
|
lines.Add("Global");
|
|
lines.Add("\tGlobalSection(SolutionConfigurationPlatforms) = preSolution");
|
|
lines.Add("\t\tDebug|Any CPU = Debug|Any CPU");
|
|
lines.Add("\t\tRelease|Any CPU = Release|Any CPU");
|
|
lines.Add("\tEndGlobalSection");
|
|
|
|
lines.Add("\tGlobalSection(ProjectConfigurationPlatforms) = postSolution");
|
|
foreach (var entry in projectEntries)
|
|
{
|
|
var guid = entry.Item1;
|
|
lines.Add(string.Format("\t\t{0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU", guid));
|
|
lines.Add(string.Format("\t\t{0}.Debug|Any CPU.Build.0 = Debug|Any CPU", guid));
|
|
lines.Add(string.Format("\t\t{0}.Release|Any CPU.ActiveCfg = Release|Any CPU", guid));
|
|
lines.Add(string.Format("\t\t{0}.Release|Any CPU.Build.0 = Release|Any CPU", guid));
|
|
}
|
|
lines.Add("\tEndGlobalSection");
|
|
|
|
lines.Add("\tGlobalSection(SolutionProperties) = preSolution");
|
|
lines.Add("\t\tHideSolutionNode = FALSE");
|
|
lines.Add("\tEndGlobalSection");
|
|
|
|
lines.Add("EndGlobal");
|
|
|
|
File.WriteAllLines(slnPath, lines);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Simple helper to get relative path from one folder to a file.
|
|
/// </summary>
|
|
private static string GetRelativePath(string basePath, string fullPath)
|
|
{
|
|
var baseUri = new Uri(AppendDirectorySeparatorChar(basePath));
|
|
var fullUri = new Uri(fullPath);
|
|
var relative = baseUri.MakeRelativeUri(fullUri).ToString();
|
|
|
|
return relative.Replace('/', Path.DirectorySeparatorChar);
|
|
}
|
|
|
|
private static string AppendDirectorySeparatorChar(string path)
|
|
{
|
|
return !path.EndsWith(Path.DirectorySeparatorChar.ToString()) ? path + Path.DirectorySeparatorChar : path;
|
|
}
|
|
} |