Browse Source

Fix T4 templates using GAC references not in project.

Add FindBestMatchingAssemblyName() taken from GacInterop class
in SharpDevelop 4 into GlobalAssemblyCacheService
newNRvisualizers
Matt Ward 13 years ago
parent
commit
dbdef30715
  1. 13
      src/AddIns/Misc/TextTemplating/Project/Src/IAssemblyParserService.cs
  2. 12
      src/AddIns/Misc/TextTemplating/Project/Src/IReflectionProjectContent.cs
  3. 21
      src/AddIns/Misc/TextTemplating/Project/Src/TextTemplatingAssemblyParserService.cs
  4. 35
      src/AddIns/Misc/TextTemplating/Project/Src/TextTemplatingAssemblyPathResolver.cs
  5. 20
      src/AddIns/Misc/TextTemplating/Project/Src/TextTemplatingReflectionProjectContent.cs
  6. 4
      src/AddIns/Misc/TextTemplating/Project/TextTemplating.csproj
  7. 23
      src/AddIns/Misc/TextTemplating/Test/Helpers/FakeAssemblyParserService.cs
  8. 13
      src/AddIns/Misc/TextTemplating/Test/Helpers/FakeReflectionProjectContent.cs
  9. 83
      src/AddIns/Misc/TextTemplating/Test/Src/TextTemplatingAssemblyPathResolverTests.cs
  10. 24
      src/AddIns/Misc/TextTemplating/Test/Src/TextTemplatingReflectionProjectContentTests.cs
  11. 3
      src/AddIns/Misc/TextTemplating/Test/TextTemplating.Tests.csproj
  12. 6
      src/Main/Base/Project/Parser/IGlobalAssemblyCacheService.cs
  13. 6
      src/Main/SharpDevelop/Parser/Fusion.cs
  14. 68
      src/Main/SharpDevelop/Parser/GlobalAssemblyCacheService.cs

13
src/AddIns/Misc/TextTemplating/Project/Src/IAssemblyParserService.cs

@ -1,13 +0,0 @@ @@ -1,13 +0,0 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using ICSharpCode.SharpDevelop.Project;
namespace ICSharpCode.TextTemplating
{
public interface IAssemblyParserService
{
IReflectionProjectContent GetReflectionProjectContentForReference(ReferenceProjectItem item);
}
}

12
src/AddIns/Misc/TextTemplating/Project/Src/IReflectionProjectContent.cs

@ -1,12 +0,0 @@ @@ -1,12 +0,0 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
namespace ICSharpCode.TextTemplating
{
public interface IReflectionProjectContent
{
string AssemblyLocation { get; }
}
}

21
src/AddIns/Misc/TextTemplating/Project/Src/TextTemplatingAssemblyParserService.cs

@ -1,21 +0,0 @@ @@ -1,21 +0,0 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Parser;
using ICSharpCode.SharpDevelop.Project;
namespace ICSharpCode.TextTemplating
{
public class TextTemplatingAssemblyParserService : IAssemblyParserService
{
public IReflectionProjectContent GetReflectionProjectContentForReference(ReferenceProjectItem item)
{
//IProjectContent projectContent = SD.AssemblyParserService.GetProjectContentForReference(item);
//return new TextTemplatingReflectionProjectContent(projectContent);
return null;
}
}
}

35
src/AddIns/Misc/TextTemplating/Project/Src/TextTemplatingAssemblyPathResolver.cs

