/// <summary> /// Query source repository for latest package base given package id /// </summary> internal static async Task <UIPackageMetadata> GetLatestPackageByIdFromSrcRepo(this SourceRepository srcRepo, string packageId) { // 7 references none of which uses bool includePrerelease = true, bool includeUnlisted = false var metadataResource = await srcRepo.GetResourceAndValidateAsync <UIMetadataResource>(); return(await metadataResource.GetLatestPackageByIdFromMetaRes(packageId)); }
/// <summary> /// Helper function to download package from given url, and place package (only 'content' folder from package) to given folder /// </summary> /// <param name="identity">Package identity</param> /// <param name="destinationFolder">Folder where we copy the package content (content folder only) to</param> /// <param name="pathToLocalCopyOfNupkg">File path where we copy the nudpk to</param> /// <returns></returns> public static async Task DownloadPackageToFolder(this SourceRepository srcRepo, PackageIdentity identity, string destinationFolder, string pathToLocalCopyOfNupkg) { var downloadResource = await srcRepo.GetResourceAndValidateAsync <DownloadResource>(); using (Stream packageStream = await srcRepo.GetPackageStream(identity)) { WriteStreamToFile(packageStream, pathToLocalCopyOfNupkg); // set position back to the head of stream packageStream.Position = 0; using (ZipFile zipFile = ZipFile.Read(packageStream)) { // we only care about stuff under "content" folder int substringStartIndex = @"content/".Length; IEnumerable <ZipEntry> contentEntries = zipFile.Entries.Where(e => e.FileName.StartsWith(@"content/", StringComparison.InvariantCultureIgnoreCase)); foreach (var entry in contentEntries) { string fullPath = Path.Combine(destinationFolder, entry.FileName.Substring(substringStartIndex)); FileSystemHelpers.EnsureDirectory(Path.GetDirectoryName(fullPath)); using (Stream writeStream = FileSystemHelpers.OpenWrite(fullPath)) { // let the thread go with itself, so that once file finsihed writing, doesn`t need to request thread context from main thread await entry.OpenReader().CopyToAsync(writeStream).ConfigureAwait(false); } } } } }
/// <summary> /// Query result by search term, always include pre-released /// </summary> public static async Task <IEnumerable <UIPackageMetadata> > Search(this SourceRepository srcRepo, string searchTerm, SearchFilter filterOptions = null, int skip = 0, int take = 1000) { // always include pre-release package if (filterOptions == null) { filterOptions = new SearchFilter(); } filterOptions.IncludePrerelease = true; // keep the good old behavior var searchResource = await srcRepo.GetResourceAndValidateAsync <SearchLatestResource>(); // When using nuget.org, we only look at packages that have our tag. Later, we should switch to filtering // by PackageType once nuget.org starts supporting that if (srcRepo.PackageSource.Source.StartsWith("https://www.nuget.org/", StringComparison.InvariantCultureIgnoreCase)) { if (String.IsNullOrWhiteSpace(searchTerm)) { // No user provided search string: just search by tag searchTerm = "tags:AzureSiteExtension"; } else if (searchTerm.Contains(":")) { // User provided complex query with fields: add it as is to the tag field query searchTerm = $"tags:AzureSiteExtension {searchTerm}"; } else { // User provided simple string: treat it as a title. This is not ideal behavior, but // is the best we can do based on how nuget.org works searchTerm = $"tags:AzureSiteExtension title:\"{searchTerm}\""; } } return(await searchResource.Search(searchTerm, filterOptions, skip, take, CancellationToken.None)); }
/// <summary> /// <para>Query source repository for a package base on given package id and version</para> /// <para>Will also query pre-release and unlisted packages</para> /// </summary> /// <param name="packageId">Package id, must not be null</param> /// <param name="version">Package version, must not be null</param> /// <returns>Package metadata</returns> public static async Task<UIPackageMetadata> GetPackageByIdentity(this SourceRepository srcRepo, string packageId, string version) { var metadataResource = await srcRepo.GetResourceAndValidateAsync<UIMetadataResource>(); NuGetVersion expectedVersion = NuGetVersion.Parse(version); var identity = new PackageIdentity(packageId, expectedVersion); return await metadataResource.GetMetadata(identity, CancellationToken.None); }
public async Task <IEnumerable <SiteExtensionInfo> > GetRemoteExtensions(string filter, bool allowPrereleaseVersions, string feedUrl) { ITracer tracer = _traceFactory.GetTracer(); var extensions = new List <SiteExtensionInfo>(); IEnumerable <SourceRepository> remoteRepos = GetRemoteRepositories(feedUrl); SearchFilter filterOptions = new SearchFilter(); filterOptions.IncludePrerelease = allowPrereleaseVersions; IEnumerable <UIPackageMetadata> packages = new List <UIPackageMetadata>(); using (tracer.Step("Search site extensions by filter: {0}", filter)) { foreach (SourceRepository remoteRepo in remoteRepos) { var foundUIPackages = await remoteRepo.Search(string.IsNullOrWhiteSpace(filter)?string.Empty : filter, filterOptions : filterOptions); if (null != foundUIPackages && foundUIPackages.Count() > 0) { packages = packages.Concat(foundUIPackages); } } packages = packages.OrderByDescending(p => p.DownloadCount); } using (tracer.Step("Convert search result to SiteExtensionInfos with max concurrent requests: {0}", System.Environment.ProcessorCount)) { // GetResourceAsync is not thread safe var metadataResource = await _localRepository.GetResourceAndValidateAsync <UIMetadataResource>(); var convertedResult = await ConvertNuGetPackagesToSiteExtensionInfos( packages, async (uiPackage) => { // this function is called in multiple threads simoutaneously return(await ConvertRemotePackageToSiteExtensionInfo(uiPackage, feedUrl, metadataResource)); }); extensions.AddRange(convertedResult); } return(extensions); }
/// <summary> /// Query result by search term, always include pre-released /// </summary> public static async Task<IEnumerable<UIPackageMetadata>> Search(this SourceRepository srcRepo, string searchTerm, SearchFilter filterOptions = null, int skip = 0, int take = 1000) { // always include pre-release package if (filterOptions == null) { filterOptions = new SearchFilter(); } filterOptions.IncludePrerelease = true; // keep the good old behavior var searchResource = await srcRepo.GetResourceAndValidateAsync<SearchLatestResource>(); return await searchResource.Search(searchTerm, filterOptions, skip, take, CancellationToken.None); }
/// <summary> /// <para>Query source repository for a package base on given package id and version</para> /// <para>Will also query pre-release and unlisted packages</para> /// </summary> /// <param name="packageId">Package id, must not be null</param> /// <param name="version">Package version, must not be null</param> /// <returns>Package metadata</returns> public static async Task <UIPackageMetadata> GetPackageByIdentity(this SourceRepository srcRepo, string packageId, string version) { var metadataResource = await srcRepo.GetResourceAndValidateAsync <UIMetadataResource>(); NuGetVersion expectedVersion = NuGetVersion.Parse(version); var identity = new PackageIdentity(packageId, expectedVersion); UIPackageMetadata ret = await metadataResource.GetMetadata(identity, CancellationToken.None); // When using nuget.org, we only look at packages that have our tag. if (ret != null && IsNuGetRepo(srcRepo.PackageSource.Source) && (ret.Tags.IndexOf("azuresiteextension", StringComparison.OrdinalIgnoreCase) < 0)) { ret = null; } return(ret); }
/// <summary> /// Query source repository for latest package base given package id /// </summary> public static async Task <UIPackageMetadata> GetLatestPackageById(this SourceRepository srcRepo, string packageId, bool includePrerelease = true, bool includeUnlisted = false) { UIPackageMetadata latestPackage = null; var metadataResource = await srcRepo.GetResourceAndValidateAsync <UIMetadataResource>(); IEnumerable <UIPackageMetadata> packages = await metadataResource.GetMetadata(packageId, includePrerelease, includeUnlisted, token : CancellationToken.None); foreach (var p in packages) { if (latestPackage == null || latestPackage.Identity.Version < p.Identity.Version) { latestPackage = p; } } return(latestPackage); }
/// <summary> /// Helper function to download package from given url, and place package (only 'content' folder from package) to given folder /// </summary> /// <param name="identity">Package identity</param> /// <param name="destinationFolder">Folder where we copy the package content (content folder only) to</param> /// <param name="pathToLocalCopyOfNudpk">File path where we copy the nudpk to</param> /// <returns></returns> public static async Task DownloadPackageToFolder(this SourceRepository srcRepo, PackageIdentity identity, string destinationFolder, string pathToLocalCopyOfNudpk = null) { var downloadResource = await srcRepo.GetResourceAndValidateAsync <DownloadResource>(); using (Stream sourceStream = await downloadResource.GetStream(identity, CancellationToken.None)) { if (sourceStream == null) { // package not exist from feed throw new FileNotFoundException(string.Format(CultureInfo.InvariantCulture, "Package {0} - {1} not found when try to download.", identity.Id, identity.Version.ToNormalizedString())); } Stream packageStream = sourceStream; try { if (!sourceStream.CanSeek) { // V3 DownloadResource.GetStream does not support seek operations. // https://github.com/NuGet/NuGet.Protocol/issues/15 MemoryStream memStream = new MemoryStream(); try { byte[] buffer = new byte[2048]; int bytesRead = 0; do { bytesRead = sourceStream.Read(buffer, 0, buffer.Length); memStream.Write(buffer, 0, bytesRead); } while (bytesRead != 0); await memStream.FlushAsync(); memStream.Position = 0; packageStream = memStream; } catch { memStream.Dispose(); throw; } } if (!string.IsNullOrWhiteSpace(pathToLocalCopyOfNudpk)) { string packageFolderPath = Path.GetDirectoryName(pathToLocalCopyOfNudpk); FileSystemHelpers.CreateDirectory(packageFolderPath); using (Stream writeStream = FileSystemHelpers.OpenWrite(pathToLocalCopyOfNudpk)) { OperationManager.Attempt(() => packageStream.CopyTo(writeStream)); } // set position back to the head of stream packageStream.Position = 0; } using (ZipFile zipFile = ZipFile.Read(packageStream)) { // we only care about stuff under "content" folder int substringStartIndex = @"content/".Length; IEnumerable <ZipEntry> contentEntries = zipFile.Entries.Where(e => e.FileName.StartsWith(@"content/", StringComparison.InvariantCultureIgnoreCase)); foreach (var entry in contentEntries) { string fullPath = Path.Combine(destinationFolder, entry.FileName.Substring(substringStartIndex)); FileSystemHelpers.CreateDirectory(Path.GetDirectoryName(fullPath)); using (Stream writeStream = FileSystemHelpers.OpenWrite(fullPath)) { // let the thread go with itself, so that once file finsihed writing, doesn`t need to request thread context from main thread await entry.OpenReader().CopyToAsync(writeStream).ConfigureAwait(false); } } } } finally { if (packageStream != null && !sourceStream.CanSeek) { // in this case, we created a copy of the source stream in memoery, need to manually dispose packageStream.Dispose(); } } } }