Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Development add template engine mock fs adapter #471

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions cmf-cli/Commands/new/HelpCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ protected override List<string> GenerateArgs(IDirectoryInfo projectRoot, IDirect
projectRoot.FullName)
).Replace("\\", "/");

var requireModuleSES =
ExecutionContext.Instance.ProjectConfig.MESVersion >= new Version(11, 0, 0) &&
ExecutionContext.Instance.ProjectConfig.MESVersion < new Version(11, 2, 0);

args.AddRange(new[]
{
"--rootRelativePath", relativePathToRoot,
Expand All @@ -75,6 +79,7 @@ protected override List<string> GenerateArgs(IDirectoryInfo projectRoot, IDirect
"--esLintVersion", ExecutionContext.ServiceProvider.GetService<IDependencyVersionService>().Angular(ExecutionContext.Instance.ProjectConfig.MESVersion).ESLint,
"--tsesVersion", ExecutionContext.ServiceProvider.GetService<IDependencyVersionService>().Angular(ExecutionContext.Instance.ProjectConfig.MESVersion).TSESLint,
"--assetsPkgName", this.assetsPkgName,
"--requireModuleSES", requireModuleSES.ToString(),
"--dfPackageNamePascalCase", this.dfPackageNamePascalCase
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,12 @@
"description": "The custom assets package name",
"displayName": "Assets Package Name",
"replaces": "<%= $CLI_PARAM_CustomAssetsPackageName %>"
},
"requireModuleSES": {
"type": "parameter",
"datatype": "bool",
"description": "Some versions of MES require a specific dependency to be present on the package.json file",
"displayName": "Require Module SES"
}
},
"forms": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@
"mermaid": "^9.1.3",
"prismjs": "1.29.0",
"rxjs": "~7.8.0",
//#if (requireModuleSES)
"ses": "^1.4.1",
//#endif
"tslib": "^2.4.0",
"zone.js": "^<%= $CLI_PARAM_zoneVersion %>"
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
"enableI18nLegacyMessageIdFormat": false,
"strictInjectionParameters": true,
"strictInputAccessModifiers": true,
"strictTemplates": true
"strictTemplates": true,
"skipLibCheck": true
}
}
22 changes: 16 additions & 6 deletions core/Commands/TemplateCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,16 @@
using System.Threading.Tasks;
using Cmf.CLI.Core.Constants;
using Cmf.CLI.Core.Objects;
using Cmf.CLI.Core.Templating;
using Cmf.CLI.Utilities;
using Microsoft.TemplateEngine.Abstractions;
using Microsoft.TemplateEngine.Abstractions.PhysicalFileSystem;
using Microsoft.TemplateEngine.Abstractions.TemplatePackage;
using Microsoft.TemplateEngine.Edge;
using Microsoft.TemplateEngine.Edge.Template;
using Microsoft.TemplateEngine.IDE;
using Microsoft.TemplateEngine.Utils;
using Newtonsoft.Json;
using DefaultTemplateEngineHost = Microsoft.TemplateEngine.Edge.DefaultTemplateEngineHost;
using ExecutionContext = Cmf.CLI.Core.Objects.ExecutionContext;

namespace Cmf.CLI.Core.Commands
Expand Down Expand Up @@ -48,15 +49,15 @@ public abstract class TemplateCommand : BaseCommand
/// <param name="args">the template engine arguments</param>
public virtual void RunCommand(IReadOnlyCollection<string> args)
{
this.ExecuteTemplate(this.CommandName, args);
this.ExecuteTemplate(this.CommandName, args).Wait();
}

