src/GetHelper.cs
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. using System; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using static System.Environment; using System.Globalization; using System.IO; using System.Linq; using System.Management.Automation; using System.Net; using System.Runtime.InteropServices; using System.Text.RegularExpressions; using System.Threading; using Microsoft.PowerShell.PowerShellGet.RepositorySettings; using MoreLinq.Extensions; using Newtonsoft.Json; using NuGet.Common; using NuGet.Configuration; using NuGet.Packaging.Core; using NuGet.Protocol; using NuGet.Protocol.Core.Types; using NuGet.Versioning; namespace Microsoft.PowerShell.PowerShellGet.Cmdlets { /// <summary> /// Find helper class /// </summary> class GetHelper : PSCmdlet { private CancellationToken cancellationToken; private readonly bool update; private readonly PSCmdlet cmdletPassedIn; public static readonly string OsPlatform = System.Runtime.InteropServices.RuntimeInformation.OSDescription; private string programFilesPath; private string myDocumentsPath; public GetHelper(CancellationToken cancellationToken, PSCmdlet cmdletPassedIn) { this.cancellationToken = cancellationToken; this.cmdletPassedIn = cmdletPassedIn; } public List<PSObject> ProcessGetParams(string[] name, string version, bool prerelease, string path) { var dirsToSearch = new List<string>(); if (path != null) { cmdletPassedIn.WriteDebug(string.Format("Provided path is: '{0}'", path)); dirsToSearch.AddRange(Directory.GetDirectories(path).ToList()); } else { // PSModules path var psModulePath = Environment.GetEnvironmentVariable("PSModulePath"); var modulePaths = psModulePath.Split(';'); #if NET472 programFilesPath = System.IO.Path.Combine(Environment.GetFolderPath(SpecialFolder.ProgramFiles), "WindowsPowerShell"); myDocumentsPath = System.IO.Path.Combine(Environment.GetFolderPath(SpecialFolder.MyDocuments), "WindowsPowerShell"); #else // If PS6+ on Windows if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { myDocumentsPath = System.IO.Path.Combine(Environment.GetFolderPath(SpecialFolder.MyDocuments), "PowerShell"); programFilesPath = System.IO.Path.Combine(Environment.GetFolderPath(SpecialFolder.ProgramFiles), "PowerShell"); } else { // Paths are the same for both Linux and MacOS myDocumentsPath = System.IO.Path.Combine(Environment.GetFolderPath(SpecialFolder.LocalApplicationData), "powershell"); programFilesPath = System.IO.Path.Combine("/usr", "local", "share", "powershell"); } #endif cmdletPassedIn.WriteDebug(string.Format("Current user scope path: '{0}'", myDocumentsPath)); cmdletPassedIn.WriteDebug(string.Format("All users scope path: '{0}'", programFilesPath)); /*** Will search first in PSModulePath, then will search in default paths ***/ foreach (var modulePath in modulePaths) { dirsToSearch.AddRange(Directory.GetDirectories(modulePath).ToList()); } var pfModulesPath = System.IO.Path.Combine(programFilesPath, "Modules"); if (Directory.Exists(pfModulesPath)) { dirsToSearch.AddRange(Directory.GetDirectories(pfModulesPath).ToList()); } var mdModulesPath = System.IO.Path.Combine(myDocumentsPath, "Modules"); if (Directory.Exists(mdModulesPath)) { dirsToSearch.AddRange(Directory.GetDirectories(mdModulesPath).ToList()); } var pfScriptsPath = System.IO.Path.Combine(programFilesPath, "Scripts", "InstalledScriptInfos"); if (Directory.Exists(pfScriptsPath)) { dirsToSearch.AddRange(Directory.GetFiles(pfScriptsPath).ToList()); } var mdScriptsPath = System.IO.Path.Combine(myDocumentsPath, "Scripts", "InstalledScriptInfos"); if (Directory.Exists(mdScriptsPath)) { dirsToSearch.AddRange(Directory.GetFiles(mdScriptsPath).ToList()); } // uniqueify dirsToSearch = dirsToSearch.Distinct().ToList(); } foreach (var dir in dirsToSearch) { cmdletPassedIn.WriteDebug(string.Format("All directories to search: '{0}'", dir)); } // Or a list of the passed in names if (name != null && !name[0].Equals("*")) { var nameLowerCased = new List<string>(); var scriptXMLnames = new List<string>(); Array.ForEach(name, n => nameLowerCased.Add(n.ToLower())); Array.ForEach(name, n => scriptXMLnames.Add((n + "_InstalledScriptInfo.xml").ToLower())); dirsToSearch = dirsToSearch.FindAll(p => (nameLowerCased.Contains(new DirectoryInfo(p).Name.ToLower()) || scriptXMLnames.Contains((System.IO.Path.GetFileName(p)).ToLower()))); cmdletPassedIn.WriteDebug(dirsToSearch.Any().ToString()); } // try to parse into a specific NuGet version VersionRange versionRange = null; if (version != null) { NuGetVersion specificVersion; NuGetVersion.TryParse(version, out specificVersion); if (specificVersion != null) { // exact version versionRange = new VersionRange(specificVersion, true, specificVersion, true, null, null); cmdletPassedIn.WriteDebug(string.Format("A specific version, '{0}', is specified", versionRange.ToString())); } else { // check if version range versionRange = VersionRange.Parse(version); cmdletPassedIn.WriteDebug(string.Format("A version range, '{0}', is specified", versionRange.ToString())); } } List<string> installedPkgsToReturn = new List<string>(); IEnumerable<string> returnPkgs = null; //2) use above list to check // if the version specificed is a version range if (versionRange != null) { foreach (var pkgPath in dirsToSearch) { cmdletPassedIn.WriteDebug(string.Format("Searching through package path: '{0}'", pkgPath)); var versionsDirs = Directory.GetDirectories(pkgPath); foreach (var versionPath in versionsDirs) { cmdletPassedIn.WriteDebug(string.Format("Searching through package version path: '{0}'", versionPath)); NuGetVersion dirAsNugetVersion; var dirInfo = new DirectoryInfo(versionPath); NuGetVersion.TryParse(dirInfo.Name, out dirAsNugetVersion); cmdletPassedIn.WriteDebug(string.Format("Directory parsed as NuGet version: '{0}'", dirAsNugetVersion)); if (versionRange.Satisfies(dirAsNugetVersion)) { // just search scripts paths if (pkgPath.ToLower().Contains("Scripts")) { if (File.Exists(pkgPath)) { installedPkgsToReturn.Add(pkgPath); } } else { // modules paths versionsDirs = Directory.GetDirectories(pkgPath); cmdletPassedIn.WriteDebug(string.Format("Getting sub directories from : '{0}'", pkgPath)); // Check if the pkg path actually has version sub directories. if (versionsDirs.Length != 0) { Array.Sort(versionsDirs, StringComparer.OrdinalIgnoreCase); Array.Reverse(versionsDirs); var pkgXmlFilePath = System.IO.Path.Combine(versionsDirs.First(), "PSGetModuleInfo.xml"); // TODO: check if this xml file exists, if it doesn't check if it exists in a previous version cmdletPassedIn.WriteDebug(string.Format("Found module XML: '{0}'", pkgXmlFilePath)); installedPkgsToReturn.Add(pkgXmlFilePath); } } installedPkgsToReturn.Add(versionPath); } } } } else { cmdletPassedIn.WriteDebug("No version provided-- check each path for the requested package"); // if no version is specified, just get the latest version foreach (var pkgPath in dirsToSearch) { cmdletPassedIn.WriteDebug(string.Format("Searching through package path: '{0}'", pkgPath)); // just search scripts paths if (pkgPath.ToLower().Contains("scripts")) { if (File.Exists(pkgPath)) //check to make sure properly formatted { installedPkgsToReturn.Add(pkgPath); } } else { // modules paths string[] versionsDirs = new string[0]; versionsDirs = Directory.GetDirectories(pkgPath); // Check if the pkg path actually has version sub directories. if (versionsDirs.Length != 0) { Array.Sort(versionsDirs, StringComparer.OrdinalIgnoreCase); Array.Reverse(versionsDirs); var pkgXmlFilePath = System.IO.Path.Combine(versionsDirs.First(), "PSGetModuleInfo.xml"); // TODO: check if this xml file exists, if it doesn't check if it exists in a previous version cmdletPassedIn.WriteDebug(string.Format("Found package XML: '{0}'", pkgXmlFilePath)); installedPkgsToReturn.Add(pkgXmlFilePath); } } } } // Flatten returned pkgs before displaying output returnedPkgsFound.Flatten().ToList()[0] var flattenedPkgs = installedPkgsToReturn.Flatten(); List<PSObject> foundInstalledPkgs = new List<PSObject>(); foreach (string xmlFilePath in flattenedPkgs) { cmdletPassedIn.WriteDebug(string.Format("Reading package metadata from: '{0}'", xmlFilePath)); // Open xml and read metadata from it if (File.Exists(xmlFilePath)) { ReadOnlyPSMemberInfoCollection<PSPropertyInfo> nameInfo; ReadOnlyPSMemberInfoCollection<PSPropertyInfo> versionInfo; ReadOnlyPSMemberInfoCollection<PSPropertyInfo> typeInfo; ReadOnlyPSMemberInfoCollection<PSPropertyInfo> descriptionInfo; ReadOnlyPSMemberInfoCollection<PSPropertyInfo> authorInfo; ReadOnlyPSMemberInfoCollection<PSPropertyInfo> companyNameInfo; ReadOnlyPSMemberInfoCollection<PSPropertyInfo> copyrightInfo; ReadOnlyPSMemberInfoCollection<PSPropertyInfo> publishedDateInfo; ReadOnlyPSMemberInfoCollection<PSPropertyInfo> installedDateInfo; ReadOnlyPSMemberInfoCollection<PSPropertyInfo> updatedDateInfo; ReadOnlyPSMemberInfoCollection<PSPropertyInfo> licenseUriInfo; ReadOnlyPSMemberInfoCollection<PSPropertyInfo> projectUriInfo; ReadOnlyPSMemberInfoCollection<PSPropertyInfo> iconUriInfo; ReadOnlyPSMemberInfoCollection<PSPropertyInfo> tagsInfo; ReadOnlyPSMemberInfoCollection<PSPropertyInfo> includesInfo; ReadOnlyPSMemberInfoCollection<PSPropertyInfo> powerShellGetFormatVersionInfo; ReadOnlyPSMemberInfoCollection<PSPropertyInfo> releaseNotesInfo; ReadOnlyPSMemberInfoCollection<PSPropertyInfo> dependenciesInfo; ReadOnlyPSMemberInfoCollection<PSPropertyInfo> repositorySourceLocationInfo; ReadOnlyPSMemberInfoCollection<PSPropertyInfo> repositoryInfo; ReadOnlyPSMemberInfoCollection<PSPropertyInfo> additionalMetadataInfo; ReadOnlyPSMemberInfoCollection<PSPropertyInfo> installedLocationInfo; //var isPrelease = false; using (StreamReader sr = new StreamReader(xmlFilePath)) { string text = sr.ReadToEnd(); var deserializedObj = (PSObject)PSSerializer.Deserialize(text); nameInfo = deserializedObj.Properties.Match("Name"); versionInfo = deserializedObj.Properties.Match("Version"); typeInfo = deserializedObj.Properties.Match("Type"); descriptionInfo = deserializedObj.Properties.Match("Description"); authorInfo = deserializedObj.Properties.Match("Author"); companyNameInfo = deserializedObj.Properties.Match("CompanyName"); copyrightInfo = deserializedObj.Properties.Match("Copyright"); publishedDateInfo = deserializedObj.Properties.Match("PublishedDate"); installedDateInfo = deserializedObj.Properties.Match("InstalledDate"); updatedDateInfo = deserializedObj.Properties.Match("UpdatedDate"); licenseUriInfo = deserializedObj.Properties.Match("LicenseUri"); projectUriInfo = deserializedObj.Properties.Match("ProjectUri"); iconUriInfo = deserializedObj.Properties.Match("IconUri"); tagsInfo = deserializedObj.Properties.Match("Tags"); includesInfo = deserializedObj.Properties.Match("Includes"); powerShellGetFormatVersionInfo = deserializedObj.Properties.Match("PowerShellGetFormatVersion"); releaseNotesInfo = deserializedObj.Properties.Match("ReleaseNotes"); dependenciesInfo = deserializedObj.Properties.Match("Dependencies"); repositorySourceLocationInfo = deserializedObj.Properties.Match("RepositorySourceLocation"); repositoryInfo = deserializedObj.Properties.Match("Repository"); additionalMetadataInfo = deserializedObj.Properties.Match("AdditionalMetadata"); installedLocationInfo = deserializedObj.Properties.Match("InstalledLocation"); /* // testing adding prerelease parameter additionalMetadataInfo = deserializedObj.Properties.Match("AdditionalMetadata"); if (additionalMetadataInfo.Any()) { isPrelease = additionalMetadataInfo.FirstOrDefault().Value.ToString().Contains("IsPrerelease=true"); if ((isPrelease == true) && _prerelease) // find a stable version of the pkg {} } */ }; // if -Prerelease is not passed in as a parameter, don't allow prerelease pkgs to be returned, // we still want all pkgs to be returned if -Prerelease is passed in as a param //if ((_prerelease == false && isPrelease == false) || _prerelease == true) //{ //var foundPkgs = List<PSObject>(); PSObject pkgAsPSObject = new PSObject(); try { pkgAsPSObject.Members.Add(new PSNoteProperty("Name", nameInfo.Any()? nameInfo.FirstOrDefault().Value : string.Empty)); pkgAsPSObject.Members.Add(new PSNoteProperty("Version", versionInfo.Any()? versionInfo.FirstOrDefault().Value : string.Empty)); pkgAsPSObject.Members.Add(new PSNoteProperty("Type", typeInfo.Any()? typeInfo.FirstOrDefault().Value : string.Empty)); pkgAsPSObject.Members.Add(new PSNoteProperty("Description", descriptionInfo.Any()? descriptionInfo.FirstOrDefault().Value : string.Empty)); pkgAsPSObject.Members.Add(new PSNoteProperty("Author", authorInfo.Any()? authorInfo.FirstOrDefault().Value : string.Empty)); pkgAsPSObject.Members.Add(new PSNoteProperty("CompanyName", companyNameInfo.Any()? companyNameInfo.FirstOrDefault().Value : string.Empty)); pkgAsPSObject.Members.Add(new PSNoteProperty("Copyright", copyrightInfo.Any()? copyrightInfo.FirstOrDefault().Value : string.Empty)); pkgAsPSObject.Members.Add(new PSNoteProperty("PublishedDate", publishedDateInfo.Any()? publishedDateInfo.FirstOrDefault().Value : string.Empty)); pkgAsPSObject.Members.Add(new PSNoteProperty("InstalledDate", installedDateInfo.Any()? installedDateInfo.FirstOrDefault().Value : string.Empty)); pkgAsPSObject.Members.Add(new PSNoteProperty("UpdatedDate", updatedDateInfo.Any()? updatedDateInfo.FirstOrDefault().Value : string.Empty)); pkgAsPSObject.Members.Add(new PSNoteProperty("LicenseUri", licenseUriInfo.Any()? licenseUriInfo.FirstOrDefault().Value : string.Empty)); pkgAsPSObject.Members.Add(new PSNoteProperty("ProjectUri", projectUriInfo.Any()? projectUriInfo.FirstOrDefault().Value : string.Empty)); pkgAsPSObject.Members.Add(new PSNoteProperty("IconUri", iconUriInfo.Any()? iconUriInfo.FirstOrDefault().Value : string.Empty)); pkgAsPSObject.Members.Add(new PSNoteProperty("Tags", tagsInfo.Any()? tagsInfo.FirstOrDefault().Value : string.Empty)); pkgAsPSObject.Members.Add(new PSNoteProperty("Includes", includesInfo.Any()? includesInfo.FirstOrDefault().Value : string.Empty)); pkgAsPSObject.Members.Add(new PSNoteProperty("PowerShellGetFormatVersion", powerShellGetFormatVersionInfo.Any()? powerShellGetFormatVersionInfo.FirstOrDefault().Value : string.Empty)); pkgAsPSObject.Members.Add(new PSNoteProperty("ReleaseNotes", releaseNotesInfo.Any()? releaseNotesInfo.FirstOrDefault().Value : string.Empty)); pkgAsPSObject.Members.Add(new PSNoteProperty("Dependencies", dependenciesInfo.Any()? dependenciesInfo.FirstOrDefault().Value : string.Empty)); pkgAsPSObject.Members.Add(new PSNoteProperty("RepositorySourceLocation", repositorySourceLocationInfo.Any()? repositorySourceLocationInfo.FirstOrDefault().Value : string.Empty)); pkgAsPSObject.Members.Add(new PSNoteProperty("Repository", repositoryInfo.Any()? repositoryInfo.FirstOrDefault().Value : string.Empty)); pkgAsPSObject.Members.Add(new PSNoteProperty("AdditionalMetadata", additionalMetadataInfo.Any()? additionalMetadataInfo.FirstOrDefault().Value : string.Empty)); pkgAsPSObject.Members.Add(new PSNoteProperty("InstalledLocation", installedLocationInfo.Any()? installedLocationInfo.FirstOrDefault().Value : string.Empty)); // verify that this works, then add the object to a list and return it //WriteObject(pkgAsPSObject); foundInstalledPkgs.Add(pkgAsPSObject); } catch { } } } // return here return foundInstalledPkgs; } } } |