Skip to content

Commit

Permalink
Merge pull request #254 from ForrestTrepte/dev/getCredentialProviderO…
Browse files Browse the repository at this point in the history
…ptimization

cache calls to GetCredentialProvider
  • Loading branch information
ForrestTrepte authored Jun 12, 2019
2 parents ce481da + 05fdfe8 commit 6c04461
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 4 deletions.
55 changes: 51 additions & 4 deletions Assets/NuGet/Editor/NugetHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,11 @@ public static PackagesConfigFile PackagesConfigFile
/// </summary>
private static Dictionary<string, NugetPackage> installedPackages = new Dictionary<string, NugetPackage>();

/// <summary>
/// The dictionary of cached credentials retrieved by credential providers, keyed by feed URI.
/// </summary>
private static Dictionary<Uri, CredentialProviderResponse?> cachedCredentialsByFeedUri = new Dictionary<Uri, CredentialProviderResponse?>();

/// <summary>
/// The current .NET version being used (2.0 [actually 3.5], 4.6, etc).
/// </summary>
Expand Down Expand Up @@ -1286,7 +1291,7 @@ public static Stream RequestUrl(string url, string userName, string password, in

if (string.IsNullOrEmpty(password))
{
CredentialProviderResponse? creds = GetCredentialFromProvider(getRequest.RequestUri, true);
CredentialProviderResponse? creds = GetCredentialFromProvider(GetTruncatedFeedUri(getRequest.RequestUri));
if (creds.HasValue)
{
userName = creds.Value.Username;
Expand Down Expand Up @@ -1578,10 +1583,52 @@ private static void DownloadCredentialProviders(Uri feedUri)
/// See here for more info on nuget Credential Providers:
/// https://docs.microsoft.com/en-us/nuget/reference/extensibility/nuget-exe-credential-providers
/// </summary>
/// <param name="packageHost">The hostname where the VSTS instance is hosted (such as microsoft.pkgs.visualsudio.com</param>
/// <param name="feedUri">The hostname where the VSTS instance is hosted (such as microsoft.pkgs.visualsudio.com.</param>
/// <returns>The password in the form of a token, or null if the password could not be aquired</returns>
private static CredentialProviderResponse? GetCredentialFromProvider(Uri feedUri, bool downloadIfMissing)
private static CredentialProviderResponse? GetCredentialFromProvider(Uri feedUri)
{
CredentialProviderResponse? response;
if (!cachedCredentialsByFeedUri.TryGetValue(feedUri, out response))
{
response = GetCredentialFromProvider_Uncached(feedUri, true);
cachedCredentialsByFeedUri[feedUri] = response;
}
return response;
}

/// <summary>
/// Given the URI of a nuget method, returns the URI of the feed itself without the method and query parameters.
/// </summary>
/// <param name="methodUri">URI of nuget method.</param>
/// <returns>URI of the feed without the method and query parameters.</returns>
private static Uri GetTruncatedFeedUri(Uri methodUri)
{
string truncatedUriString = methodUri.GetLeftPart(UriPartial.Path);
int lastSeparatorIndex = truncatedUriString.LastIndexOf('/');
if (lastSeparatorIndex != -1)
{
truncatedUriString = truncatedUriString.Substring(0, lastSeparatorIndex);
}
Uri truncatedUri = new Uri(truncatedUriString);
return truncatedUri;
}

/// <summary>
/// Clears static credentials previously cached by GetCredentialFromProvider.
/// </summary>
public static void ClearCachedCredentials()
{
cachedCredentialsByFeedUri.Clear();
}

/// <summary>
/// Internal function called by GetCredentialFromProvider to implement retrieving credentials. For performance reasons,
/// most functions should call GetCredentialFromProvider in order to take advantage of cached credentials.
/// </summary>
private static CredentialProviderResponse? GetCredentialFromProvider_Uncached(Uri feedUri, bool downloadIfMissing)
{
LogVerbose("Getting credential for {0}", feedUri);

// Build the list of possible locations to find the credential provider. In order it should be local app data, paths set on the
// environment varaible, and lastly look at the root of the pacakges save location.
List<string> possibleCredentialProviderPaths = new List<string>();
Expand Down Expand Up @@ -1651,7 +1698,7 @@ private static void DownloadCredentialProviders(Uri feedUri)
if(downloadIfMissing)
{
DownloadCredentialProviders(feedUri);
return GetCredentialFromProvider(feedUri, false);
return GetCredentialFromProvider_Uncached(feedUri, false);
}

return null;
Expand Down
3 changes: 3 additions & 0 deletions Assets/NuGet/Editor/NugetPackageSource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -535,6 +535,8 @@ private static void ComparePackageLists(List<NugetPackage> updates, List<NugetPa
/// <returns>A list of all updates available.</returns>
private List<NugetPackage> GetUpdatesFallback(IEnumerable<NugetPackage> installedPackages, bool includePrerelease = false, bool includeAllVersions = false, string targetFrameworks = "", string versionContraints = "")
{
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
Debug.Assert(string.IsNullOrEmpty(targetFrameworks) && string.IsNullOrEmpty(versionContraints)); // These features are not supported by this version of GetUpdates.

List<NugetPackage> updates = new List<NugetPackage>();
Expand All @@ -556,6 +558,7 @@ private List<NugetPackage> GetUpdatesFallback(IEnumerable<NugetPackage> installe
updates.AddRange(packageUpdates);
}

NugetHelper.LogVerbose("NugetPackageSource.GetUpdatesFallback took {0} ms", stopwatch.ElapsedMilliseconds);
return updates;
}
}
Expand Down
5 changes: 5 additions & 0 deletions Assets/NuGet/Editor/NugetWindow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,11 @@ private void Refresh(bool forceFullRefresh)

try
{
if (forceFullRefresh)
{
NugetHelper.ClearCachedCredentials();
}

// reload the NuGet.config file, in case it was changed after Unity opened, but before the manager window opened (now)
NugetHelper.LoadNugetConfigFile();

Expand Down

0 comments on commit 6c04461

Please sign in to comment.