forked from xerxesb/SpecFlow
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix bug with generator plugin loader when using plugin path and add s…
…upport for global nuget packages (#1045) * Fix bug with generator plugin loader when using plugin path and add support for global nuget packages * Add better assertion message to unit tests for generator plugin loader * Fix issue with tests not using correct assembly version * Split GeneratorPluginLoader and GeneratorPluginLocator * Remove global nuget generator probing and simplify environment variable expansion * Update changelog * Cleanup code and add test for relative plugin paths
- Loading branch information
1 parent
97dcb79
commit eeeb80e
Showing
13 changed files
with
703 additions
and
108 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
136 changes: 136 additions & 0 deletions
136
TechTalk.SpecFlow.Generator/Plugins/GeneratorPluginLocator.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.IO; | ||
using System.Linq; | ||
using System.Reflection; | ||
using TechTalk.SpecFlow.Generator.Interfaces; | ||
using TechTalk.SpecFlow.Plugins; | ||
using TechTalk.SpecFlow.Utils; | ||
|
||
namespace TechTalk.SpecFlow.Generator.Plugins | ||
{ | ||
/// <summary> | ||
/// Loading logic: | ||
/// <plugin-folder> = @path | <generator-folder> | <nuget-plugin-folder> | ||
/// | ||
/// <configured-path> = @path | <project-folder>\@path | ||
/// | ||
/// <nuget-plugin-folder> = <nuget-packages>\<plugin-name>.SpecFlowPlugin.<nuget-package-version> | <nuget-packages>\<plugin-name>.SpecFlow.<nuget-package-version> | <nuget-packages>\<plugin-name>.<nuget-package-version> // match first for the one with <specflow-version> | ||
/// | ||
/// <specflow-version> = n-n[-n] // e.g. 1-8-1 | ||
/// | ||
/// <nuget-packages> = <generator-folder>\..\.. // assuming that SpecFlow was installed with nuget, generator is in the "tools" folder | ||
/// | ||
/// <nuget-package-version> = latest-of: n(.n)*[-tag] | ||
/// | ||
/// <plugin-generator-folder> = <plugin-folder> | <plugin-folder>\tools\SpecFlowPlugin[.<specflow-version>] | <plugin-folder>\tools | <plugin-folder>\lib\net45 | <plugin-folder>\lib\net40 | <plugin-folder>\lib\net35 | <plugin-folder>\lib | ||
/// | ||
/// <generator-plugin-assembly> = <plugin-generator-folder>\<plugin-name>.Generator.SpecFlowPlugin.dll | <generator-plugin-folder>\<plugin-name>.SpecFlowPlugin.dll | ||
/// </summary> | ||
public class GeneratorPluginLocator : IGeneratorPluginLocator | ||
{ | ||
private readonly string generatorFolder; | ||
private readonly ProjectSettings projectSettings; | ||
private readonly IFileSystem fileSystem; | ||
|
||
public GeneratorPluginLocator(ProjectSettings projectSettings, IFileSystem fileSystem) | ||
: this(projectSettings, null, fileSystem) | ||
{ | ||
this.generatorFolder = Path.GetDirectoryName(new Uri(Assembly.GetExecutingAssembly().CodeBase).LocalPath); | ||
} | ||
|
||
internal GeneratorPluginLocator(ProjectSettings projectSettings, string generatorFolder, IFileSystem fileSystem) | ||
{ | ||
this.projectSettings = projectSettings; | ||
this.generatorFolder = generatorFolder; | ||
this.fileSystem = fileSystem; | ||
} | ||
|
||
public String LocatePluginAssembly(PluginDescriptor pluginDescriptor) | ||
{ | ||
var assemblyPath = GetGeneratorPluginAssemblies(pluginDescriptor).FirstOrDefault(); | ||
|
||
if (assemblyPath == null) | ||
{ | ||
throw new SpecFlowException($"Unable to find plugin in the plugin search path: {pluginDescriptor.Name}. Please check http://go.specflow.org/doc-plugins for details."); | ||
} | ||
|
||
return assemblyPath; | ||
} | ||
|
||
private IEnumerable<string> GetGeneratorPluginAssemblies(PluginDescriptor pluginDescriptor) | ||
{ | ||
foreach (var pluginGeneratorFolder in GetPluginGeneratorFolders(pluginDescriptor)) | ||
{ | ||
string generatorSpecificAssembly = Path.GetFullPath(Path.Combine(pluginGeneratorFolder, string.Format("{0}.Generator.SpecFlowPlugin.dll", pluginDescriptor.Name))); | ||
generatorSpecificAssembly = Environment.ExpandEnvironmentVariables(generatorSpecificAssembly); | ||
|
||
if (this.fileSystem.FileExists(generatorSpecificAssembly)) | ||
yield return generatorSpecificAssembly; | ||
|
||
string genericAssembly = Path.GetFullPath(Path.Combine(pluginGeneratorFolder, string.Format("{0}.SpecFlowPlugin.dll", pluginDescriptor.Name))); | ||
genericAssembly = Environment.ExpandEnvironmentVariables(genericAssembly); | ||
if (this.fileSystem.FileExists(genericAssembly)) | ||
yield return genericAssembly; | ||
} | ||
} | ||
|
||
private IEnumerable<string> GetPluginGeneratorFolders(PluginDescriptor pluginDescriptor) | ||
{ | ||
var pluginGeneratorFolders = (new[] { @"" }) | ||
.Concat(GetSpecFlowVersionSpecifiers().Select(v => @"tools\SpecFlowPlugin" + v)) | ||
.Concat(new[] { @"tools", @"lib\net45", @"lib\net40", @"lib\net35", @"lib" }); | ||
|
||
return GetPluginFolders(pluginDescriptor).SelectMany(pluginFolder => pluginGeneratorFolders, Path.Combine); | ||
} | ||
|
||
private IEnumerable<string> GetPluginFolders(PluginDescriptor pluginDescriptor) | ||
{ | ||
if (pluginDescriptor.Path != null) | ||
{ | ||
var path = Environment.ExpandEnvironmentVariables(pluginDescriptor.Path); | ||
|
||
yield return Path.IsPathRooted(path) | ||
? path | ||
: Path.Combine(projectSettings.ProjectFolder, path); | ||
|
||
yield break; | ||
} | ||
|
||
yield return generatorFolder; | ||
|
||
foreach (var nuGetPluginFolder in GetNuGetPluginFolders(pluginDescriptor)) | ||
yield return nuGetPluginFolder; | ||
} | ||
|
||
private static readonly string[] pluginPostfixes = new[] { @".SpecFlowPlugin", @".SpecFlow", @"" }; | ||
|
||
private IEnumerable<string> GetNuGetPluginFolders(PluginDescriptor pluginDescriptor) | ||
{ | ||
string nuGetPackagesFolder = GetNuGetPackagesFolder(); | ||
|
||
return pluginPostfixes | ||
.Select(pluginPostfix => pluginDescriptor.Name + pluginPostfix) | ||
.Select(packageName => GetLatestPackage(nuGetPackagesFolder, packageName)) | ||
.Where(pluginFolder => pluginFolder != null); | ||
} | ||
|
||
private string GetLatestPackage(string nuGetPackagesFolder, string packageName) | ||
{ | ||
return this.fileSystem.GetDirectories(nuGetPackagesFolder, packageName + ".*").OrderByDescending(d => d).FirstOrDefault(); | ||
} | ||
|
||
private IEnumerable<string> GetSpecFlowVersionSpecifiers() | ||
{ | ||
var version = Assembly.GetExecutingAssembly().GetName().Version; | ||
yield return string.Format(".{0}-{1}-{2}", version.Major, version.Minor, version.Revision); | ||
yield return string.Format(".{0}-{1}", version.Major, version.Minor); | ||
yield return ""; | ||
} | ||
|
||
private string GetNuGetPackagesFolder() | ||
{ | ||
return Path.Combine(this.generatorFolder, "..", ".."); // assuming that SpecFlow was installed with nuget, generator is in the "tools" folder | ||
} | ||
} | ||
} |
9 changes: 9 additions & 0 deletions
9
TechTalk.SpecFlow.Generator/Plugins/IGeneratorPluginLocator.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
using TechTalk.SpecFlow.Plugins; | ||
|
||
namespace TechTalk.SpecFlow.Generator.Plugins | ||
{ | ||
public interface IGeneratorPluginLocator | ||
{ | ||
string LocatePluginAssembly(PluginDescriptor pluginDescriptor); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.