@ -3,6 +3,9 @@ @@ -3,6 +3,9 @@
using System;
using System.IO;
using ICSharpCode.Core;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Parser;
using ICSharpCode.SharpDevelop.Project;
namespace ICSharpCode.TextTemplating
@ -10,23 +13,23 @@ namespace ICSharpCode.TextTemplating @@ -10,23 +13,23 @@ namespace ICSharpCode.TextTemplating
public class TextTemplatingAssemblyPathResolver : ITextTemplatingAssemblyPathResolver
{
IProject project;
IAssemblyParserService assemblyParserService;
IGlobalAssemblyCacheService gac;
ITextTemplatingPathResolver pathResolver;
public TextTemplatingAssemblyPathResolver(
IProject project,
IAssemblyParserService assemblyParserService,
IGlobalAssemblyCacheService gac,
ITextTemplatingPathResolver pathResolver)
{
this.project = project;
this.assemblyParserService = assemblyParserService;
this.gac = gac;
this.pathResolver = pathResolver;
}
public TextTemplatingAssemblyPathResolver(IProject project)
: this(
project,
new TextTemplatingAssemblyParserService(),
SD.GlobalAssemblyCache,
new TextTemplatingPathResolver())
{
}
@ -40,8 +43,7 @@ namespace ICSharpCode.TextTemplating @@ -40,8 +43,7 @@ namespace ICSharpCode.TextTemplating
string resolvedAssemblyFileName = ResolveAssemblyFromProject(assemblyReference);
if (resolvedAssemblyFileName == null) {
// TODO GAC assembly reference.
//resolvedAssemblyFileName = ResolveAssemblyFromGac(assemblyReference);
resolvedAssemblyFileName = ResolveAssemblyFromGac(assemblyReference);
}
if (resolvedAssemblyFileName != null) {
return resolvedAssemblyFileName;
@ -66,22 +68,15 @@ namespace ICSharpCode.TextTemplating @@ -66,22 +68,15 @@ namespace ICSharpCode.TextTemplating
string ResolveAssemblyFromGac(string assemblyReference)
{
IReflectionProjectContent projectContent = GetProjectContent(assemblyReference);
if (projectContent != null) {
return projectContent.AssemblyLocation;
var assemblyName = new DomAssemblyName(assemblyReference);
DomAssemblyName foundAssemblyName = gac.FindBestMatchingAssemblyName(assemblyName);
if (foundAssemblyName != null) {
FileName fileName = gac.FindAssemblyInNetGac(foundAssemblyName);
if (fileName != null) {
return fileName.ToString();
}
}
return null;
}
IReflectionProjectContent GetProjectContent(string assemblyReference)
{
var reference = new ReferenceProjectItem(project, assemblyReference);
return GetProjectContent(reference);
}
IReflectionProjectContent GetProjectContent(ReferenceProjectItem refProjectItem)
{
return assemblyParserService.GetReflectionProjectContentForReference(refProjectItem);
}
}
}

20
src/AddIns/Misc/TextTemplating/Project/Src/TextTemplatingReflectionProjectContent.cs

@ -1,20 +0,0 @@ @@ -1,20 +0,0 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.TextTemplating
{
public class TextTemplatingReflectionProjectContent : IReflectionProjectContent
{
public TextTemplatingReflectionProjectContent(IProjectContent projectContent)
{
if (projectContent != null) {
AssemblyLocation = projectContent.Location;
}
}
public string AssemblyLocation { get; private set; }
}
}

4
src/AddIns/Misc/TextTemplating/Project/TextTemplating.csproj

@ -59,8 +59,6 @@ @@ -59,8 +59,6 @@
<Compile Include="Src\IAddInRuntime.cs" />
<Compile Include="Src\IAddInTree.cs" />
<Compile Include="Src\IAppDomain.cs" />
<Compile Include="Src\IAssemblyParserService.cs" />
<Compile Include="Src\IReflectionProjectContent.cs" />
<Compile Include="Src\ITextTemplatingAppDomain.cs" />
<Compile Include="Src\ITextTemplatingAppDomainFactory.cs" />
<Compile Include="Src\ITextTemplatingAssemblyPathResolver.cs" />
@ -81,7 +79,6 @@ @@ -81,7 +79,6 @@
<Compile Include="Src\TextTemplatingAddInTree.cs" />
<Compile Include="Src\TextTemplatingAppDomain.cs" />
<Compile Include="Src\TextTemplatingAppDomainFactory.cs" />
<Compile Include="Src\TextTemplatingAssemblyParserService.cs" />
<Compile Include="Src\TextTemplatingAssemblyPathResolver.cs" />
<Compile Include="Src\TextTemplatingAssemblyResolver.cs" />
<Compile Include="Src\TextTemplatingCustomTool.cs" />
@ -99,7 +96,6 @@ @@ -99,7 +96,6 @@
<Compile Include="Src\TextTemplatingHostAppDomainAssemblyResolver.cs" />
<Compile Include="Src\TextTemplatingHostContext.cs" />
<Compile Include="Src\TextTemplatingPathResolver.cs" />
<Compile Include="Src\TextTemplatingReflectionProjectContent.cs" />
<Compile Include="Src\TextTemplatingServiceProvider.cs" />
<Compile Include="Src\TextTemplatingStringParser.cs" />
<Compile Include="Src\TextTemplatingVariableLocation.cs" />

23
src/AddIns/Misc/TextTemplating/Test/Helpers/FakeAssemblyParserService.cs

@ -1,23 +0,0 @@ @@ -1,23 +0,0 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using ICSharpCode.SharpDevelop.Project;
using ICSharpCode.TextTemplating;
namespace TextTemplating.Tests.Helpers
{
public class FakeAssemblyParserService : IAssemblyParserService
{
public FakeReflectionProjectContent FakeReflectionProjectContent = new FakeReflectionProjectContent();
public ReferenceProjectItem ItemPassedToGetReflectionProjectContentForReference;
public bool IsGetReflectionProjectContentForReferenceCalled;
public IReflectionProjectContent GetReflectionProjectContentForReference(ReferenceProjectItem item)
{
IsGetReflectionProjectContentForReferenceCalled = true;
ItemPassedToGetReflectionProjectContentForReference = item;
return FakeReflectionProjectContent;
}
}
}

13
src/AddIns/Misc/TextTemplating/Test/Helpers/FakeReflectionProjectContent.cs

@ -1,13 +0,0 @@ @@ -1,13 +0,0 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using ICSharpCode.TextTemplating;
namespace TextTemplating.Tests.Helpers
{
public class FakeReflectionProjectContent : IReflectionProjectContent
{
public string AssemblyLocation { get; set; }
}
}

83
src/AddIns/Misc/TextTemplating/Test/Src/TextTemplatingAssemblyPathResolverTests.cs

@ -2,11 +2,14 @@ @@ -2,11 +2,14 @@
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using ICSharpCode.Core;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Internal.Templates;
using ICSharpCode.SharpDevelop.Parser;
using ICSharpCode.SharpDevelop.Project;
using ICSharpCode.TextTemplating;
using NUnit.Framework;
using Rhino.Mocks;
using TextTemplating.Tests.Helpers;
namespace TextTemplating.Tests
@ -16,7 +19,7 @@ namespace TextTemplating.Tests @@ -16,7 +19,7 @@ namespace TextTemplating.Tests
{
TextTemplatingAssemblyPathResolver resolver;
IProject project;
FakeAssemblyParserService fakeAssemblyParserService;
IGlobalAssemblyCacheService fakeGacService;
FakeTextTemplatingPathResolver fakePathResolver;
[SetUp]
@ -35,9 +38,9 @@ namespace TextTemplating.Tests @@ -35,9 +38,9 @@ namespace TextTemplating.Tests
void CreateResolver()
{
project = ProjectHelper.CreateProject();
fakeAssemblyParserService = new FakeAssemblyParserService();
fakeGacService = MockRepository.GenerateStub<IGlobalAssemblyCacheService>();
fakePathResolver = new FakeTextTemplatingPathResolver();
resolver = new TextTemplatingAssemblyPathResolver(project, fakeAssemblyParserService, fakePathResolver);
resolver = new TextTemplatingAssemblyPathResolver(project, fakeGacService, fakePathResolver);
}
ReferenceProjectItem AddReferenceToProject(string referenceName)
@ -46,26 +49,30 @@ namespace TextTemplating.Tests @@ -46,26 +49,30 @@ namespace TextTemplating.Tests
ProjectService.AddProjectItem(project, projectItem);
return projectItem;
}
IProject GetProjectPassedToAssemblyParserService()
{
return ReferenceProjectItemPassedToGetReflectionProjectContentForReference.Project;
}
ReferenceProjectItem ReferenceProjectItemPassedToGetReflectionProjectContentForReference {
get { return fakeAssemblyParserService.ItemPassedToGetReflectionProjectContentForReference; }
void AddFileNameForGacReference(string fileName, string reference)
{
DomAssemblyName assemblyName = AddMatchingAssemblyNameForGacReference(reference);
fakeGacService
.Stub(gac => gac.FindAssemblyInNetGac(assemblyName))
.Return(new FileName(fileName));
}
ItemType GetReferenceItemTypePassedToAssemblyParserService()
DomAssemblyName AddMatchingAssemblyNameForGacReference(string reference)
{
return ReferenceProjectItemPassedToGetReflectionProjectContentForReference.ItemType;
var assemblyName = new DomAssemblyName(reference);
var assemblyNameToReturn = new DomAssemblyName("GacReference");
fakeGacService
.Stub(gac => gac.FindBestMatchingAssemblyName(assemblyName))
.Return(assemblyNameToReturn);
return assemblyNameToReturn;
}
[Test]
public void ResolvePath_ProjectHasNoReferences_ReturnsAssemblyReferencePassedToMethod()
{
CreateResolver();
fakeAssemblyParserService.FakeReflectionProjectContent = null;
string result = resolver.ResolvePath("Test");
Assert.AreEqual("Test", result);
@ -111,56 +118,21 @@ namespace TextTemplating.Tests @@ -111,56 +118,21 @@ namespace TextTemplating.Tests
}
[Test]
[Ignore("TODO GAC assembly resolving")]
public void ResolvePath_ProjectHasNoReferencesAndAssemblyReferenceInGac_ReturnsFullPathToAssemblyFoundFromAssemblyParserService()
{
CreateResolver();
string expectedFileName = @"c:\Windows\System32\Gac\System.Data.dll";
fakeAssemblyParserService.FakeReflectionProjectContent.AssemblyLocation = expectedFileName;
AddFileNameForGacReference(expectedFileName, "System.Data");
string result = resolver.ResolvePath("System.Data");
Assert.AreEqual(expectedFileName, result);
}
[Test]
[Ignore("TODO GAC assembly resolving")]
public void ResolvePath_ProjectHasNoReferencesAndAssemblyReferenceInGac_ReferenceItemPassedToAssemblyParserServiceUsesProject()
{
CreateResolver();
string result = resolver.ResolvePath("System.Data");
IProject expectedProject = GetProjectPassedToAssemblyParserService();
Assert.AreEqual(project, expectedProject);
}
[Test]
[Ignore("TODO GAC assembly resolving")]
public void ResolvePath_ProjectHasNoReferencesAndAssemblyReferenceInGac_ReferenceItemPassedToAssemblyParserServiceIsReference()
{
CreateResolver();
string result = resolver.ResolvePath("System.Data");
ItemType type = GetReferenceItemTypePassedToAssemblyParserService();
Assert.AreEqual(ItemType.Reference, type);
}
[Test]
[Ignore("TODO GAC assembly resolving")]
public void ResolvePath_ProjectHasNoReferencesAndAssemblyReferenceInGac_ReferenceItemIncludePassedToAssemblyParserServiceIsAssemblyNameToResolvePath()
{
CreateResolver();
string result = resolver.ResolvePath("System.Data");
string referenceInclude = ReferenceProjectItemPassedToGetReflectionProjectContentForReference.Include;
Assert.AreEqual("System.Data", referenceInclude);
}
[Test]
public void ResolvePath_ProjectHasNoReferencesAndAssemblyReferenceNotFoundInGac_ReturnsAssemblyReferencePassedToMethod()
{
CreateResolver();
fakeAssemblyParserService.FakeReflectionProjectContent = null;
string result = resolver.ResolvePath("System.Data");
@ -190,7 +162,18 @@ namespace TextTemplating.Tests @@ -190,7 +162,18 @@ namespace TextTemplating.Tests
string result = resolver.ResolvePath(path);
Assert.IsFalse(fakeAssemblyParserService.IsGetReflectionProjectContentForReferenceCalled);
fakeGacService.AssertWasNotCalled(gac => gac.FindBestMatchingAssemblyName(Arg<DomAssemblyName>.Is.Anything));
}
[Test]
public void ResolvePath_AssemblyReferenceInGacButNoFileNameFound_ReturnsAssemblyReferenceNamePassedToResolvePath()
{
CreateResolver();
AddMatchingAssemblyNameForGacReference("System.Data");
string result = resolver.ResolvePath("System.Data");
Assert.AreEqual("System.Data", result);
}
}
}

