internal static void GetInstalledZipPackage(PackageJson package, PackageSourceListRequest request) { try { if (request.AddToPath.Value) { request.Verbose(Resources.Messages.AddOrRemovePath, Constants.ProviderName, "AddToPath", "Install-Package"); } if (request.RemoveFromPath.Value) { request.Verbose(Resources.Messages.AddOrRemovePath, Constants.ProviderName, "RemoveFromPath", "Uninstall-Package"); } string path = Path.Combine(package.Destination, package.Name, package.Version); if (Directory.Exists(path)) { if (Directory.EnumerateFiles(path, "*", SearchOption.AllDirectories).Any()) { string userSpecifiedProvider = request.GetOptionValue("ProviderName") ?? request.GetOptionValue("Provider"); var fp = PackageSourceListRequest.MakeFastPathComplex(package.Source, package.Name, (package.DisplayName ?? ""), package.Version, path, userSpecifiedProvider ?? ""); //the directory exists and contain files, we think the package has been installed. request.YieldSoftwareIdentity(fp, package.Name, package.Version, package.VersionScheme, package.Summary, path, package.Name, path, path); } } } catch (Exception e) { request.Debug(e.StackTrace); } }
private void UnInstallMsiPackage(PackageSourceListRequest request, string fastPath, PackageJson package) { request.Debug(Resources.Messages.DebugInfoCallMethod, PackageProviderName, string.Format(CultureInfo.InvariantCulture, "UnInstallMsiPackage' - name='{0}', fastPath='{1}'", package.Name, fastPath)); string sourceLocation; string id; string displayName; string version; string fastPackageReference; if (!request.TryParseFastPathComplex(fastPath: fastPath, regex: PackageSourceListRequest.RegexFastPathComplex, location: out sourceLocation, id: out id, displayname: out displayName, version: out version, fastpath: out fastPackageReference)) { //we don't need to error out even if fastpath is not correct because msi provider is expected to handle the uninstall-package. request.Verbose(Resources.Messages.UnsupportMSIUninstall, Constants.ProviderName, package.Name); return; } // Normally uninstall-package will be handled by MSI provider. Here we added a special case for handling uninstall-package nodejs // which msi provider unable to deal with (node.js only for msi) if (id != null && id.EqualsIgnoreCase("nodejs")) { var provider = PackageSourceListRequest.FindProvider(request, Constants.ProviderNames.Msi, request); if (provider != null) { if (!_fastPackReftable.ContainsKey(fastPackageReference)) { request.WriteError(ErrorCategory.InvalidData, fastPackageReference, Resources.Messages.FailedToGetPackageObject, Constants.ProviderName, fastPackageReference); return; } request.Verbose(Resources.Messages.UninstallingPackage, Constants.ProviderName, package.Name); var p = _fastPackReftable[fastPackageReference]; var installing = provider.UninstallPackage(p, request); foreach (var i in installing) { request.YieldSoftwareIdentity(i.FastPackageReference, i.Name, i.Version, i.VersionScheme, i.Summary, package.Source, i.SearchKey, i.FullPath, i.PackageFilename); if (request.IsCanceled) { installing.Cancel(); } return; } } } else { //no-op for uninstalling the msi packages. only install-package nodejs is supported because msi can not handle it request.Verbose(Resources.Messages.UnsupportMSIUninstall, Constants.ProviderName, package.Name); return; } }
internal static bool VerifyHash(string fileFullPath, PackageJson package, PackageSourceListRequest request) { //skip in case the skip switch is specified if (request.SkipHashValidation.Value) { request.Verbose(Resources.Messages.SkipHashValidation); return(true); } PackageHash packageHash = package.Hash; if (packageHash == null || string.IsNullOrWhiteSpace(packageHash.algorithm) || string.IsNullOrWhiteSpace(packageHash.hashCode)) { request.WriteError(ErrorCategory.InvalidArgument, Constants.ProviderName, Resources.Messages.HashNotSpecified, package.Name); return(false); } try { string hashAlgorithm = packageHash.algorithm.ToLowerInvariant(); if (!("sha256".Equals(hashAlgorithm) || "md5".Equals(hashAlgorithm) || "sha512".Equals(hashAlgorithm))) { request.WriteError(ErrorCategory.InvalidArgument, Constants.ProviderName, Resources.Messages.InvalidHashAlgorithm, packageHash.algorithm); return(false); } // compute the hash string computedHash = ComputeHash(fileFullPath, hashAlgorithm, request); if (computedHash == null) { request.WriteError(ErrorCategory.InvalidOperation, Constants.ProviderName, Resources.Messages.HashVerificationFailed, package.Name, package.Source); return(false); } // hash from json string hashFromJSON = package.Hash.hashCode; //compare computed hash with hash from json if (!hashFromJSON.Equals(computedHash)) { request.WriteError(ErrorCategory.InvalidOperation, Constants.ProviderName, Resources.Messages.HashVerificationFailed, package.Name, package.Source); return(false); } else { request.Verbose(Resources.Messages.HashValidationSuccessfull); } } catch { request.WriteError(ErrorCategory.InvalidOperation, Constants.ProviderName, Resources.Messages.HashVerificationFailed, package.Name, package.Source); return(false); } return(true); }
/// <summary> /// Uninstalls a package /// </summary> /// <param name="package">package defined in the PackageSourceList</param> /// <param name="fastPackageReference"></param> /// <param name="request">An object passed in from the PackageManagement that contains functions that can be used to interact with its Provider</param> /// <param name="fastPackReftable"></param> internal static void UninstallNuGetPackage(PackageJson package, string fastPackageReference, PackageSourceListRequest request, Dictionary <string, SoftwareIdentity> fastPackReftable) { if (request == null) { throw new ArgumentNullException("request"); } var destination = package.Destination; // PSL will call NuGet to uninstall the package when: 1) a user explictly specifies -providerName psl; or // 2) the psl.json file contains the defintion of Destination. // Otherwise, NuGet will handle the uninstall-package // string userSpecifiedProvider = request.GetOptionValue("ProviderName") ?? request.GetOptionValue("Provider"); string providerNameFromPipeline = request.GetProviderNameFromFastPathComplex(fastPackageReference); if ((string.IsNullOrWhiteSpace(userSpecifiedProvider) || !Constants.ProviderName.EqualsIgnoreCase(userSpecifiedProvider) && (string.IsNullOrWhiteSpace(providerNameFromPipeline) || !Constants.ProviderName.EqualsIgnoreCase(providerNameFromPipeline))) && string.IsNullOrWhiteSpace(destination)) { request.Verbose(Resources.Messages.UninstallPackageNotSupported, Constants.ProviderName, package.Name, Constants.ProviderNames.NuGet); return; } request.Debug(Resources.Messages.DebugInfoCallMethod, Constants.ProviderName, "Calling UninstallNuGetPackage"); var unInstallRequest = PackageSourceListRequest.ExtendRequest( new Dictionary <string, string[]> { { "Destination", new[] { destination } } }, null, request); var provider = PackageSourceListRequest.FindProvider(request, package.Type, request, true); if (provider != null) { request.Debug("{0}: Using the provider '{1} to uninstall the package '{2}'", Constants.ProviderName, provider.Name, package.Name); if (!fastPackReftable.ContainsKey(fastPackageReference)) { request.WriteError(ErrorCategory.InvalidData, fastPackageReference, Resources.Messages.FailedToGetPackageObject, Constants.ProviderName, fastPackageReference); return; } var p = fastPackReftable[fastPackageReference]; //calling NuGet for uninstall var installing = provider.UninstallPackage(p, unInstallRequest); foreach (var i in installing) { request.YieldSoftwareIdentity(i.FastPackageReference, i.Name, i.Version, i.VersionScheme, i.Summary, i.Source, i.SearchKey, i.FullPath, i.PackageFilename); if (request.IsCanceled) { installing.Cancel(); } } } }
private static IEnumerable <PackageJson> GetDependencies(PackageJson packageJson, PackageSourceListRequest request) { if (packageJson.DependencyObjects == null) { yield break; } bool force = request.GetOptionValue("Force") != null; foreach (var dep in packageJson.DependencyObjects.Where(dep => (dep != null) && !dep.IsCommonDefinition)) { if (!force) { var provider = PackageSourceListRequest.FindProvider(request, dep.Type, request, true); if (provider == null) { //FindProvider logged an error already break; } //Check whether the dependency package is installed var installedPackages = provider.GetInstalledPackages(dep.Name, requiredVersion: null, minimumVersion: dep.Version, maximumVersion: null, requestObject: request); if (installedPackages == null || !installedPackages.Any()) { request.Verbose(Resources.Messages.DependencyNotInstalled, dep.Name); yield return(dep); } else { request.Verbose(Resources.Messages.DependencyInstalled, dep.Name); } } else { yield return(dep); } } }
private bool ValidatePackageManagementVersion(PackageSourceListRequest request) { var userSpecifiedProvider = request.GetOptionValue("ProviderName") ?? request.GetOptionValue("Provider"); if (_currentPackageManagementVersion == null) { var moduleInfo = GetModule("PackageManagement"); if (moduleInfo == null || !moduleInfo.Any()) { request.Verbose(Resources.Messages.CannotFindPackageManagementVersion); return(false); } _currentPackageManagementVersion = moduleInfo.OrderByDescending(each => each.Version).FirstOrDefault().Version; if (_currentPackageManagementVersion < new Version(RequiredPackageManagementVersion)) { _doesPackageManagementVersionMatch = false; } else { _doesPackageManagementVersionMatch = true; } } if (!_doesPackageManagementVersionMatch) { if (userSpecifiedProvider != null && userSpecifiedProvider.IndexOf(Constants.ProviderName, StringComparison.OrdinalIgnoreCase) > -1) { request.WriteError(ErrorCategory.InvalidOperation, Constants.ProviderName, Resources.Messages.MinimumVersionCheck, Constants.ProviderName, RequiredPackageManagementVersion, _currentPackageManagementVersion); } else { request.Verbose(Resources.Messages.MinimumVersionCheck, Constants.ProviderName, RequiredPackageManagementVersion, _currentPackageManagementVersion); } } return(_doesPackageManagementVersionMatch); }
/// <summary> /// Uninstalls a package /// </summary> /// <param name="package">package defined in the PackageSourceList</param> /// <param name="fastPackageReference"></param> /// <param name="request">An object passed in from the PackageManagement that contains functions that can be used to interact with its Provider</param> /// <param name="fastPackReftable"></param> internal static void UninstallPowershellArtifacts(PackageJson package, string fastPackageReference, PackageSourceListRequest request, Dictionary <string, SoftwareIdentity> fastPackReftable) { if (request == null) { throw new ArgumentNullException("request"); } // If a user explicitly specifies -providerName psl, e.g., uninstall-package -providername psl -name xjea, // PSL will call PowerShellGet to uninstall the package. // Otherwise, it is expected that PowerShellGet will handle the uninstall-package and PSL won't // participate in the uninstall operation, e.g., uninstall-package xjea string userSpecifiedProvider = request.GetOptionValue("ProviderName") ?? request.GetOptionValue("Provider"); string providerNameFromPipeline = request.GetProviderNameFromFastPathComplex(fastPackageReference); if ((string.IsNullOrWhiteSpace(userSpecifiedProvider) || !Constants.ProviderName.EqualsIgnoreCase(userSpecifiedProvider)) && string.IsNullOrWhiteSpace(providerNameFromPipeline) || !Constants.ProviderName.EqualsIgnoreCase(providerNameFromPipeline)) { request.Verbose(Resources.Messages.UninstallPackageNotSupported, Constants.ProviderName, package.Name, Constants.ProviderNames.PowerShellGet); return; } request.Debug(Resources.Messages.DebugInfoCallMethod, Constants.ProviderName, "Calling UninstallPowershellArtifacts"); var provider = PackageSourceListRequest.FindProvider(request, package.Type, request, true); if (provider != null) { request.Debug("{0}: Using the provider '{1} to uninstall the package '{2}'", Constants.ProviderName, provider.Name, package.Name); if (!fastPackReftable.ContainsKey(fastPackageReference)) { request.WriteError(Internal.ErrorCategory.InvalidData, fastPackageReference, Resources.Messages.FailedToGetPackageObject, Constants.ProviderName, fastPackageReference); return; } var p = fastPackReftable[fastPackageReference]; //calling NuGet for uninstall var installing = provider.UninstallPackage(p, request); foreach (var i in installing) { request.YieldSoftwareIdentity(i.FastPackageReference, i.Name, i.Version, i.VersionScheme, i.Summary, i.Source, i.SearchKey, i.FullPath, i.PackageFilename); if (request.IsCanceled) { installing.Cancel(); } } } }
private static void InstallPackageFile(PackageJson package, string fastPath, PackageSourceListRequest request) { request.Debug(Resources.Messages.DebugInfoCallMethod, Constants.ProviderName, string.Format(CultureInfo.InvariantCulture, "InstallPackageFile' - name='{0}', fastPath='{1}'", package.Name, fastPath)); // get a temp file name, msi or msu var providerType = package.Type.ToLowerInvariant(); var destination = Path.ChangeExtension(Path.GetTempFileName(), providerType); //download the msi package to the temp file WebDownloader.DownloadFile(package.Source, destination, request, null); if (!File.Exists(destination)) { return; } // validate the file if (!WebDownloader.VerifyHash(destination, package, request)) { return; } if (!package.IsTrustedSource) { if (!request.ShouldContinueWithUntrustedPackageSource(package.Name, package.Source)) { request.Warning(Constants.Messages.UserDeclinedUntrustedPackageInstall, package.Name); return; } } var installRequest = PackageSourceListRequest.ExtendRequest(new Dictionary <string, string[]> { { "Source", new[] { package.Source ?? "" } } }, new[] { package.Source ?? "" }, package.IsTrustedSource, request); request.Verbose(Resources.Messages.CallMsiForInstall, package.Name); if (request.ProviderServices.Install(destination, "", installRequest)) { // it installed ok!exit request.YieldFromSwidtag(package, fastPath); return; } else { request.WriteError(ErrorCategory.InvalidOperation, Constants.ProviderName, Resources.Messages.PackageFailedInstall, package.Name); } }
internal PackageQuery(PackageSource packageSource, PackageSourceListRequest request) { if (packageSource == null) { throw new ArgumentNullException("packageSource"); } if(string.IsNullOrWhiteSpace(packageSource.Location) || !System.IO.File.Exists(packageSource.Location)) { request.Warning(Resources.Messages.PackageSourceManifestNotFound, packageSource.Location, Constants.ProviderName); return; } Uri uri; if (Uri.TryCreate(packageSource.Location, UriKind.Absolute, out uri)) { if (uri.IsFile) { try { //process the file _PackageSourceList = JsonParser.ReadPackageSpec(packageSource, null); } catch (Exception ex) { request.Warning(ex.Message); while (ex.InnerException != null) { ex = ex.InnerException; request.Warning(ex.Message); } request.Warning(string.Format(CultureInfo.CurrentCulture, Resources.Messages.InvalidPackageListFormat, uri.AbsolutePath)); ex.Dump(request); } } // Uri? //TODO: ask a user whether go ahead for downloading an sample PSL.json } else { //TODO: Check with GP, DSC Settings, request.Verbose(Resources.Messages.UnsupportedPackageSource, packageSource.Location); return; } }
internal PackageQuery(PackageSource packageSource, PackageSourceListRequest request) { if (packageSource == null) { throw new ArgumentNullException("packageSource"); } if (string.IsNullOrWhiteSpace(packageSource.Location) || !System.IO.File.Exists(packageSource.Location)) { request.Warning(Resources.Messages.PackageSourceManifestNotFound, packageSource.Location, Constants.ProviderName); return; } Uri uri; if (Uri.TryCreate(packageSource.Location, UriKind.Absolute, out uri)) { if (uri.IsFile) { try { //process the file _PackageSourceList = JsonParser.ReadPackageSpec(packageSource, null); } catch (Exception ex) { request.Warning(ex.Message); while (ex.InnerException != null) { ex = ex.InnerException; request.Warning(ex.Message); } request.Warning(string.Format(CultureInfo.CurrentCulture, Resources.Messages.InvalidPackageListFormat, uri.AbsolutePath)); ex.Dump(request); } } // Uri? //TODO: ask a user whether go ahead for downloading an sample PSL.json } else { //TODO: Check with GP, DSC Settings, request.Verbose(Resources.Messages.UnsupportedPackageSource, packageSource.Location); return; } }
internal static void GetInstalledPowershellArtifacts(PackageJson package, string requiredVersion, string minimumVersion, string maximumVersion, Dictionary <string, SoftwareIdentity> fastPackReftable, PackageSourceListRequest request) { if (request == null) { throw new ArgumentNullException("request"); } request.Debug(Resources.Messages.DebugInfoCallMethod, Constants.ProviderName, string.Format(CultureInfo.InvariantCulture, "GetInstalledPowershellArtifacts' - name='{0}', requiredVersion='{1}',minimumVersion='{2}', maximumVersion='{3}'", package.Name, requiredVersion, minimumVersion, maximumVersion)); var provider = PackageSourceListRequest.FindProvider(request, package.Type, request); if (provider == null) { return; } //calling the PowerShellGet provider request.Debug("Calling '{0}' provider to get installed packages '{1}.{2}'", provider.Name, package.Name, package.Version); var packagesInstalled = provider.GetInstalledPackages(package.Name, requiredVersion, minimumVersion, maximumVersion, request).ToArray(); if (packagesInstalled == null || !packagesInstalled.Any()) { request.Verbose(Resources.Messages.NumberOfPackagesRecevied, 0, provider.Name, "GetInstalledPackages"); return; } //Make sure the packages found are defined in the psl.json foreach (var i in packagesInstalled.Where(each => new SemanticVersion(each.Version) == new SemanticVersion(package.Version))) { request.Debug("Found an installed package '{0}.{1} from {2}' ", i.Name, i.Version, i.Source); string userSpecifiedProvider = request.GetOptionValue("ProviderName") ?? request.GetOptionValue("Provider"); var info = PackageSourceListRequest.MakeFastPathComplex(i.Source, i.Name, "", i.Version, "", userSpecifiedProvider ?? ""); fastPackReftable.AddOrSet(info, i); // check if the installed version matches with the one specified in the PSL.json. // If so, we choose PSL.json. var version = i.Version.CompareVersion(package.Version) ? package.Version : i.Version; request.YieldSoftwareIdentity(info, i.Name, version, i.VersionScheme, i.Summary, i.Source, i.SearchKey, i.FullPath, i.PackageFilename); } }
private void UnInstallMsiPackage(PackageSourceListRequest request, string fastPath, PackageJson package) { request.Debug(Resources.Messages.DebugInfoCallMethod, PackageProviderName, string.Format(CultureInfo.InvariantCulture, "UnInstallMsiPackage' - name='{0}'", package.Name)); string sourceLocation; string id; string displayName; string version; string fastPackageReference; string providerNameFromPipeline; if (!request.TryParseFastPathComplex(fastPath: fastPath, regex: PackageSourceListRequest.RegexFastPathComplex, location: out sourceLocation, id: out id, displayname: out displayName, version: out version, fastpath: out fastPackageReference, providerName: out providerNameFromPipeline)) { //we don't need to error out even if fastpath is not correct because msi provider is expected to handle the uninstall-package. request.Verbose(Resources.Messages.UninstallPackageNotSupported, Constants.ProviderName, package.Name, Constants.ProviderNames.Msi); return; } // Normally uninstall-package will be handled by MSI provider, so we do not need to handle it here. // But there are some special cases where MSI provider does not work well. // // For example, after installing the nodejs.msi (install-package nodejs), the product name appears to be "node.js". // After installing the PowerShell.msi package (install-package PowerShell), the product name appears to be "PowerShell_<Version>". // The msi provider works well if you pass in the product display name. In this case you need to use "PowerShell_Version" in // the Get-Package and UnInstall-Package. // But the msi provider will not work if you "Uninstall-Package PowerShell" or "Uninstall-Package nodejs" // Here we add some logic to let PSL try both well-known package name and the displayname. string userSpecifiedProvider = request.GetOptionValue("ProviderName") ?? request.GetOptionValue("Provider"); if ((!string.IsNullOrWhiteSpace(id) && (!string.IsNullOrWhiteSpace(displayName)) && (!id.EqualsIgnoreCase(displayName)) && (id.EqualsIgnoreCase(package.Name))) || (!string.IsNullOrWhiteSpace(providerNameFromPipeline) && Constants.ProviderName.EqualsIgnoreCase(providerNameFromPipeline)) || (!string.IsNullOrWhiteSpace(userSpecifiedProvider) && Constants.ProviderName.EqualsIgnoreCase(userSpecifiedProvider))) { var provider = PackageSourceListRequest.FindProvider(request, Constants.ProviderNames.Msi, request); if (provider != null) { if (!_fastPackReftable.ContainsKey(fastPackageReference)) { request.WriteError(ErrorCategory.InvalidData, fastPackageReference, Resources.Messages.FailedToGetPackageObject, Constants.ProviderName, fastPackageReference); return; } request.Verbose(Resources.Messages.UninstallingPackage, Constants.ProviderName, package.Name); var p = _fastPackReftable[fastPackageReference]; var installing = provider.UninstallPackage(p, request); foreach (var i in installing) { request.YieldSoftwareIdentity(i.FastPackageReference, i.Name, i.Version, i.VersionScheme, i.Summary, package.Source, i.SearchKey, i.FullPath, i.PackageFilename); if (request.IsCanceled) { installing.Cancel(); } return; } } } else { //no-op for uninstalling the msi packages. only install-package nodejs is supported because msi can not handle it request.Verbose(Resources.Messages.UninstallPackageNotSupported, Constants.ProviderName, package.Name, Constants.ProviderNames.Msi); return; } }
private static void InstallPackageFile(PackageJson package, string fastPath, PackageSourceListRequest request) { request.Debug(Resources.Messages.DebugInfoCallMethod, Constants.ProviderName, string.Format(CultureInfo.InvariantCulture, "InstallPackageFile' - name='{0}'", package.Name)); // get a temp file name, msi or msu var providerType = package.Type.ToLowerInvariant(); var destination = Path.ChangeExtension(Path.GetTempFileName(), providerType); try { //download the msi package to the temp file WebDownloader.DownloadFile(package.Source, destination, request, null); if (!File.Exists(destination)) { return; } // validate the file if (!WebDownloader.VerifyHash(destination, package, request)) { return; } // For unsigned msi packages, the MSI provider will prompt a user if he wants to install it. // However if the signed msi package but the PackageSource is untrusted, MSI provider does not prompt. So we prompt here. if (request.ProviderServices.IsSignedAndTrusted(destination, request)) { if (!request.ShouldContinueWithUntrustedPackageSource(package.Name, package.Source)) { request.Warning(Constants.Messages.UserDeclinedUntrustedPackageInstall, package.Name); return; } } if (!string.IsNullOrWhiteSpace(package.Destination)) { request.Verbose(Resources.Messages.DestinationNotSupported, package.Type); } var installRequest = PackageSourceListRequest.ExtendRequest(new Dictionary <string, string[]> { { "Source", new[] { package.Source ?? "" } } }, new[] { package.Source ?? "" }, request); request.Verbose(Resources.Messages.CallMsiForInstall, package.Name); if (request.ProviderServices.Install(destination, "", installRequest)) { // it installed ok!exit request.YieldFromSwidtag(package, fastPath); return; } else { request.WriteError(ErrorCategory.InvalidOperation, Constants.ProviderName, Resources.Messages.PackageFailedInstall, package.Name); } } finally { if (File.Exists(destination)) { destination.TryHardToDelete(); } } }
public void GetInstalledPackages(string name, string requiredVersion, string minimumVersion, string maximumVersion, PackageSourceListRequest request) { if (request == null) { throw new ArgumentNullException("request"); } if (!ValidatePackageManagementVersion(request)) { return; } request.Debug(Resources.Messages.DebugInfoCallMethod, PackageProviderName, string.Format(CultureInfo.InvariantCulture, "GetInstalledPackages' - name='{0}', requiredVersion='{1}',minimumVersion='{2}', maximumVersion='{3}'", name, requiredVersion, minimumVersion, maximumVersion)); IEnumerable <PackageJson> packagesDefinedInJsonSpec; if (string.IsNullOrWhiteSpace(name) || WildcardPattern.ContainsWildcardCharacters(name)) { // In the case of the package name is null or contains wildcards, error out if a user puts version info if (!string.IsNullOrWhiteSpace(requiredVersion) || !string.IsNullOrWhiteSpace(minimumVersion) || !string.IsNullOrWhiteSpace(maximumVersion)) { request.Warning(Resources.Messages.WildCardCharsAreNotSupported, name); return; } packagesDefinedInJsonSpec = request.GetPackages(name).ToArray(); } else { //return all installed packagesDefinedInJsonSpec = request.GetPackages(name, requiredVersion, minimumVersion, maximumVersion).ToArray(); } _fastPackReftable.Clear(); if (!packagesDefinedInJsonSpec.Any()) { request.Verbose(Resources.Messages.NoPackageFound, Constants.ProviderName); return; } foreach (var package in packagesDefinedInJsonSpec) { switch (package.Type.ToLowerInvariant()) { case Constants.MediaType.AppxPackage: //TODO for future break; case Constants.MediaType.PsArtifacts: PowerShellArtifactInstaller.GeInstalledPowershellArtifacts(package, requiredVersion, minimumVersion, maximumVersion, _fastPackReftable, request); break; case Constants.MediaType.ExePackage: //program provider can handle get-package git for git.exe ExePackageInstaller.GetInstalledExePackages(package, requiredVersion, minimumVersion, minimumVersion, request); break; case Constants.MediaType.MsiPackage: //msi provider can handle get-package node.js for node.js.msi GetMsiInstalledPackage(name, package, requiredVersion, minimumVersion, maximumVersion, request); break; case Constants.MediaType.ZipPackage: ZipPackageInstaller.GetInstalledZipPackage(package, request); break; case Constants.MediaType.NuGetPackage: NupkgInstaller.GeInstalledNuGetPackages(package, requiredVersion, minimumVersion, maximumVersion, _fastPackReftable, request); break; } //switch } }
internal static void GeInstalledPowershellArtifacts(PackageJson package, string requiredVersion, string minimumVersion, string maximumVersion, Dictionary<string, SoftwareIdentity> fastPackReftable, PackageSourceListRequest request) { if (request == null) { throw new ArgumentNullException("request"); } request.Debug(Resources.Messages.DebugInfoCallMethod, Constants.ProviderName, string.Format(CultureInfo.InvariantCulture, "GeInstalledPowershellArtifacts' - name='{0}', requiredVersion='{1}',minimumVersion='{2}', maximumVersion='{3}'", package.Name, requiredVersion, minimumVersion, maximumVersion)); var provider = PackageSourceListRequest.FindProvider(request, package.Type, request); if (provider == null) return; //calling the PowerShellGet provider request.Debug("Calling '{0}' provider to get installed packages '{1}.{2}'", provider.Name, package.Name, package.Version); var packagesInstalled = provider.GetInstalledPackages(package.Name, requiredVersion, minimumVersion, maximumVersion, request).ToArray(); if (packagesInstalled == null || !packagesInstalled.Any()) { request.Verbose(Resources.Messages.NumberOfPackagesRecevied, 0, provider.Name, "GetInstalledPackages"); return; } foreach (var i in packagesInstalled) { request.Debug("Found an installed package '{0}.{1} from {2}' ", i.Name, i.Version, i.Source); var info = PackageSourceListRequest.MakeFastPathComplex(i.Source, i.Name, "", i.Version, ""); fastPackReftable.AddOrSet(info, i); // check if the installed version matches with the one specified in the PSL.json. // If so, we choose PSL.json. var version = i.Version.CompareVersion(package.Version) ? package.Version : i.Version; request.YieldSoftwareIdentity(info, i.Name, version, i.VersionScheme, i.Summary, i.Source, i.SearchKey, i.FullPath, i.PackageFilename); } }
internal static bool VerifyHash(string fileFullPath, PackageJson package, PackageSourceListRequest request) { //skip in case the skip switch is specified if (request.SkipHashValidation.Value) { request.Verbose(Resources.Messages.SkipHashValidation); return(true); } PackageHash packageHash = package.Hash; if (packageHash == null || string.IsNullOrWhiteSpace(packageHash.algorithm) || string.IsNullOrWhiteSpace(packageHash.hashCode)) { request.WriteError(ErrorCategory.InvalidArgument, Constants.ProviderName, Resources.Messages.HashNotSpecified, package.Name); return(false); } try { HashAlgorithm hashAlgorithm = null; switch (packageHash.algorithm.ToLowerInvariant()) { case "sha256": hashAlgorithm = SHA256.Create(); break; case "md5": hashAlgorithm = MD5.Create(); break; case "sha512": hashAlgorithm = SHA512.Create(); break; default: request.WriteError(ErrorCategory.InvalidArgument, Constants.ProviderName, Resources.Messages.InvalidHashAlgorithm, packageHash.algorithm); return(false); } using (FileStream stream = File.OpenRead(fileFullPath)) { // compute the hash byte[] computedHash = hashAlgorithm.ComputeHash(stream); // convert the original hash we got from json byte[] hashFromJSON = Convert.FromBase64String(package.Hash.hashCode); if (!Enumerable.SequenceEqual(computedHash, hashFromJSON)) { request.WriteError(ErrorCategory.InvalidOperation, Constants.ProviderName, Resources.Messages.HashVerificationFailed, package.Name, package.Source); return(false); } else { request.Verbose(Resources.Messages.HashValidationSuccessful); } } } catch { request.WriteError(ErrorCategory.InvalidOperation, Constants.ProviderName, Resources.Messages.HashVerificationFailed, package.Name, package.Source); return(false); } return(true); }
internal static PackageProvider FindProvider(PackageSourceListRequest request, string providerType, IHostApi hostApi, bool logError = false) { string providerName = null; switch (providerType.ToLowerInvariant()) { case Constants.MediaType.MsiPackage: providerName = Constants.ProviderNames.Msi; break; case Constants.MediaType.MsuPackage: providerName = Constants.ProviderNames.Msu; break; case Constants.MediaType.AppxPackage: //TODO for future whenever needed to support appx packages break; case Constants.MediaType.NuGetPackage: providerName = Constants.ProviderNames.NuGet; break; case Constants.MediaType.ZipPackage: case Constants.MediaType.ExePackage: providerName = Constants.ProviderNames.PSL; break; case Constants.MediaType.PsArtifacts: providerName = Constants.ProviderNames.PowerShellGet; break; default: request.Warning(Resources.Messages.UnsupportedProviderType, Constants.ProviderName, providerType); break; } if (string.IsNullOrWhiteSpace(providerName)) { return(null); } PackageProvider provider; if (_packageProviders.ContainsKey(providerName)) { provider = _packageProviders[providerName]; } else { provider = request.PackageManagementService.SelectProviders(providerName, request).FirstOrDefault(); if (provider != null) { _packageProviders.AddOrSet(providerName, provider); } } if (provider != null) { return(provider); } request.Verbose(Resources.Messages.ProviderNotFound, providerName); if (logError) { request.Error(ErrorCategory.InvalidOperation, providerName, Resources.Messages.ProviderNotFound, providerName); } return(null); }
/// <summary> /// This is called when the user is adding (or updating) a package source /// /// If this PROVIDER doesn't support user-defined package sources, remove this method. /// </summary> /// <param name="name">The name of the package source. If this parameter is null or empty the PROVIDER should use the location as the name (if the PROVIDER actually stores names of package sources)</param> /// <param name="location">The location (ie, directory, URL, etc) of the package source. If this is null or empty, the PROVIDER should use the name as the location (if valid)</param> /// <param name="trusted">A boolean indicating that the user trusts this package source. Packages returned from this source should be marked as 'trusted'</param> /// <param name="request">An object passed in from the PackageManagement that contains functions that can be used to interact with its Provider</param> public void AddPackageSource(string name, string location, bool trusted, PackageSourceListRequest request) { if (request == null) { throw new ArgumentNullException("request"); } if (!ValidatePackageManagementVersion(request)) { return; } try { request.Debug(Resources.Messages.DebugInfoCallMethod, PackageProviderName, "AddPackageSource - ProviderName = '{0}', name='{1}', location='{2}', trusted='{3}'", PackageProviderName, name, location, trusted); // Error out if a user does not provide package source Name if (string.IsNullOrWhiteSpace(name)) { request.WriteError(ErrorCategory.InvalidArgument, Constants.Parameters.Name, Constants.Messages.MissingRequiredParameter, Constants.Parameters.Name); return; } if (string.IsNullOrWhiteSpace(location)) { request.WriteError(ErrorCategory.InvalidArgument, Constants.Parameters.Location, Constants.Messages.MissingRequiredParameter, Constants.Parameters.Location); return; } // Set-PackageSource will update the existing package source. In that case IsUpdate = true. var isUpdate = request.GetOptionValue(Constants.Parameters.IsUpdate).IsTrue(); request.Debug(Resources.Messages.VariableCheck, "IsUpdate", isUpdate); // check first that we're not clobbering an existing source, unless this is an update request.Debug(Resources.Messages.DebugInfoCallMethod, PackageProviderName, string.Format(CultureInfo.InvariantCulture, "FindRegisteredSource -name'{0}'", name)); var src = request.FindRegisteredSource(name); if (src != null && !isUpdate) { // tell the user that there's one here already request.WriteError(ErrorCategory.InvalidArgument, name, Constants.Messages.PackageSourceExists, name); return; } // conversely, if it didn't find one, and it is an update, that's bad too: if (src == null && isUpdate) { // you can't find that package source? Tell that to the user request.WriteError(ErrorCategory.ObjectNotFound, name, Constants.Messages.UnableToResolveSource, name); return; } // ok, we know that we're ok to save this source // next we check if the location is valid (if we support that kind of thing) var validated = false; validated = request.ValidateSourceLocation(location); if (!validated) { request.WriteError(ErrorCategory.InvalidData, name, Constants.Messages.SourceLocationNotValid, location); return; } else { request.Verbose(Resources.Messages.SuccessfullyValidated, name); } bool force = request.GetOptionValue("Force") != null; //if source is UNC location/ copy it to local path; Uri uri; if (Uri.TryCreate(location, UriKind.Absolute, out uri)) { if (uri.IsFile && uri.IsUnc) { string fileName = Path.GetFileNameWithoutExtension(location); string directory = Path.GetDirectoryName(location); string catalogFilePath = Path.Combine(directory, fileName+".cat"); if (!File.Exists(catalogFilePath)) { request.WriteError(ErrorCategory.InvalidData, location, Resources.Messages.CatalogFileMissing, location); return; } if (!TestCatalogFile(location, catalogFilePath, request)) { return; } if (force || request.ShouldContinue(Resources.Messages.QueryDownloadPackageSourceList.format(location), Resources.Messages.PackageSourceListNotTrusted)) { string destination = Path.Combine(_pslDirLocation, Path.GetFileName(uri.LocalPath)); if (File.Exists(destination)) { if (force || request.ShouldContinue(Resources.Messages.OverwriteFile, Resources.Messages.FileExists)) { File.Copy(location, destination, true); location = destination; } else { return; } } else { File.Copy(location, destination); location = destination; } } else { return; } } } // it's good to check just before you actually write something to see if the user has cancelled the operation if (request.IsCanceled) { return; } // looking good -- store the package source. request.AddPackageSource(name, location, trusted, validated); // Yield the package source back to the caller. request.YieldPackageSource(name, location, trusted, true /*since we just registered it*/, validated); } catch (Exception e) { e.Dump(request); } }
internal static bool InstallExePackage(PackageJson package, string fastPath, PackageSourceListRequest request) { ProgressTracker tracker = new ProgressTracker(request.StartProgress(0, Resources.Messages.Installing)); var providerType = package.Type.ToLowerInvariant(); var exePackage = Path.ChangeExtension(Path.GetTempFileName(), providerType); if (!string.IsNullOrWhiteSpace(package.Destination)) { request.Verbose(Resources.Messages.DestinationNotSupported, package.Type); } try { WebDownloader.DownloadFile(package.Source, exePackage, request, tracker); if (File.Exists(exePackage)) { request.Verbose("Package: '{0}'", exePackage); // validate the file if (!WebDownloader.VerifyHash(exePackage, package, request)) { return(false); } if (!request.ShouldContinueWithUntrustedPackageSource(package.Name, package.Source)) { request.Warning(Constants.Messages.UserDeclinedUntrustedPackageInstall, package.Name); return(false); } // Prepare the process to run var processArguments = string.IsNullOrWhiteSpace(package.InstallArguments) ? "/VERYSILENT /CLOSEAPPLICATIONS /NORESTART /NOCANCEL /SP /qn" : package.InstallArguments; var start = new ProcessStartInfo { FileName = exePackage, Arguments = processArguments, UseShellExecute = false, RedirectStandardInput = true, RedirectStandardOutput = true, RedirectStandardError = true, CreateNoWindow = true, //LoadUserProfile = true, }; double percent = tracker.StartPercent; Timer timer = null; object timerLock = new object(); bool cleanUp = false; Action cleanUpAction = () => { lock (timerLock) { // check whether clean up is already done before or not if (!cleanUp) { try { if (timer != null) { // stop timer timer.Change(Timeout.Infinite, Timeout.Infinite); // dispose it timer.Dispose(); } } catch { } cleanUp = true; } } }; // Run the external process & wait for it to finish using (var proc = Process.Start(start)) { var timer1 = timer; timer = new Timer(_ => { percent += 0.025; // percent between startProgress and endProgress var progressPercent = tracker.ConvertPercentToProgress(percent); if (progressPercent < 90) { request.Progress(tracker.ProgressID, (int)progressPercent, Resources.Messages.InstallingPackage, package.Source); } if (request.IsCanceled) { cleanUpAction(); } }, null, 100, 3000); proc.WaitForExit(); // Retrieve the app's exit code var exitCode = proc.ExitCode; if (exitCode != 0) { request.WriteError(ErrorCategory.InvalidOperation, fastPath, Resources.Messages.InstallFailed, package.Name, proc.StandardError.ReadToEnd()); request.CompleteProgress(tracker.ProgressID, false); return(false); } else { request.CompleteProgress(tracker.ProgressID, true); request.YieldFromSwidtag(package, fastPath); request.Verbose(Resources.Messages.SuccessfullyInstalled, package.Name); } cleanUpAction(); } return(true); } else { request.WriteError(ErrorCategory.InvalidOperation, Constants.ProviderName, Resources.Messages.FailedToDownload, Constants.ProviderName, package.Source); } return(false); } catch (Exception ex) { request.Error(ErrorCategory.InvalidOperation, "install-package", ex.Message); ex.Dump(request); return(false); } finally { if (File.Exists(exePackage)) { exePackage.TryHardToDelete(); } } }
internal static bool InstallExePackage(PackageJson package, string fastPath, PackageSourceListRequest request) { ProgressTracker tracker = new ProgressTracker(request.StartProgress(0, Resources.Messages.Installing)); var exePackage = Path.ChangeExtension(Path.GetTempFileName(), "exe"); WebDownloader.DownloadFile(package.Source, exePackage, request, tracker); if (File.Exists(exePackage)) { request.Verbose("Package: '{0}'", exePackage); // validate the file if (!WebDownloader.VerifyHash(exePackage,package, request)) { return false; } if (!package.IsTrustedSource) { if (!request.ShouldContinueWithUntrustedPackageSource(package.Name, package.Source)) { request.Warning(Constants.Messages.UserDeclinedUntrustedPackageInstall, package.Name); return false; } } // Prepare the process to run var processArguments = string.IsNullOrWhiteSpace(package.InstallArguments) ? "/VERYSILENT /CLOSEAPPLICATIONS /NORESTART /NOCANCEL /SP /qn" : package.InstallArguments; var start = new ProcessStartInfo { FileName = exePackage, Arguments = processArguments, UseShellExecute = false, RedirectStandardInput = true, RedirectStandardOutput = true, RedirectStandardError = true, CreateNoWindow = true, //LoadUserProfile = true, }; double percent = tracker.StartPercent; Timer timer = null; object timerLock = new object(); bool cleanUp = false; Action cleanUpAction = () => { lock (timerLock) { // check whether clean up is already done before or not if (!cleanUp) { try { if (timer != null) { // stop timer timer.Change(Timeout.Infinite, Timeout.Infinite); // dispose it timer.Dispose(); } } catch { } cleanUp = true; } } }; // Run the external process & wait for it to finish using (var proc = Process.Start(start)) { var timer1 = timer; timer = new Timer(_ => { percent += 0.025; // percent between startProgress and endProgress var progressPercent = tracker.ConvertPercentToProgress(percent); if (progressPercent < 90) { request.Progress(tracker.ProgressID, (int)progressPercent, Resources.Messages.InstallingPackage, package.Source); } if (request.IsCanceled) { cleanUpAction(); } }, null, 100, 3000); proc.WaitForExit(); // Retrieve the app's exit code var exitCode = proc.ExitCode; if (exitCode != 0) { request.WriteError(ErrorCategory.InvalidOperation, fastPath, Resources.Messages.InstallFailed, package.Name, proc.StandardError.ReadToEnd()); request.CompleteProgress(tracker.ProgressID, false); return false; } else { request.CompleteProgress(tracker.ProgressID, true); request.YieldFromSwidtag(package, fastPath); request.Verbose(Resources.Messages.SuccessfullyInstalled, package.Name); } cleanUpAction(); } return true; } else { request.Error(ErrorCategory.InvalidOperation, Resources.Messages.FailedToDownload, Constants.ProviderName, package.Source, exePackage); } return false; }
private bool ValidatePackageManagementVersion(PackageSourceListRequest request) { var userSpecifiedProvider = request.GetOptionValue("ProviderName") ?? request.GetOptionValue("Provider"); if (_currentPackageManagementVersion == null) { var moduleInfo = GetModule("PackageManagement"); if(moduleInfo == null || !moduleInfo.Any()) { request.Verbose(Resources.Messages.CannotFindPackageManagementVersion); return false; } _currentPackageManagementVersion = moduleInfo.OrderByDescending(each => each.Version).FirstOrDefault().Version; if (_currentPackageManagementVersion < new Version(RequiredPackageManagementVersion)) { _doesPackageManagementVersionMatch = false; } else { _doesPackageManagementVersionMatch = true; } } if (!_doesPackageManagementVersionMatch) { if (userSpecifiedProvider != null && userSpecifiedProvider.IndexOf(Constants.ProviderName, StringComparison.OrdinalIgnoreCase) > -1) { request.WriteError(ErrorCategory.InvalidOperation, Constants.ProviderName, Resources.Messages.MinimumVersionCheck, Constants.ProviderName, RequiredPackageManagementVersion, _currentPackageManagementVersion); } else { request.Verbose(Resources.Messages.MinimumVersionCheck, Constants.ProviderName, RequiredPackageManagementVersion, _currentPackageManagementVersion); } } return _doesPackageManagementVersionMatch; }
private static IEnumerable<PackageJson> GetDependencies(PackageJson packageJson, PackageSourceListRequest request) { if (packageJson.DependencyObjects == null) { yield break; } bool force = request.GetOptionValue("Force") != null; foreach (var dep in packageJson.DependencyObjects.Where(dep => (dep != null) && !dep.IsCommonDefinition)) { if (!force) { var provider = PackageSourceListRequest.FindProvider(request, dep.Type, request, true); if(provider == null) { //FindProvider logged an error already break; } //Check whether the dependency package is installed var installedPackages = provider.GetInstalledPackages(dep.Name, requiredVersion: null, minimumVersion: dep.Version, maximumVersion: null, requestObject: request); if (installedPackages == null || !installedPackages.Any()) { request.Verbose(Resources.Messages.DependencyNotInstalled, dep.Name); yield return dep; } else { request.Verbose(Resources.Messages.DependencyInstalled, dep.Name); } } else { yield return dep; } } }
private static void InstallPackageFile(PackageJson package, string fastPath, PackageSourceListRequest request) { request.Debug(Resources.Messages.DebugInfoCallMethod, Constants.ProviderName, string.Format(CultureInfo.InvariantCulture, "InstallPackageFile' - name='{0}', fastPath='{1}'", package.Name, fastPath)); // get a temp file name, msi or msu var providerType = package.Type.ToLowerInvariant(); var destination = Path.ChangeExtension(Path.GetTempFileName(), providerType); //download the msi package to the temp file WebDownloader.DownloadFile(package.Source, destination, request, null); if (!File.Exists(destination)) { return; } // validate the file if (!WebDownloader.VerifyHash(destination,package, request)) { return; } if (!package.IsTrustedSource) { if (!request.ShouldContinueWithUntrustedPackageSource(package.Name, package.Source)) { request.Warning(Constants.Messages.UserDeclinedUntrustedPackageInstall, package.Name); return; } } var installRequest = PackageSourceListRequest.ExtendRequest(new Dictionary<string, string[]> { {"Source", new[] {package.Source ?? ""}} }, new[] { package.Source ?? "" }, package.IsTrustedSource, request); request.Verbose(Resources.Messages.CallMsiForInstall, package.Name); if (request.ProviderServices.Install(destination, "", installRequest)) { // it installed ok!exit request.YieldFromSwidtag(package, fastPath); return; } else { request.WriteError(ErrorCategory.InvalidOperation, Constants.ProviderName, Resources.Messages.PackageFailedInstall, package.Name); } }
internal static PackageProvider FindProvider(PackageSourceListRequest request, string providerType, IHostApi hostApi, bool logError = false) { string providerName = null; switch (providerType.ToLowerInvariant()) { case Constants.MediaType.MsiPackage: providerName = Constants.ProviderNames.Msi; break; case Constants.MediaType.MsuPackage: providerName = Constants.ProviderNames.Msu; break; case Constants.MediaType.AppxPackage: //TODO for future whenever needed to support appx packages break; case Constants.MediaType.NuGetPackage: providerName = Constants.ProviderNames.NuGet; break; case Constants.MediaType.ZipPackage: case Constants.MediaType.ExePackage: providerName = Constants.ProviderNames.PSL; break; case Constants.MediaType.PsArtifacts: providerName = Constants.ProviderNames.PowerShellGet; break; default: request.Warning(Resources.Messages.UnsupportedProviderType, providerType); break; } if (string.IsNullOrWhiteSpace(providerName)) { return null; } PackageProvider provider; if (_packageProviders.ContainsKey(providerName)) { provider = _packageProviders[providerName]; } else { provider = request.PackageManagementService.SelectProviders(providerName, request).FirstOrDefault(); if (provider != null) { _packageProviders.AddOrSet(providerName, provider); } } if (provider != null) { return provider; } request.Verbose(Resources.Messages.ProviderNotFound, providerName); if (logError) { request.Error(ErrorCategory.InvalidOperation, providerName, Resources.Messages.ProviderNotFound, providerName); } return null; }
internal static string DownloadFile(string queryUrl, string destination, PackageSourceListRequest request, ProgressTracker progressTracker) { try { request.Debug(Resources.Messages.DebugInfoCallMethod, Constants.ProviderName, string.Format(System.Globalization.CultureInfo.InvariantCulture, "DownloadFile - url='{0}', destination='{1}'", queryUrl, destination)); if (string.IsNullOrWhiteSpace(destination)) { throw new ArgumentNullException("destination"); } // make sure that the parent folder is created first. var folder = Path.GetDirectoryName(destination); if (!Directory.Exists(folder)) { Directory.CreateDirectory(folder); } if (File.Exists(destination)) { destination.TryHardToDelete(); } if (progressTracker == null) { progressTracker = new ProgressTracker(request.StartProgress(0, Resources.Messages.DownloadingPackage, queryUrl)); } Uri uri; if (!Uri.TryCreate(queryUrl, UriKind.Absolute, out uri)) { request.Error(Internal.ErrorCategory.InvalidOperation, Resources.Messages.UnsupportedUriFormat, Constants.ProviderName, queryUrl); return null; } if (uri.IsFile) { // downloading from a file share using (var input = File.OpenRead(queryUrl)) { using (var output = new FileStream(destination, FileMode.Create, FileAccess.Write, FileShare.Read)) { request.Progress(progressTracker.ProgressID, progressTracker.StartPercent, Resources.Messages.Downloading); input.CopyTo(output); } } request.CompleteProgress(progressTracker.ProgressID, true); } else { //Downloading from url var result = DownloadDataToFileAsync(destination, queryUrl, request, PathUtility.GetNetworkCredential(request.CredentialUsername, request.CredentialPassword), progressTracker).Result; } if (File.Exists(destination)) { request.Verbose(Resources.Messages.CompletedDownload, queryUrl); return destination; } else { request.Error(Internal.ErrorCategory.InvalidOperation, Resources.Messages.FailedToDownload, Constants.ProviderName, queryUrl, destination); return null; } } catch (Exception ex) { ex.Dump(request); request.Warning(ex.Message); return null; } }
internal static bool VerifyHash(string fileFullPath,PackageJson package, PackageSourceListRequest request) { //skip in case the skip switch is specified if (request.SkipHashValidation.Value) { request.Verbose(Resources.Messages.SkipHashValidation); return true; } PackageHash packageHash = package.Hash; if (packageHash==null || string.IsNullOrWhiteSpace(packageHash.algorithm) || string.IsNullOrWhiteSpace(packageHash.hashCode)) { request.WriteError(ErrorCategory.InvalidArgument, Constants.ProviderName, Resources.Messages.HashNotSpecified, package.Name); return false; } try { HashAlgorithm hashAlgorithm = null; switch (packageHash.algorithm.ToLowerInvariant()) { case "sha256": hashAlgorithm = SHA256.Create(); break; case "md5": hashAlgorithm = MD5.Create(); break; case "sha512": hashAlgorithm = SHA512.Create(); break; default: request.WriteError(ErrorCategory.InvalidArgument, Constants.ProviderName, Resources.Messages.InvalidHashAlgorithm, packageHash.algorithm); return false; } using (FileStream stream = File.OpenRead(fileFullPath)) { // compute the hash byte[] computedHash = hashAlgorithm.ComputeHash(stream); // convert the original hash we got from json byte[] hashFromJSON = Convert.FromBase64String(package.Hash.hashCode); if (!Enumerable.SequenceEqual(computedHash, hashFromJSON)) { request.WriteError(ErrorCategory.InvalidOperation, Constants.ProviderName, Resources.Messages.HashVerificationFailed, package.Name, package.Source); return false; } else { request.Verbose(Resources.Messages.HashValidationSuccessful); } } } catch { request.WriteError(ErrorCategory.InvalidOperation, Constants.ProviderName, Resources.Messages.HashVerificationFailed, package.Name, package.Source); return false; } return true; }
internal static string DownloadFile(string queryUrl, string destination, PackageSourceListRequest request, ProgressTracker progressTracker) { try { request.Debug(Resources.Messages.DebugInfoCallMethod, Constants.ProviderName, string.Format(System.Globalization.CultureInfo.InvariantCulture, "DownloadFile - url='{0}', destination='{1}'", queryUrl, destination)); if (string.IsNullOrWhiteSpace(destination)) { throw new ArgumentNullException("destination"); } // make sure that the parent folder is created first. var folder = Path.GetDirectoryName(destination); if (!Directory.Exists(folder)) { Directory.CreateDirectory(folder); } if (File.Exists(destination)) { destination.TryHardToDelete(); } if (progressTracker == null) { progressTracker = new ProgressTracker(request.StartProgress(0, Resources.Messages.DownloadingPackage, queryUrl)); } Uri uri; if (!Uri.TryCreate(queryUrl, UriKind.Absolute, out uri)) { request.Error(Internal.ErrorCategory.InvalidOperation, Resources.Messages.UnsupportedUriFormat, Constants.ProviderName, queryUrl); return(null); } if (uri.IsFile) { // downloading from a file share using (var input = File.OpenRead(queryUrl)) { using (var output = new FileStream(destination, FileMode.Create, FileAccess.Write, FileShare.Read)) { request.Progress(progressTracker.ProgressID, progressTracker.StartPercent, Resources.Messages.Downloading); input.CopyTo(output); } } request.CompleteProgress(progressTracker.ProgressID, true); } else { //Downloading from url var result = DownloadDataToFileAsync(destination, queryUrl, request, PathUtility.GetNetworkCredential(request.CredentialUsername, request.CredentialPassword), progressTracker).Result; } if (File.Exists(destination)) { request.Verbose(Resources.Messages.CompletedDownload, queryUrl); return(destination); } else { request.Error(Internal.ErrorCategory.InvalidOperation, Resources.Messages.FailedToDownload, Constants.ProviderName, queryUrl, destination); return(null); } } catch (Exception ex) { ex.Dump(request); request.Warning(ex.Message); return(null); } }
/// <summary> /// Download data from remote via uri query. /// </summary> /// <param name="fileName">A file to store the downloaded data.</param> /// <param name="query">Uri query</param> /// <param name="request">An object passed in from the PackageManagement platform that contains APIs that can be used to interact with it </param> /// <param name="networkCredential">Credential to pass along to get httpclient</param> /// <param name="progressTracker">Utility class to help track progress</param> /// <returns></returns> internal static async Task<long> DownloadDataToFileAsync(string fileName, string query, PackageSourceListRequest request, NetworkCredential networkCredential, ProgressTracker progressTracker) { request.Verbose(Resources.Messages.DownloadingPackage, query); // try downloading for 3 times int remainingTry = 3; long totalDownloaded = 0; CancellationTokenSource cts; Stream input = null; FileStream output = null; while (remainingTry > 0) { // if user cancel the request, no need to do anything if (request.IsCanceled) { break; } input = null; output = null; cts = new CancellationTokenSource(); totalDownloaded = 0; try { // decrease try by 1 remainingTry -= 1; var httpClient = request.Client; httpClient.DefaultRequestHeaders.TryAddWithoutValidation("User-Agent", "text/html; charset=iso-8859-1"); input = await httpClient.GetStreamAsync(query); // buffer size of 64 KB, this seems to be preferable buffer size, not too small and not too big byte[] bytes = new byte[1024 * 64]; output = File.Open(fileName, FileMode.OpenOrCreate, FileAccess.Write, FileShare.Read); int current = 0; // here we read content that we got from the http response stream into the bytes array current = await input.ReadAsync(bytes, 0, bytes.Length, cts.Token); int progressPercentage = progressTracker.StartPercent; // report initial progress request.Progress(progressTracker.ProgressID, progressPercentage, Resources.Messages.BytesRead, current); int i = progressTracker.StartPercent; while (current > 0) { totalDownloaded += current; // here we write out the bytes array into the file await output.WriteAsync(bytes, 0, current, cts.Token); // report the progress request.Progress(progressTracker.ProgressID, progressPercentage<progressTracker.EndPercent?progressPercentage++:progressTracker.EndPercent, Resources.Messages.BytesRead, totalDownloaded); // continue reading from the stream current = await input.ReadAsync(bytes, 0, bytes.Length, cts.Token); } if (totalDownloaded > 0) { // report that we finished the download request.Progress(progressTracker.ProgressID, progressTracker.EndPercent, Resources.Messages.BytesRead, totalDownloaded); request.CompleteProgress(progressTracker.ProgressID, true); return totalDownloaded; } // if request is canceled, don't retry if (request.IsCanceled) { return 0; } } catch (Exception ex) { request.CompleteProgress(progressTracker.ProgressID, true); request.Verbose(ex.Message); request.Debug(ex.StackTrace); } finally { // dispose input and output stream if (input != null) { input.Dispose(); } // dispose it if (output != null) { output.Dispose(); } // delete the file if created and nothing has downloaded if (totalDownloaded == 0 && File.Exists(fileName)) { fileName.TryHardToDelete(); } if (cts != null) { cts.Dispose(); } } // we have to retry again request.Verbose(Resources.Messages.RetryingDownload, query, remainingTry); } return totalDownloaded; }
/// <summary> /// Download data from remote via uri query. /// </summary> /// <param name="fileName">A file to store the downloaded data.</param> /// <param name="query">Uri query</param> /// <param name="request">An object passed in from the PackageManagement platform that contains APIs that can be used to interact with it </param> /// <param name="networkCredential">Credential to pass along to get httpclient</param> /// <param name="progressTracker">Utility class to help track progress</param> /// <returns></returns> internal static async Task <long> DownloadDataToFileAsync(string fileName, string query, PackageSourceListRequest request, NetworkCredential networkCredential, ProgressTracker progressTracker) { request.Verbose(Resources.Messages.DownloadingPackage, query); // try downloading for 3 times int remainingTry = 3; long totalDownloaded = 0; CancellationTokenSource cts; Stream input = null; FileStream output = null; while (remainingTry > 0) { // if user cancel the request, no need to do anything if (request.IsCanceled) { break; } input = null; output = null; cts = new CancellationTokenSource(); totalDownloaded = 0; try { // decrease try by 1 remainingTry -= 1; var httpClient = request.Client; httpClient.DefaultRequestHeaders.TryAddWithoutValidation("User-Agent", "text/html; charset=iso-8859-1"); input = await httpClient.GetStreamAsync(query); // buffer size of 64 KB, this seems to be preferable buffer size, not too small and not too big byte[] bytes = new byte[1024 * 64]; output = File.Open(fileName, FileMode.OpenOrCreate, FileAccess.Write, FileShare.Read); int current = 0; // here we read content that we got from the http response stream into the bytes array current = await input.ReadAsync(bytes, 0, bytes.Length, cts.Token); int progressPercentage = progressTracker.StartPercent; // report initial progress request.Progress(progressTracker.ProgressID, progressPercentage, Resources.Messages.BytesRead, current); int i = progressTracker.StartPercent; while (current > 0) { totalDownloaded += current; // here we write out the bytes array into the file await output.WriteAsync(bytes, 0, current, cts.Token); // report the progress request.Progress(progressTracker.ProgressID, progressPercentage < progressTracker.EndPercent?progressPercentage++:progressTracker.EndPercent, Resources.Messages.BytesRead, totalDownloaded); // continue reading from the stream current = await input.ReadAsync(bytes, 0, bytes.Length, cts.Token); } if (totalDownloaded > 0) { // report that we finished the download request.Progress(progressTracker.ProgressID, progressTracker.EndPercent, Resources.Messages.BytesRead, totalDownloaded); request.CompleteProgress(progressTracker.ProgressID, true); return(totalDownloaded); } // if request is canceled, don't retry if (request.IsCanceled) { return(0); } } catch (Exception ex) { request.CompleteProgress(progressTracker.ProgressID, true); request.Verbose(ex.Message); request.Debug(ex.StackTrace); } finally { // dispose input and output stream if (input != null) { input.Dispose(); } // dispose it if (output != null) { output.Dispose(); } // delete the file if created and nothing has downloaded if (totalDownloaded == 0 && File.Exists(fileName)) { fileName.TryHardToDelete(); } if (cts != null) { cts.Dispose(); } } // we have to retry again request.Verbose(Resources.Messages.RetryingDownload, query, remainingTry); } return(totalDownloaded); }
/// <summary> /// This is called when the user is adding (or updating) a package source /// /// If this PROVIDER doesn't support user-defined package sources, remove this method. /// </summary> /// <param name="name">The name of the package source. If this parameter is null or empty the PROVIDER should use the location as the name (if the PROVIDER actually stores names of package sources)</param> /// <param name="location">The location (ie, directory, URL, etc) of the package source. If this is null or empty, the PROVIDER should use the name as the location (if valid)</param> /// <param name="trusted">A boolean indicating that the user trusts this package source. Packages returned from this source should be marked as 'trusted'</param> /// <param name="request">An object passed in from the PackageManagement that contains functions that can be used to interact with its Provider</param> public void AddPackageSource(string name, string location, bool trusted, PackageSourceListRequest request) { if (request == null) { throw new ArgumentNullException("request"); } if (!ValidatePackageManagementVersion(request)) { return; } try { request.Debug(Resources.Messages.DebugInfoCallMethod, PackageProviderName, "AddPackageSource - ProviderName = '{0}', name='{1}', location='{2}', trusted='{3}'", PackageProviderName, name, location, trusted); // Error out if a user does not provide package source Name if (string.IsNullOrWhiteSpace(name)) { request.WriteError(ErrorCategory.InvalidArgument, Constants.Parameters.Name, Constants.Messages.MissingRequiredParameter, Constants.Parameters.Name); return; } if (string.IsNullOrWhiteSpace(location)) { request.WriteError(ErrorCategory.InvalidArgument, Constants.Parameters.Location, Constants.Messages.MissingRequiredParameter, Constants.Parameters.Location); return; } // Set-PackageSource will update the existing package source. In that case IsUpdate = true. var isUpdate = request.GetOptionValue(Constants.Parameters.IsUpdate).IsTrue(); request.Debug(Resources.Messages.VariableCheck, "IsUpdate", isUpdate); // check first that we're not clobbering an existing source, unless this is an update request.Debug(Resources.Messages.DebugInfoCallMethod, PackageProviderName, string.Format(CultureInfo.InvariantCulture, "FindRegisteredSource -name'{0}'", name)); var src = request.FindRegisteredSource(name); if (src != null && !isUpdate) { // tell the user that there's one here already request.WriteError(ErrorCategory.InvalidArgument, name, Constants.Messages.PackageSourceExists, name); return; } // conversely, if it didn't find one, and it is an update, that's bad too: if (src == null && isUpdate) { // you can't find that package source? Tell that to the user request.WriteError(ErrorCategory.ObjectNotFound, name, Constants.Messages.UnableToResolveSource, name); return; } // ok, we know that we're ok to save this source // next we check if the location is valid (if we support that kind of thing) var validated = false; validated = request.ValidateSourceLocation(location); if (!validated) { request.WriteError(ErrorCategory.InvalidData, name, Constants.Messages.SourceLocationNotValid, location); return; } else { request.Verbose(Resources.Messages.SuccessfullyValidated, name); } bool force = request.GetOptionValue("Force") != null; //if source is UNC location/ copy it to local path; Uri uri; if (Uri.TryCreate(location, UriKind.Absolute, out uri)) { if (uri.IsFile && uri.IsUnc) { string fileName = Path.GetFileNameWithoutExtension(location); string directory = Path.GetDirectoryName(location); string catalogFilePath = Path.Combine(directory, fileName + ".cat"); if (!File.Exists(catalogFilePath)) { request.WriteError(ErrorCategory.InvalidData, location, Resources.Messages.CatalogFileMissing, location); return; } if (!TestCatalogFile(location, catalogFilePath, request)) { return; } if (force || request.ShouldContinue(Resources.Messages.QueryDownloadPackageSourceList.format(location), Resources.Messages.PackageSourceListNotTrusted)) { string destination = Path.Combine(_pslDirLocation, Path.GetFileName(uri.LocalPath)); if (File.Exists(destination)) { if (force || request.ShouldContinue(Resources.Messages.OverwriteFile, Resources.Messages.FileExists)) { File.Copy(location, destination, true); location = destination; } else { return; } } else { File.Copy(location, destination); location = destination; } } else { return; } } } // it's good to check just before you actually write something to see if the user has cancelled the operation if (request.IsCanceled) { return; } // looking good -- store the package source. request.AddPackageSource(name, location, trusted, validated); // Yield the package source back to the caller. request.YieldPackageSource(name, location, trusted, true /*since we just registered it*/, validated); } catch (Exception e) { e.Dump(request); } }
private static void InstallPackageViaPowerShellGet(PackageJson packageJson, PackageSourceListRequest request, SoftwareIdentity[] packages) { var provider = PackageSourceListRequest.FindProvider(request, packageJson.Type, request, true); if (provider == null) return; IHostApi installRequest = request; if (provider.Name.EqualsIgnoreCase(Constants.ProviderNames.PowerShellGet) && !request.ProviderServices.IsElevated) { // if we're not elevated, we want powershellget to install to the user scope installRequest = PackageSourceListRequest.ExtendRequest( new Dictionary<string, string[]> { {"Scope", new[] {"CurrentUser"}} }, null, packageJson.IsTrustedSource, request); } else { installRequest = PackageSourceListRequest.ExtendRequest( new Dictionary<string, string[]> { {"Destination", new[] {packageJson.Destination ?? ""}} }, null, packageJson.IsTrustedSource, request); } request.Debug("Calling '{0}' provider to install the package '{1}.{2}'", provider.Name, packageJson.Name, packageJson.Version); var installing = provider.InstallPackage(packages[0], installRequest); if (installing == null || !installing.Any()) { request.Verbose(Resources.Messages.NumberOfPackagesRecevied, 0, provider.Name, "InstallPackage"); request.Warning(Resources.Messages.FailToInstallPackage, Constants.ProviderName, packages[0].Name); return; } int packagesRecevied = 0; foreach (var i in installing) { request.YieldSoftwareIdentity(i.FastPackageReference, i.Name, i.Version, i.VersionScheme, i.Summary, i.Source, i.SearchKey, i.FullPath, i.PackageFilename); if (request.IsCanceled) { installing.Cancel(); } else { request.Verbose(Resources.Messages.SuccessfullyInstalled, "{0}.{1}".format(packageJson.Name, packageJson.Version)); //load provider if (packageJson.IsPackageProvider) { //Per provider development guidance: provider name and module name should be the same otherwise we can not import it. request.PackageManagementService.ImportPackageProvider(request, packageJson.Name, null, null, null, isRooted: false, force: false); } } packagesRecevied++; } request.Verbose(Resources.Messages.NumberOfPackagesRecevied, packagesRecevied, provider.Name, "install-package"); }
public void GetInstalledPackages(string name, string requiredVersion, string minimumVersion, string maximumVersion, PackageSourceListRequest request) { if (request == null) { throw new ArgumentNullException("request"); } if (!ValidatePackageManagementVersion(request)) { return; } request.Debug(Resources.Messages.DebugInfoCallMethod, PackageProviderName, string.Format(CultureInfo.InvariantCulture, "GetInstalledPackages' - name='{0}', requiredVersion='{1}',minimumVersion='{2}', maximumVersion='{3}'", name, requiredVersion, minimumVersion, maximumVersion)); IEnumerable<PackageJson> packagesDefinedInJsonSpec; if (string.IsNullOrWhiteSpace(name) || WildcardPattern.ContainsWildcardCharacters(name)) { // In the case of the package name is null or contains wildcards, error out if a user puts version info if (!string.IsNullOrWhiteSpace(requiredVersion) || !string.IsNullOrWhiteSpace(minimumVersion) || !string.IsNullOrWhiteSpace(maximumVersion)) { request.Warning(Resources.Messages.WildCardCharsAreNotSupported, name); return; } packagesDefinedInJsonSpec = request.GetPackages(name).ToArray(); } else { //return all installed packagesDefinedInJsonSpec = request.GetPackages(name, requiredVersion, minimumVersion, maximumVersion).ToArray(); } _fastPackReftable.Clear(); if (!packagesDefinedInJsonSpec.Any()) { request.Verbose(Resources.Messages.NoPackageFound, Constants.ProviderName); return; } foreach (var package in packagesDefinedInJsonSpec) { switch (package.Type.ToLowerInvariant()) { case Constants.MediaType.AppxPackage: //TODO for future break; case Constants.MediaType.PsArtifacts: PowerShellArtifactInstaller.GeInstalledPowershellArtifacts(package, requiredVersion, minimumVersion,maximumVersion, _fastPackReftable, request); break; case Constants.MediaType.ExePackage: //program provider can handle get-package git for git.exe ExePackageInstaller.GetInstalledExePackages(package, requiredVersion, minimumVersion, minimumVersion, request); break; case Constants.MediaType.MsiPackage: //msi provider can handle get-package node.js for node.js.msi GetMsiInstalledPackage(name, package, requiredVersion, minimumVersion, maximumVersion, request); break; case Constants.MediaType.ZipPackage: ZipPackageInstaller.GetInstalledZipPackage(package, request); break; case Constants.MediaType.NuGetPackage: NupkgInstaller.GeInstalledNuGetPackages(package, requiredVersion, minimumVersion, maximumVersion, _fastPackReftable, request); break; } //switch } }
private static void InstallPackageViaPowerShellGet(PackageJson packageJson, PackageSourceListRequest request, SoftwareIdentity[] packages) { var provider = PackageSourceListRequest.FindProvider(request, packageJson.Type, request, true); if (provider == null) { return; } IHostApi installRequest = request; if (provider.Name.EqualsIgnoreCase(Constants.ProviderNames.PowerShellGet) && !request.ProviderServices.IsElevated) { // if we're not elevated, we want powershellget to install to the user scope installRequest = PackageSourceListRequest.ExtendRequest( new Dictionary <string, string[]> { { "Scope", new[] { "CurrentUser" } } }, null, packageJson.IsTrustedSource, request); } else { installRequest = PackageSourceListRequest.ExtendRequest( new Dictionary <string, string[]> { { "Destination", new[] { packageJson.Destination ?? "" } } }, null, packageJson.IsTrustedSource, request); } request.Debug("Calling '{0}' provider to install the package '{1}.{2}'", provider.Name, packageJson.Name, packageJson.Version); var installing = provider.InstallPackage(packages[0], installRequest); if (installing == null || !installing.Any()) { request.Verbose(Resources.Messages.NumberOfPackagesRecevied, 0, provider.Name, "InstallPackage"); request.Warning(Resources.Messages.FailToInstallPackage, Constants.ProviderName, packages[0].Name); return; } int packagesReceived = 0; foreach (var i in installing) { request.YieldSoftwareIdentity(i.FastPackageReference, i.Name, i.Version, i.VersionScheme, i.Summary, i.Source, i.SearchKey, i.FullPath, i.PackageFilename); if (request.IsCanceled) { installing.Cancel(); } else { request.Verbose(Resources.Messages.SuccessfullyInstalled, "{0}.{1}".format(packageJson.Name, packageJson.Version)); //load provider if (packageJson.IsPackageProvider) { //Per provider development guidance: provider name and module name should be the same otherwise we can not import it. request.PackageManagementService.ImportPackageProvider(request, packageJson.Name, null, null, null, isRooted: false, force: false); } } packagesReceived++; } request.Verbose(Resources.Messages.NumberOfPackagesRecevied, packagesReceived, provider.Name, "install-package"); }
internal static bool InstallZipPackage(PackageJson package, string fastPath, PackageSourceListRequest request) { if (request.RemoveFromPath.Value) { request.Warning(Resources.Messages.AddOrRemovePath, Constants.ProviderName, "RemoveFromPath", "Uninstall-Package"); } // download the exe package var providerType = package.Type.ToLowerInvariant(); var file = Path.ChangeExtension(Path.GetTempFileName(), providerType); if (string.IsNullOrWhiteSpace(package.Destination)) { request.Error(ErrorCategory.InvalidOperation, Constants.ProviderName, Resources.Messages.DestinationRequired); return(false); } WebDownloader.DownloadFile(package.Source, file, request, null); if (!File.Exists(file)) { return(false); } // validate the file if (!WebDownloader.VerifyHash(file, package, request)) { file.TryHardToDelete(); return(false); } if (!request.ShouldContinueWithUntrustedPackageSource(package.Name, package.Source)) { request.Warning(Constants.Messages.UserDeclinedUntrustedPackageInstall, package.Name); file.TryHardToDelete(); return(false); } Timer timer = null; object timerLock = new object(); bool cleanUp = false; ProgressTracker tracker = new ProgressTracker(request.StartProgress(0, "Installing Zip Package............")); double percent = tracker.StartPercent; Action cleanUpAction = () => { lock (timerLock) { // check whether clean up is already done before or not if (!cleanUp) { try { if (timer != null) { // stop timer timer.Change(Timeout.Infinite, Timeout.Infinite); timer.Dispose(); timer = null; } } catch { } cleanUp = true; } } }; // extracted folder string extractedFolder = string.Concat(file.GenerateTemporaryFilename()); var versionFolder = ""; try { timer = new Timer(_ => { percent += 0.025; var progressPercent = tracker.ConvertPercentToProgress(percent); if (progressPercent < 90) { request.Progress(tracker.ProgressID, (int)progressPercent, string.Format(CultureInfo.CurrentCulture, "Copying files ...")); } if (request.IsCanceled) { cleanUpAction(); } }, null, 0, 1000); //unzip the file ZipFile.ExtractToDirectory(file, extractedFolder); if (Directory.Exists(extractedFolder)) { versionFolder = Path.Combine(package.Destination, package.Name, package.Version); // create the directory version folder if not exist if (!Directory.Exists(versionFolder)) { Directory.CreateDirectory(versionFolder); } // The package will be installed to destination\packageName\version\ // However, a few packages have a package name as its top level folder after zip. // So the installed folder will look like this: // \destination\foobarPackage\1.0.1\foobarPackage // In this case we directly copy the files to \destination\foobarPackage\1.0.1. var extractedTopLevelFolder = Directory.EnumerateDirectories(extractedFolder, "*", SearchOption.TopDirectoryOnly); while (!Directory.GetFiles(extractedFolder).Any() && extractedTopLevelFolder.Count() == 1) { extractedFolder = extractedTopLevelFolder.FirstOrDefault(); //in case the zip contains version folder extractedTopLevelFolder = Directory.EnumerateDirectories(extractedFolder, "*", SearchOption.TopDirectoryOnly); } FileUtility.CopyDirectory(extractedFolder, versionFolder, true); request.YieldFromSwidtag(package, fastPath); request.Verbose(Resources.Messages.SuccessfullyInstalledToDestination, package.Name, package.Destination); AddEnvironmentVariable(request, versionFolder); return(true); } else { request.Warning("Failed to download a Zip package {0} from {1}", package.Name, package.Source); } } catch (Exception e) { request.Debug(e.StackTrace); if (e is System.UnauthorizedAccessException) { request.WriteError(ErrorCategory.InvalidOperation, package.Name, Resources.Messages.InstallFailed, package.Name, "UnauthorizedAccessException. The requested operation likely requires elevation, i.e., launch PowerShell as administer"); } else { request.WriteError(ErrorCategory.InvalidOperation, package.Name, Resources.Messages.InstallFailed, package.Name, e.Message); } if (!(e is UnauthorizedAccessException || e is IOException)) { // something wrong, delete the version folder versionFolder.TryHardToDelete(); } } finally { cleanUpAction(); file.TryHardToDelete(); extractedFolder.TryHardToDelete(); request.CompleteProgress(tracker.ProgressID, true); } return(false); }