Skip to content
This repository was archived by the owner on Jun 21, 2023. It is now read-only.

Commit 8bc8745

Browse files
committed
Consolidate BindingPath(Utilities|Helper)
Merge BindingPathUtilities into BindingPathHelper.
1 parent 0cb3401 commit 8bc8745

File tree

3 files changed

+67
-82
lines changed

3 files changed

+67
-82
lines changed

src/GitHub.Exports/Helpers/BindingPathUtilities.cs

Lines changed: 0 additions & 71 deletions
This file was deleted.

src/GitHub.VisualStudio/Helpers/BindingPathHelper.cs

Lines changed: 62 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,43 @@
11
using System;
2+
using System.IO;
23
using System.Linq;
34
using System.Reflection;
45
using System.Diagnostics;
5-
using GitHub.Helpers;
6+
using System.Collections.Generic;
67
using GitHub.Logging;
78
using Microsoft.VisualStudio.Shell;
89
using Microsoft.VisualStudio.Shell.Interop;
10+
using Microsoft.VisualStudio.Shell.Settings;
11+
using Microsoft.VisualStudio.Settings;
912
using Serilog;
1013

1114
namespace GitHub.VisualStudio.Helpers
1215
{
1316
/// <summary>
14-
// When running in the Exp instance, ensure there is only one active binding path.
15-
// This is necessary when the regular (AllUsers) extension is also installed.
17+
/// This a workaround for extensions that define a ProvideBindingPath attribute and
18+
/// install for AllUsers.
1619
/// </summary>
1720
/// <remarks>
21+
/// Extensions that are installed for AllUsers, will also be installed for all
22+
/// instances of Visual Studio - including the experimental (Exp) instance which
23+
/// is used in development. This isn't a problem so long as all features that
24+
/// exist in the AllUsers extension, also exist in the extension that is being
25+
/// developed.
26+
///
27+
/// When an extension uses the ProvideBindingPath attribute, the binding path for
28+
/// the AllUsers extension gets installed at the same time as the one in development.
29+
/// This doesn't matter when an assembly is strong named and is loaded using its
30+
/// full name (including version number). When an assembly is loaded using its
31+
/// simple name, assemblies from the AllUsers extension can end up loaded at the
32+
/// same time as the extension being developed. This can happen when an assembly
33+
/// is loaded from XAML or an .imagemanifest.
34+
///
35+
/// This is a workaround for that issue. The <see cref="FindRedundantBindingPaths(List{string}, string)" />
36+
/// method will check to see if a reference assembly could be loaded from an alternative
37+
/// binding path. It will return any alternative paths that is finds.
1838
/// See https://github.com/github/VisualStudio/issues/1995
1939
/// </remarks>
20-
class BindingPathHelper
40+
public class BindingPathHelper
2141
{
2242
static readonly ILogger log = LogManager.ForContext<BindingPathHelper>();
2343

@@ -26,8 +46,8 @@ internal static void CheckBindingPaths(Assembly assembly, IServiceProvider servi
2646
log.Information("Looking for assembly on wrong binding path");
2747

2848
ThreadHelper.CheckAccess();
29-
var bindingPaths = BindingPathUtilities.FindBindingPaths(serviceProvider);
30-
var bindingPath = BindingPathUtilities.FindRedundantBindingPaths(bindingPaths, assembly.Location)
49+
var bindingPaths = FindBindingPaths(serviceProvider);
50+
var bindingPath = FindRedundantBindingPaths(bindingPaths, assembly.Location)
3151
.FirstOrDefault();
3252
if (bindingPath == null)
3353
{
@@ -49,5 +69,41 @@ internal static void CheckBindingPaths(Assembly assembly, IServiceProvider servi
4969
Process.Start("https://github.com/github/VisualStudio/issues/2006");
5070
}
5171
}
72+
73+
/// <summary>
74+
/// Find any alternative binding path that might have been installed by an AllUsers extension.
75+
/// </summary>
76+
/// <param name="bindingPaths">A list of binding paths to search</param>
77+
/// <param name="assemblyLocation">A reference assembly that has been loaded from the correct path.</param>
78+
/// <returns>A list of redundant binding paths.</returns>
79+
public static IList<string> FindRedundantBindingPaths(IEnumerable<string> bindingPaths, string assemblyLocation)
80+
{
81+
var fileName = Path.GetFileName(assemblyLocation);
82+
return bindingPaths
83+
.Select(p => (path: p, file: Path.Combine(p, fileName)))
84+
.Where(pf => File.Exists(pf.file))
85+
.Where(pf => !pf.file.Equals(assemblyLocation, StringComparison.OrdinalIgnoreCase))
86+
.Select(pf => pf.path)
87+
.ToList();
88+
}
89+
90+
/// <summary>
91+
/// Find Visual Studio's list of binding paths.
92+
/// </summary>
93+
/// <returns>A list of binding paths.</returns>
94+
public static IEnumerable<string> FindBindingPaths(IServiceProvider serviceProvider)
95+
{
96+
const string bindingPaths = "BindingPaths";
97+
var manager = new ShellSettingsManager(serviceProvider);
98+
var store = manager.GetReadOnlySettingsStore(SettingsScope.Configuration);
99+
foreach (var guid in store.GetSubCollectionNames(bindingPaths))
100+
{
101+
var guidPath = Path.Combine(bindingPaths, guid);
102+
foreach (var path in store.GetPropertyNames(guidPath))
103+
{
104+
yield return path;
105+
}
106+
}
107+
}
52108
}
53109
}

test/GitHub.Exports.UnitTests/Helpers/BindingPathUtilitiesTests.cs renamed to test/GitHub.VisualStudio.UnitTests/Helpers/BindingPathHelperTests.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
using System.IO;
22
using System.Collections.Generic;
3-
using GitHub.Helpers;
3+
using GitHub.VisualStudio.Helpers;
44
using NUnit.Framework;
55

6-
public static class BindingPathUtilitiesTests
6+
public static class BindingPathHelperTests
77
{
8-
public class TheRationalizeBindingPathsMethod
8+
public class TheFindRedundantBindingPathsMethod
99
{
1010
[TestCase]
1111
public void Redundant_Binding_Paths_Contains_Alternative_Path()
@@ -17,7 +17,7 @@ public void Redundant_Binding_Paths_Contains_Alternative_Path()
1717
var assemblyLocation = Path.Combine(assemblyDir, fileName);
1818
var bindingPaths = new List<string> { alternativeDir, assemblyDir };
1919

20-
var paths = BindingPathUtilities.FindRedundantBindingPaths(bindingPaths, assemblyLocation);
20+
var paths = BindingPathHelper.FindRedundantBindingPaths(bindingPaths, assemblyLocation);
2121

2222
Assert.That(paths, Contains.Item(alternativeDir));
2323
Assert.That(paths, Does.Not.Contain(assemblyDir));
@@ -30,7 +30,7 @@ public void No_Redundant_Binding_Paths()
3030
var assemblyDir = Path.GetDirectoryName(assemblyLocation);
3131
var bindingPaths = new List<string> { assemblyDir };
3232

33-
var paths = BindingPathUtilities.FindRedundantBindingPaths(bindingPaths, assemblyLocation);
33+
var paths = BindingPathHelper.FindRedundantBindingPaths(bindingPaths, assemblyLocation);
3434

3535
Assert.That(paths, Does.Not.Contain(assemblyDir));
3636
}

0 commit comments

Comments
 (0)