/// <summary>
/// execute a template
/// </summary>
/// <param name="templateName">the name of the template</param>
/// <param name="args">the template engine arguments</param>
protected async void ExecuteTemplate(string templateName, IReadOnlyCollection<string> args)
protected async Task ExecuteTemplate(string templateName, IReadOnlyCollection<string> args)
{
Log.Debug($"Going to generate template {templateName}");
// TODO: args needs to become a dictionary
Expand Down Expand Up @@ -108,7 +109,7 @@ protected async void ExecuteTemplate(string templateName, IReadOnlyCollection<st
var version = (Assembly.GetEntryAssembly() ?? Assembly.GetExecutingAssembly())
.GetCustomAttribute<AssemblyInformationalVersionAttribute>()
?.InformationalVersion;
var templateEngineHost = CreateHost(version);
var templateEngineHost = CreateHost(version, fileSystem);
using var bootstrapper = new Bootstrapper(templateEngineHost, false);

// this needs a refactor, right now we're minimizing the impact on the implemented commands
Expand Down Expand Up @@ -200,7 +201,7 @@ public Task<IReadOnlyList<ITemplatePackage>> GetAllTemplatePackagesAsync(Cancell
public string DisplayName => "CMF CLI templates";
}

private static ITemplateEngineHost CreateHost(string version)
private static ITemplateEngineHost CreateHost(string version, IFileSystem fileSystem)
{
var builtIns = new List<(Type InterfaceType, IIdentifiedComponent Instance)>();
builtIns.AddRange(Microsoft.TemplateEngine.Orchestrator.RunnableProjects.Components.AllComponents);
Expand All @@ -210,7 +211,16 @@ private static ITemplateEngineHost CreateHost(string version)
{
};

return new DefaultTemplateEngineHost(hostIdentifier: ExecutionContext.PackageId,
IPhysicalFileSystem templatingFileSystem = fileSystem switch
{
// trick to avoid the overhead of using the adapter when we are using the host file system anyway
// Should work the same as if we had passed it through the adapter, just with less overhead
FileSystem => new PhysicalFileSystem(),
_ => new IOAbstractionsFileSystem(fileSystem)
};

return new CmfCliTemplateEngineHost(templatingFileSystem,
hostIdentifier: ExecutionContext.PackageId,
version: version,
defaults: preferences,
builtIns: builtIns,
Expand Down
4 changes: 2 additions & 2 deletions core/Objects/CmfPackage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -547,9 +547,9 @@ public void LoadDependencies(IEnumerable<Uri> repoUris, StatusContext ctx, bool
}

IDirectoryInfo[] repoDirectories = repoUris?.Select(r => r.GetDirectory()).Where(d=> d.Exists==true).ToArray();
if (ExecutionContext.Instance.RunningOnWindows && repoDirectories.Length == 0)
if (ExecutionContext.Instance.RunningOnWindows && repoDirectories != null && repoDirectories.Length == 0)
{
throw new CliException($"None of the provided repositories exist: {string.Join(", ", repoUris.Select(d => d.OriginalString))}");
Log.Warning($"None of the provided repositories exist: {string.Join(", ", repoUris.Select(d => d.OriginalString))}");
}
foreach (var dependency in this.Dependencies)
{
Expand Down
90 changes: 90 additions & 0 deletions core/Templating/CmfCliTemplateEngineHost.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.TemplateEngine.Abstractions;
using Microsoft.TemplateEngine.Abstractions.PhysicalFileSystem;
using Microsoft.TemplateEngine.Utils;
using System;
using System.Collections.Generic;

namespace Cmf.CLI.Core.Templating
{
/// <summary>
/// Implementation of <see cref="ITemplateEngineHost"/>, based on the
/// <see cref="Microsoft.TemplateEngine.Edge.DefaultTemplateEngineHost"/>, with the difference that this
/// one allows passing an initial file system (that does not have to be the real <see cref="PhysicalFileSystem"/>).
/// </summary>
public class CmfCliTemplateEngineHost : ITemplateEngineHost
{
private static readonly IReadOnlyList<(Type, IIdentifiedComponent)> NoComponents = Array.Empty<(Type, IIdentifiedComponent)>();
private readonly IReadOnlyDictionary<string, string> _hostDefaults;
private readonly IReadOnlyList<(Type InterfaceType, IIdentifiedComponent Instance)> _hostBuiltInComponents;
private readonly ILoggerFactory _loggerFactory;
private readonly ILogger _logger;

public CmfCliTemplateEngineHost(
IPhysicalFileSystem fileSystem,
string hostIdentifier,
string version,
Dictionary<string, string> defaults = null,
IReadOnlyList<(Type InterfaceType, IIdentifiedComponent Instance)> builtIns = null,
IReadOnlyList<string> fallbackHostTemplateConfigNames = null,
ILoggerFactory loggerFactory = null)
{
HostIdentifier = hostIdentifier;
Version = version;
_hostDefaults = defaults ?? new Dictionary<string, string>();
FileSystem = fileSystem;
_hostBuiltInComponents = builtIns ?? NoComponents;
FallbackHostTemplateConfigNames = fallbackHostTemplateConfigNames ?? new List<string>();

loggerFactory ??= NullLoggerFactory.Instance;
_loggerFactory = loggerFactory;
_logger = _loggerFactory.CreateLogger("Template Engine") ?? NullLogger.Instance;
}

public IPhysicalFileSystem FileSystem { get; private set; }

public string HostIdentifier { get; }

public IReadOnlyList<string> FallbackHostTemplateConfigNames { get; }

public string Version { get; }

public virtual IReadOnlyList<(Type InterfaceType, IIdentifiedComponent Instance)> BuiltInComponents => _hostBuiltInComponents;

public ILogger Logger => _logger;

public ILoggerFactory LoggerFactory => _loggerFactory;

// stub that will be built out soon.
public virtual bool TryGetHostParamDefault(string paramName, out string value)
{
switch (paramName)
{
case "HostIdentifier":
value = HostIdentifier;
return true;
}

return _hostDefaults.TryGetValue(paramName, out value);
}

public void VirtualizeDirectory(string path)
{
FileSystem = new InMemoryFileSystem(path, FileSystem);
}

public void Dispose()
{
_loggerFactory?.Dispose();
}

#region Obsoleted
[Obsolete]
bool ITemplateEngineHost.OnPotentiallyDestructiveChangesDetected(IReadOnlyList<IFileChange> changes, IReadOnlyList<IFileChange> destructiveChanges)
{
return true;
}
#endregion
}
}
132 changes: 132 additions & 0 deletions core/Templating/IOAbstractionsFileSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
using Microsoft.TemplateEngine.Abstractions.PhysicalFileSystem;
using Microsoft.TemplateEngine.Utils;
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Abstractions;

namespace Cmf.CLI.Core.Templating
{
/// <summary>
/// Adapter to allow using an <see cref="System.IO.Abstractions.IFileSystem"/> anywhere where a
/// <see cref="Microsoft.TemplateEngine.Abstractions.PhysicalFileSystem.IPhysicalFileSystem"/> was expected.
/// </summary>
public class IOAbstractionsFileSystem : IPhysicalFileSystem
{
private readonly IFileSystem _basis;

public IOAbstractionsFileSystem(IFileSystem basis)
{
_basis = basis;
}

public void CreateDirectory(string path)
{
_basis.Directory.CreateDirectory(path);
}

public Stream CreateFile(string path)
{
return _basis.File.Create(path);
}

public void DirectoryDelete(string path, bool recursive)
{
_basis.Directory.Delete(path, recursive);
}

public bool DirectoryExists(string directory)
{
return _basis.Directory.Exists(directory);
}

public IEnumerable<string> EnumerateDirectories(string path, string pattern, SearchOption searchOption)
{
return _basis.Directory.EnumerateDirectories(path, pattern, searchOption);
}

public IEnumerable<string> EnumerateFiles(string path, string pattern, SearchOption searchOption)
{
return _basis.Directory.EnumerateFiles(path, pattern, searchOption);
}

public IEnumerable<string> EnumerateFileSystemEntries(string directoryName, string pattern, SearchOption searchOption)
{
return _basis.Directory.EnumerateFileSystemEntries(directoryName, pattern, searchOption);
}

public void FileCopy(string sourcePath, string targetPath, bool overwrite)
{
_basis.File.Copy(sourcePath, targetPath, overwrite);
}

public void FileDelete(string path)
{
_basis.File.Delete(path);
}

public bool FileExists(string file)
{
return _basis.File.Exists(file);
}

public string GetCurrentDirectory()
{
return _basis.Directory.GetCurrentDirectory();
}

public Stream OpenRead(string path)
{
return _basis.File.OpenRead(path);
}

public string ReadAllText(string path)
{
return _basis.File.ReadAllText(path);
}

public byte[] ReadAllBytes(string path)
{
return _basis.File.ReadAllBytes(path);
}

public void WriteAllText(string path, string value)
{
_basis.File.WriteAllText(path, value);
}

public FileAttributes GetFileAttributes(string file)
{
return _basis.File.GetAttributes(file);
}

public void SetFileAttributes(string file, FileAttributes attributes)
{
_basis.File.SetAttributes(file, attributes);
}

public DateTime GetLastWriteTimeUtc(string file)
{
return _basis.File.GetLastWriteTimeUtc(file);
}

public void SetLastWriteTimeUtc(string file, DateTime lastWriteTimeUtc)
{
_basis.File.SetLastAccessTimeUtc(file, lastWriteTimeUtc);
}

public string PathRelativeTo(string target, string relativeTo)
{
return _basis.Path.GetRelativePath(relativeTo, target);
}

/// <summary>
/// Currently not implemented in <see cref="IOAbstractionsFileSystem"/>.
/// Just returns <see cref="IDisposable"/> object, but never calls callback.
/// </summary>
public IDisposable WatchFileChanges(string filePath, FileSystemEventHandler fileChanged)
{
return new MemoryStream();
}
}
}
2 changes: 1 addition & 1 deletion tests/Specs/ListDependencies.cs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ public void LocalDependencies_HappyPath()
]
}") }
});

ExecutionContext.Initialize(fileSystem);

//var ls = new ListDependenciesCommand(fileSystem);
//ls.Execute(fileSystem.DirectoryInfo.New(@"c:\test"), null);
Expand Down