public void TryParseFloatRangeMatchingTest(string versionString, string pattern, bool isMatch) { NuGetVersion version = new NuGetVersion(versionString); FloatRange floatRange; Assert.True(NuGetVersionHelper.TryParseFloatRangeEx(pattern, out floatRange)); Assert.Equal(isMatch, floatRange.Satisfies(version)); }
public void IsSupportedVersionStringTest(string versionString, bool isSupported) { Assert.Equal(isSupported, NuGetVersionHelper.IsSupportedVersionString(versionString)); }
public void TryParseFloatRangeReturnsExpectedBoolFlag(string versionString, bool isFloatingVersion) { Assert.Equal(isFloatingVersion, NuGetVersionHelper.TryParseFloatRangeEx(versionString, out _)); }
public IPackageMetadata ResolveSource(string workingDirectory, PackageRequestRef request) { var components = request.Uri.Split(new[] { '|' }, 2); var repository = NormalizeScheme(components[0]); var packageName = components[1]; var version = request.GitRef; var semVerRegex = new Regex("^[0-9]\\.[0-9]\\.[0-9](\\-.*)?$"); var gitHashRegex = new Regex("^[0-9a-fA-F]{40}$"); var shouldQuerySourceRepository = false; if (semVerRegex.IsMatch(version)) { // This is a semantic version; leave as-is. } else if (gitHashRegex.IsMatch(version)) { // This is a Git hash, convert it to NuGet's semantic version. version = NuGetVersionHelper.CreateNuGetPackageVersion(version, request.Platform); } else { // This is a branch, or other kind of source reference. We need // to query the source repository to resolve it to a Git hash. shouldQuerySourceRepository = true; } string serviceJson; var serviceIndex = _packageRequestCache.TryGetOptionallyCachedJsonObject( repository, !request.ForceUpgrade, out serviceJson, id => GetData(new Uri(id))); string registrationsBaseUrl = null; foreach (var entry in serviceIndex.resources) { var entryType = (string)entry["@type"]; if (entryType == "RegistrationsBaseUrl") { registrationsBaseUrl = (string)entry["@id"]; } } if (registrationsBaseUrl == null) { throw new InvalidOperationException("Unable to locate RegistrationsBaseUrl service."); } var packageMetadataUrl = $"{registrationsBaseUrl.TrimEnd(new[] {'/'})}/{packageName.ToLowerInvariant()}/index.json"; string packageMetadataJson; var packageMetadata = _packageRequestCache.TryGetOptionallyCachedJsonObject( packageMetadataUrl, !request.ForceUpgrade && request.IsStaticReference, out packageMetadataJson, id => GetData(new Uri(id))); string latestPackageVersion = null; foreach (var item in packageMetadata.items) { if (latestPackageVersion == null || string.CompareOrdinal((string)item.upper, latestPackageVersion) > 0) { latestPackageVersion = item.upper; } } var packagesByVersionLock = new object(); var packagesByVersion = new Dictionary <string, dynamic>(); if (_hostPlatformDetector.DetectPlatform() == "Windows") { // Do this in parallel as we may need to make multiple HTTPS requests. Parallel.ForEach((IEnumerable <object>)packageMetadata.items, item => PopulatePackagesByVersion(packagesByVersionLock, packagesByVersion, (dynamic)item, request)); } else { // Parallelisation is not safe on this platform, do it sequentually. foreach (var item in packageMetadata.items) { PopulatePackagesByVersion(packagesByVersionLock, packagesByVersion, item, request); } } string packageType = PackageManager.PACKAGE_TYPE_LIBRARY; string sourceCodeUrl = null; string commitHashForSourceResolve = null; if (shouldQuerySourceRepository) { var lookupVersion = latestPackageVersion; if (!packagesByVersion.ContainsKey(lookupVersion) && packagesByVersion.ContainsKey(lookupVersion + "+git.unspecified")) { lookupVersion += "+git.unspecified"; } sourceCodeUrl = ExtractSourceRepository(packagesByVersion[lookupVersion]); packageType = ExtractPackageType(packagesByVersion[lookupVersion]); if (!string.IsNullOrWhiteSpace(sourceCodeUrl)) { if (sourceCodeUrl.StartsWith("git=")) { sourceCodeUrl = sourceCodeUrl.Substring("git=".Length); var performGitLsRemote = true; if (sourceCodeUrl.StartsWith("https://github.com/")) { try { // This is a GitHub repository. During the installation of Protobuild Manager (hosted on GitHub), we need // to resolve the latest version on NuGet, but we can't do this because Git may not be in the PATH or may // not be available. We still want developers to be able to install Protobuild Manager without Git on // their PATH (as they may have dedicated shells to use it), so we attempt to use the GitHub API to resolve // the commit hash first. string gitHubJsonInfo; var gitHubComponents = sourceCodeUrl.Substring("https://github.com/".Length).Split('/'); var gitHubOwner = gitHubComponents[0]; var gitHubRepo = gitHubComponents[1]; var gitHubApiUrl = "https://api.github.com/repos/" + gitHubOwner + "/" + gitHubRepo + "/branches/" + version; var gitHubJson = _packageRequestCache.TryGetOptionallyCachedJsonObject( gitHubApiUrl, !request.ForceUpgrade && request.IsStaticReference, out packageMetadataJson, id => { using (var client = new RetryableWebClient()) { client.SilentOnError = true; client.SetHeader("User-Agent", "Protobuild NuGet Lookup/v1.0"); client.SetHeader("Accept", "application/vnd.github.v3+json"); return(client.DownloadString(gitHubApiUrl)); } }); var commitHash = gitHubJson.commit.sha; if (!string.IsNullOrWhiteSpace(commitHash)) { // This is a match and we've found our Git hash to use. version = NuGetVersionHelper.CreateNuGetPackageVersion(commitHash.Trim(), request.Platform); commitHashForSourceResolve = commitHash.Trim(); performGitLsRemote = false; } } catch (Exception) { Console.WriteLine("NOTICE: Unable to lookup version information via GitHub API; falling back to 'git ls-remote'"); } } if (performGitLsRemote) { var heads = _packageRequestCache.TryGetOptionallyCachedData( "git:" + sourceCodeUrl, !request.ForceUpgrade && request.IsStaticReference, id => GitUtils.RunGitAndCapture( workingDirectory, null, "ls-remote --heads " + new Uri(sourceCodeUrl))); var lines = heads.Split(new string[] { "\r\n", "\n", "\r" }, StringSplitOptions.RemoveEmptyEntries); foreach (var line in lines) { var sourceEntryComponents = line.Split('\t'); if (sourceEntryComponents.Length >= 2) { var branchName = sourceEntryComponents[1].Trim(); if (branchName.StartsWith("refs/heads/")) { branchName = branchName.Substring("refs/heads/".Length); } else { continue; } if (string.Equals(version, branchName, StringComparison.InvariantCulture)) { // This is a match and we've found our Git hash to use. version = NuGetVersionHelper.CreateNuGetPackageVersion( sourceEntryComponents[0].Trim(), request.Platform); commitHashForSourceResolve = sourceEntryComponents[0].Trim(); break; } } } } } else { throw new InvalidOperationException("Unknown source code repository type '" + sourceCodeUrl + "'"); } // If we fall out of this loop, we'll hit the next if statement and most likely fail. } } string binaryUri = null; string binaryFormat = null; if (!packagesByVersion.ContainsKey(version)) { if (string.IsNullOrWhiteSpace(sourceCodeUrl)) { throw new InvalidOperationException( "Unable to resolve binary package for version \"" + version + "\" and platform \"" + request.Platform + "\" and this package does not have a source repository"); } else { RedirectableConsole.WriteLine("Unable to resolve binary package for version \"" + version + "\" and platform \"" + request.Platform + "\", falling back to source version"); } } else { sourceCodeUrl = ExtractSourceRepository(packagesByVersion[version]); packageType = ExtractPackageType(packagesByVersion[version]); if (!string.IsNullOrWhiteSpace(sourceCodeUrl)) { if (sourceCodeUrl.StartsWith("git=")) { sourceCodeUrl = sourceCodeUrl.Substring("git=".Length); } else { throw new InvalidOperationException("Unknown source code repository type '" + sourceCodeUrl + "'"); } } if (commitHashForSourceResolve == null) { commitHashForSourceResolve = ExtractCommitHash(packagesByVersion[version]); } // packageContent may not be under catalogEntry; our best guess is that NuGet // moved it from the root to catalogEntry at some point in the past, but not // all of the registrations are updated with it under catalogEntry, e.g. RestSharp try { binaryUri = packagesByVersion[version].catalogEntry.packageContent; } catch { binaryUri = packagesByVersion[version].packageContent; } binaryFormat = PackageManager.ARCHIVE_FORMAT_NUGET_ZIP; } return(new NuGet3PackageMetadata( repository, packageName, packageType, sourceCodeUrl, request.Platform, version, binaryFormat, binaryUri, commitHashForSourceResolve, (workingDirectoryAlt, metadata, folder, name, upgrade, source) => { if (source == true) { _sourcePackageResolve.Resolve(workingDirectoryAlt, metadata, folder, name, upgrade); } else { _binaryPackageResolve.Resolve(workingDirectoryAlt, metadata, folder, name, upgrade); } })); }