24
src/AddIns/Misc/TextTemplating/Test/Src/TextTemplatingReflectionProjectContentTests.cs

@ -1,24 +0,0 @@ @@ -1,24 +0,0 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.TextTemplating;
using NUnit.Framework;
namespace TextTemplating.Tests
{
[TestFixture]
[Ignore("TODO assembly location")]
public class TextTemplatingReflectionProjectContentTests
{
[Test]
public void AssemblyLocation_NullProjectContentPassedToConstructor_ReturnsNull()
{
//IProjectContent projectContent = new TextTemplatingReflectionProjectContent(null);
//string location = projectContent.AssemblyLocation;
//Assert.IsNull(location);
}
}
}

3
src/AddIns/Misc/TextTemplating/Test/TextTemplating.Tests.csproj

@ -63,8 +63,6 @@ @@ -63,8 +63,6 @@
<Compile Include="Helpers\FakeAddInRuntime.cs" />
<Compile Include="Helpers\FakeAddInTree.cs" />
<Compile Include="Helpers\FakeAppDomain.cs" />
<Compile Include="Helpers\FakeAssemblyParserService.cs" />
<Compile Include="Helpers\FakeReflectionProjectContent.cs" />
<Compile Include="Helpers\FakeServiceProvider.cs" />
<Compile Include="Helpers\FakeTextTemplatingAppDomain.cs" />
<Compile Include="Helpers\FakeTextTemplatingAppDomainFactory.cs" />
@ -101,7 +99,6 @@ @@ -101,7 +99,6 @@
<Compile Include="Src\TextTemplatingHostTests.cs" />
<Compile Include="Src\TextTemplatingPathResolverTests.cs" />
<Compile Include="Src\TextTemplatingPreprocessorTests.cs" />
<Compile Include="Src\TextTemplatingReflectionProjectContentTests.cs" />
<Compile Include="Src\TextTemplatingServiceProviderTests.cs" />
<Compile Include="Src\TextTemplatingVariableLocationTests.cs" />
<Compile Include="Src\TextTemplatingVariablesTests.cs" />

