Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
gherkin parser import tool; upgrade to gh 1.0.24; fix language issues
- Loading branch information
1 parent
50ef09b
commit 5f87e75
Showing
41 changed files
with
1,270 additions
and
203 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | ||
<PropertyGroup> | ||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> | ||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> | ||
<ProductVersion>9.0.30729</ProductVersion> | ||
<SchemaVersion>2.0</SchemaVersion> | ||
<ProjectGuid>{0D3D2616-F53C-46A2-ADEB-273D140C1267}</ProjectGuid> | ||
<OutputType>Exe</OutputType> | ||
<AppDesignerFolder>Properties</AppDesignerFolder> | ||
<RootNamespace>ImportGherkinParser</RootNamespace> | ||
<AssemblyName>ImportGherkinParser</AssemblyName> | ||
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion> | ||
<FileAlignment>512</FileAlignment> | ||
</PropertyGroup> | ||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> | ||
<DebugSymbols>true</DebugSymbols> | ||
<DebugType>full</DebugType> | ||
<Optimize>false</Optimize> | ||
<OutputPath>bin\Debug\</OutputPath> | ||
<DefineConstants>DEBUG;TRACE</DefineConstants> | ||
<ErrorReport>prompt</ErrorReport> | ||
<WarningLevel>4</WarningLevel> | ||
</PropertyGroup> | ||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> | ||
<DebugType>pdbonly</DebugType> | ||
<Optimize>true</Optimize> | ||
<OutputPath>bin\Release\</OutputPath> | ||
<DefineConstants>TRACE</DefineConstants> | ||
<ErrorReport>prompt</ErrorReport> | ||
<WarningLevel>4</WarningLevel> | ||
</PropertyGroup> | ||
<ItemGroup> | ||
<Reference Include="ILMerge, Version=2.10.310.0, Culture=neutral, PublicKeyToken=736440c9b414ea16, processorArchitecture=MSIL"> | ||
<SpecificVersion>False</SpecificVersion> | ||
<HintPath>..\..\lib\ilmerge\ILMerge.exe</HintPath> | ||
</Reference> | ||
<Reference Include="System" /> | ||
<Reference Include="System.Core"> | ||
<RequiredTargetFramework>3.5</RequiredTargetFramework> | ||
</Reference> | ||
<Reference Include="System.Xml.Linq"> | ||
<RequiredTargetFramework>3.5</RequiredTargetFramework> | ||
</Reference> | ||
<Reference Include="System.Data.DataSetExtensions"> | ||
<RequiredTargetFramework>3.5</RequiredTargetFramework> | ||
</Reference> | ||
<Reference Include="System.Data" /> | ||
<Reference Include="System.Xml" /> | ||
</ItemGroup> | ||
<ItemGroup> | ||
<Compile Include="..\..\lib\nconsoler\NConsoler.cs"> | ||
<Link>NConsoler\NConsoler.cs</Link> | ||
</Compile> | ||
<Compile Include="Program.cs" /> | ||
<Compile Include="Properties\AssemblyInfo.cs" /> | ||
</ItemGroup> | ||
<ItemGroup> | ||
<None Include="import.cmd"> | ||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> | ||
</None> | ||
</ItemGroup> | ||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> | ||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. | ||
Other similar extension points exist, see Microsoft.Common.targets. | ||
<Target Name="BeforeBuild"> | ||
</Target> | ||
<Target Name="AfterBuild"> | ||
</Target> | ||
--> | ||
</Project> |
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,272 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Globalization; | ||
using System.IO; | ||
using System.Linq; | ||
using System.Reflection; | ||
using System.Text; | ||
using System.Text.RegularExpressions; | ||
using System.Xml.Linq; | ||
using ILMerging; | ||
using NConsoler; | ||
|
||
namespace ImportGherkinParser | ||
{ | ||
class Program | ||
{ | ||
static void Main(string[] args) | ||
{ | ||
Console.WriteLine("Gherkin parser import tool:"); | ||
Console.WriteLine(" + adds signing for the assembly"); | ||
Console.WriteLine(" + generates Language.xml from the parser"); | ||
Console.WriteLine(); | ||
|
||
Consolery.Run(typeof(Program), args); | ||
return; | ||
} | ||
|
||
static private readonly Regex parserVersionRe = new Regex(@"(?<version>[\d\.]+)"); | ||
|
||
[Action("Imports official Gherkin parser to SpecFlow")] | ||
public static void ImportGherkinParser( | ||
[Required(Description = "Original gherkin parser, like gherkin-1.0.21.dll")] string gherkinParser, | ||
[Optional("specflow.snk", "key")] string keyFile, | ||
[Optional("Gherkin.dll", "out")] string outputFile, | ||
[Optional("Languages.xml", "lngout")] string languagesOutputFile | ||
) | ||
{ | ||
string gherkinParserFullPath = Path.GetFullPath(gherkinParser); | ||
Version parserVersion = GetParserVersion(gherkinParserFullPath); | ||
if (parserVersion == null) | ||
return; | ||
|
||
string keyFullPath = Path.GetFullPath(keyFile); | ||
string outputFileFullPath = Path.GetFullPath(outputFile); | ||
string languagesOutputFileFullPath = Path.GetFullPath(languagesOutputFile); | ||
|
||
CreateSignedParser(gherkinParserFullPath, parserVersion, keyFullPath, outputFileFullPath); | ||
|
||
Assembly parserAssembly = LoadParser(outputFileFullPath); | ||
GenerateLanguageDescriptions(parserAssembly, languagesOutputFileFullPath); | ||
} | ||
|
||
private static Version GetParserVersion(string gherkinParserFullPath) | ||
{ | ||
var match = parserVersionRe.Match(Path.GetFileNameWithoutExtension(gherkinParserFullPath)); | ||
if (!match.Success) | ||
{ | ||
Console.WriteLine("> Unable to detect parser version"); | ||
return null; | ||
} | ||
var version = new Version(match.Groups["version"].Value); | ||
version = new Version(version.Major, version.Minor, version.Build, version.Revision < 0 ? 0 : version.Revision); | ||
return version; | ||
} | ||
|
||
private static Assembly LoadParser(string outputFileFullPath) | ||
{ | ||
Console.WriteLine("Loading imported parser from {0}", outputFileFullPath); | ||
return Assembly.LoadFrom(outputFileFullPath); | ||
} | ||
|
||
private static void CreateSignedParser(string gherkinParserFullPath, Version version, string keyFullPath, string outputFileFullPath) | ||
{ | ||
Console.WriteLine("Generating signed parser..."); | ||
|
||
ILMerge ilMerge = new ILMerge(); | ||
ilMerge.KeyFile = keyFullPath; | ||
ilMerge.Version = version; | ||
ilMerge.SetInputAssemblies(new[] { gherkinParserFullPath }); | ||
|
||
ilMerge.OutputFile = outputFileFullPath; | ||
ilMerge.TargetKind = ILMerge.Kind.Dll; | ||
|
||
ilMerge.Log = true; | ||
|
||
ilMerge.Merge(); | ||
|
||
Console.WriteLine(); | ||
} | ||
|
||
private static readonly Dictionary<string, string> languageTranslations = | ||
new Dictionary<string, string>() | ||
{ | ||
{"se", "sv"}, | ||
}; | ||
|
||
private class KeywordTranslation | ||
{ | ||
public string Keyword; | ||
public string Translation; | ||
} | ||
|
||
class LanguageInfo | ||
{ | ||
public string Code; // this is the gherkin code of the language can be either a CultureInfo or a specialized culture info | ||
public string CultureInfo; // this is the most specific .NET CultureInfo name that matches to code | ||
public string CompatibleGherkinCode; // only provided if the code was not consistent to the .NET naming (se vs. sv) | ||
public string DefaultSpecificCulture; // only provided is CultureInfo is a neutral language | ||
public string EnglishName; | ||
|
||
public readonly List<KeywordTranslation> KeywordTranslations = new List<KeywordTranslation>(); | ||
} | ||
|
||
//ikvm__gherkin!I18nKeywords_eo.properties | ||
static private readonly Regex i18NResourceRe = new Regex(@"I18nKeywords_(?<lang>.+)\.properties"); | ||
private static void GenerateLanguageDescriptions(Assembly parserAssembly, string languagesOutputFile) | ||
{ | ||
List<LanguageInfo> languages = CollectSupportedLanguages(parserAssembly); | ||
CollectKeywordTranslations(parserAssembly, languages); | ||
|
||
//write languages.xml file | ||
XDocument document = new XDocument(); | ||
var rootElement = new XElement(XName.Get("SpecFlowLanguages", "")); | ||
document.Add(rootElement); | ||
|
||
foreach (var language in languages) | ||
{ | ||
var langElement = new XElement(XName.Get("Language", "")); | ||
langElement.SetAttributeValue(XName.Get("code", ""), language.Code); | ||
langElement.SetAttributeValue(XName.Get("cultureInfo", ""), language.CultureInfo); | ||
if (language.CompatibleGherkinCode != null) | ||
langElement.SetAttributeValue(XName.Get("compatibleGherkinCode", ""), language.CompatibleGherkinCode); | ||
if (language.DefaultSpecificCulture != null) | ||
langElement.SetAttributeValue(XName.Get("defaultSpecificCulture", ""), language.DefaultSpecificCulture); | ||
if (language.EnglishName != null) | ||
langElement.SetAttributeValue(XName.Get("englishName", ""), language.EnglishName); | ||
|
||
foreach (var keywordTranslation in language.KeywordTranslations) | ||
{ | ||
var keywordElement = new XElement(XName.Get(keywordTranslation.Keyword, "")); | ||
keywordElement.SetValue(keywordTranslation.Translation); | ||
langElement.Add(keywordElement); | ||
} | ||
|
||
rootElement.Add(langElement); | ||
} | ||
|
||
document.Save(languagesOutputFile); | ||
} | ||
|
||
private static void CollectKeywordTranslations(Assembly parserAssembly, List<LanguageInfo> languages) | ||
{ | ||
Type i18NType = parserAssembly.GetType("gherkin.I18n", true); | ||
MethodInfo keywordMethod = i18NType.GetMethod("keywords"); | ||
if (keywordMethod == null) | ||
throw new InvalidOperationException("keywords method not found"); | ||
|
||
string[] keywords = new[] { "Feature", "Background", "Scenario", "ScenarioOutline", "Examples", "Given", "When", "Then", "And", "But" }; | ||
|
||
foreach (var language in languages) | ||
{ | ||
var i18N = Activator.CreateInstance(i18NType, language.CompatibleGherkinCode ?? language.Code); | ||
|
||
foreach (var keyword in keywords) | ||
{ | ||
CollectKeywordTranslations(keyword, language.KeywordTranslations, i18N, keywordMethod); | ||
} | ||
} | ||
} | ||
|
||
private static void CollectKeywordTranslations(string keyword, List<KeywordTranslation> keywordTranslations, object i18N, MethodInfo keywordMethod) | ||
{ | ||
string gherkinKeyword = keyword == "ScenarioOutline" ? "scenario_outline" : keyword.ToLower(); | ||
var keywordList = keywordMethod.Invoke(i18N, new object[] { gherkinKeyword }); | ||
object[] keywordListArray = (object[])keywordList.GetType().GetMethod("toArray", new Type[0]).Invoke(keywordList, null); | ||
foreach (string translation in keywordListArray) | ||
{ | ||
if (!translation.Trim().StartsWith("*")) | ||
keywordTranslations.Add(new KeywordTranslation { Keyword = keyword, Translation = translation.Trim() }); | ||
} | ||
} | ||
|
||
private static List<LanguageInfo> CollectSupportedLanguages(Assembly parserAssembly) | ||
{ | ||
var languages = new List<LanguageInfo>(); | ||
var resourceNames = parserAssembly.GetManifestResourceNames(); | ||
foreach (var resourceName in resourceNames) | ||
{ | ||
var match = i18NResourceRe.Match(resourceName); | ||
if (!match.Success) | ||
continue; | ||
|
||
LanguageInfo languageInfo = new LanguageInfo(); | ||
languageInfo.Code = match.Groups["lang"].Value.Replace("_", "-"); | ||
if (languageTranslations.ContainsKey(languageInfo.Code)) | ||
{ | ||
languageInfo.CompatibleGherkinCode = languageInfo.Code; | ||
languageInfo.Code = languageTranslations[languageInfo.Code]; | ||
} | ||
|
||
CultureInfo cultureInfo = GetCultureInfo(languageInfo.Code); | ||
if (cultureInfo == null) | ||
continue; | ||
|
||
languageInfo.CultureInfo = cultureInfo.Name; | ||
languageInfo.EnglishName = cultureInfo.EnglishName; | ||
if (cultureInfo.IsNeutralCulture) | ||
{ | ||
CultureInfo defaultSpecificCulture = GetDefaultSpecificCulture(languageInfo.Code); | ||
if (defaultSpecificCulture != null) | ||
languageInfo.DefaultSpecificCulture = defaultSpecificCulture.Name; | ||
} | ||
languages.Add(languageInfo); | ||
} | ||
return languages; | ||
} | ||
|
||
private static CultureInfo GetCultureInfo(string code) | ||
{ | ||
try | ||
{ | ||
return CultureInfo.GetCultureInfo(code); | ||
} | ||
catch (Exception) | ||
{ | ||
string[] langParts = code.Split('-'); | ||
try | ||
{ | ||
var result = CultureInfo.GetCultureInfo(langParts[0]); | ||
Console.WriteLine("Possibly unusable language: {0}", code); | ||
return result; | ||
} | ||
catch (Exception) | ||
{ | ||
Console.WriteLine("invlid language: {0}", code); | ||
return null; | ||
} | ||
} | ||
} | ||
|
||
private static readonly Dictionary<string, string> wellKnownSpecificCultures = | ||
new Dictionary<string, string>() | ||
{ | ||
{"en", "en-US"}, | ||
{"no", "nb-NO"}, | ||
{"sv", "sv-SE"}, | ||
{"uz", "uz-Cyrl-UZ"}, | ||
{"sr-Cyrl", "sr-Cyrl-RS"}, | ||
{"sr-Latn", "sr-Latn-RS"}, | ||
}; | ||
|
||
private static CultureInfo GetDefaultSpecificCulture(string cultureName) | ||
{ | ||
if (wellKnownSpecificCultures.ContainsKey(cultureName)) | ||
return CultureInfo.GetCultureInfo(wellKnownSpecificCultures[cultureName]); | ||
|
||
string guessedName = cultureName + "-" + cultureName.ToUpper(); | ||
var result = CultureInfo.GetCultures(CultureTypes.SpecificCultures).Where(c => c.Name.Equals(guessedName)).FirstOrDefault(); | ||
if (result != null) | ||
return result; | ||
|
||
var cultures = CultureInfo.GetCultures(CultureTypes.SpecificCultures).Where(c => c.Parent.Name.Equals(cultureName)); | ||
result = cultures.FirstOrDefault(); | ||
if (cultures.Count() > 1) | ||
{ | ||
Console.WriteLine("Multiple possible specific cultures: {0}", string.Join(", ", cultures.Select(c => c.Name).ToArray())); | ||
Console.WriteLine("Default specific culture for {0} is {1}", cultureName, result); | ||
} | ||
return result; | ||
} | ||
} | ||
} |
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,36 @@ | ||
using System.Reflection; | ||
using System.Runtime.CompilerServices; | ||
using System.Runtime.InteropServices; | ||
|
||
// General Information about an assembly is controlled through the following | ||
// set of attributes. Change these attribute values to modify the information | ||
// associated with an assembly. | ||
[assembly: AssemblyTitle("ImportGherkinParser")] | ||
[assembly: AssemblyDescription("")] | ||
[assembly: AssemblyConfiguration("")] | ||
[assembly: AssemblyCompany("Microsoft")] | ||
[assembly: AssemblyProduct("ImportGherkinParser")] | ||
[assembly: AssemblyCopyright("Copyright © Microsoft 2010")] | ||
[assembly: AssemblyTrademark("")] | ||
[assembly: AssemblyCulture("")] | ||
|
||
// Setting ComVisible to false makes the types in this assembly not visible | ||
// to COM components. If you need to access a type in this assembly from | ||
// COM, set the ComVisible attribute to true on that type. | ||
[assembly: ComVisible(false)] | ||
|
||
// The following GUID is for the ID of the typelib if this project is exposed to COM | ||
[assembly: Guid("2c786e92-a5ea-471d-bcc6-bd0c47fc0c9e")] | ||
|
||
// Version information for an assembly consists of the following four values: | ||
// | ||
// Major Version | ||
// Minor Version | ||
// Build Number | ||
// Revision | ||
// | ||
// You can specify all the values or you can default the Build and Revision Numbers | ||
// by using the '*' as shown below: | ||
// [assembly: AssemblyVersion("1.0.*")] | ||
[assembly: AssemblyVersion("1.0.0.0")] | ||
[assembly: AssemblyFileVersion("1.0.0.0")] |
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,2 @@ | ||
|
||
ImportGherkinParser.exe ..\..\..\..\lib\gherkin\%1 /key:..\..\..\..\specflow.snk /lngout:..\..\..\..\Languages.xml /out:..\..\..\..\lib\gherkin\Gherkin.dll |
Oops, something went wrong.