6
src/Main/Base/Project/Parser/IGlobalAssemblyCacheService.cs

@ -28,5 +28,11 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -28,5 +28,11 @@ namespace ICSharpCode.SharpDevelop.Parser
/// Returns null if the assembly cannot be found.
/// </summary>
FileName FindAssemblyInNetGac(DomAssemblyName reference);
/// <summary>
/// Gets the full display name of the GAC assembly of the specified short name.
/// Returns null if the assembly cannot be found.
/// </summary>
DomAssemblyName FindBestMatchingAssemblyName(DomAssemblyName reference);
}
}

6
src/Main/SharpDevelop/Parser/Fusion.cs

@ -101,6 +101,12 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -101,6 +101,12 @@ namespace ICSharpCode.SharpDevelop.Parser
uint dwFlags,
int pvReserved);
[DllImport("fusion.dll", CharSet=CharSet.Auto)]
internal static extern int CreateAssemblyNameObject(out IAssemblyName ppName,
string szAssemblyName,
uint dwFlags,
int pvReserved);
[DllImport("fusion.dll")]
internal static extern int GetCachePath(uint flags,
[MarshalAs(UnmanagedType.LPWStr)] StringBuilder wzDir,

68
src/Main/SharpDevelop/Parser/GlobalAssemblyCacheService.cs

@ -38,6 +38,74 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -38,6 +38,74 @@ namespace ICSharpCode.SharpDevelop.Parser
}
}
/// <summary>
/// Gets the full display name of the GAC assembly of the specified short name
/// </summary>
public DomAssemblyName FindBestMatchingAssemblyName(DomAssemblyName reference)
{
string[] info;
Version requiredVersion = reference.Version;
string publicKey = reference.PublicKeyToken;
IApplicationContext applicationContext = null;
IAssemblyEnum assemblyEnum = null;
IAssemblyName assemblyName;
Fusion.CreateAssemblyNameObject(out assemblyName, reference.ShortName, 0, 0);
Fusion.CreateAssemblyEnum(out assemblyEnum, null, assemblyName, 2, 0);
List<string> names = new List<string>();
while (assemblyEnum.GetNextAssembly(out applicationContext, out assemblyName, 0) == 0) {
uint nChars = 0;
assemblyName.GetDisplayName(null, ref nChars, 0);
StringBuilder sb = new StringBuilder((int)nChars);
assemblyName.GetDisplayName(sb, ref nChars, 0);
string fullName = sb.ToString();
if (publicKey != null) {
info = fullName.Split(',');
if (publicKey != info[3].Substring(info[3].LastIndexOf('=') + 1)) {
// Assembly has wrong public key
continue;
}
}
names.Add(fullName);
}
if (names.Count == 0)
return null;
string best = null;
Version bestVersion = null;
Version currentVersion;
if (requiredVersion != null) {
// use assembly with lowest version higher or equal to required version
for (int i = 0; i < names.Count; i++) {
info = names[i].Split(',');
currentVersion = new Version(info[1].Substring(info[1].LastIndexOf('=') + 1));
if (currentVersion.CompareTo(requiredVersion) < 0)
continue; // version not good enough
if (best == null || currentVersion.CompareTo(bestVersion) < 0) {
bestVersion = currentVersion;
best = names[i];
}
}
if (best != null)
return new DomAssemblyName(best);
}
// use assembly with highest version
best = names[0];
info = names[0].Split(',');
bestVersion = new Version(info[1].Substring(info[1].LastIndexOf('=') + 1));
for (int i = 1; i < names.Count; i++) {
info = names[i].Split(',');
currentVersion = new Version(info[1].Substring(info[1].LastIndexOf('=') + 1));
if (currentVersion.CompareTo(bestVersion) > 0) {
bestVersion = currentVersion;
best = names[i];
}
}
return new DomAssemblyName(best);
}
#region FindAssemblyInNetGac
// This region is based on code from Mono.Cecil:

Loading…
Cancel
Save