PowerShell/src/Microsoft.PackageManagement/Implementation/ProviderBase.cs
PowerShell Team c748652c34 Copy all mapped files from [SD:725290]
commit 8cec8f150da7583b7af5efbe2853efee0179750c
2016-07-28 23:23:03 -07:00

210 lines
8.1 KiB
C#

//
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
namespace Microsoft.PackageManagement.Internal.Implementation {
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Xml.Linq;
using System.Text.RegularExpressions;
using Api;
using Packaging;
using Providers;
using Utility.Async;
using Utility.Extensions;
using Utility.Plugin;
using Utility.Versions;
using File = System.IO.File;
using Microsoft.PackageManagement.Internal.Utility.Platform;
using PackageManagement.Packaging;
public abstract class ProviderBase : SoftwareIdentity
{
public abstract new string ProviderName {get;}
}
public abstract class ProviderBase<T> : ProviderBase where T : IProvider {
private List<DynamicOption> _dynamicOptions;
private Dictionary<string, List<string>> _features;
private bool _initialized;
private byte[][] _magicSignatures;
private string[] _supportedFileExtensions;
private string[] _supportedSchemes;
private FourPartVersion _version;
protected ProviderBase(T provider) {
Provider = provider;
}
internal new T Provider { get; private set; }
[SuppressMessage("Microsoft.Naming", "CA1721:PropertyNamesShouldNotMatchGetMethods", Justification = "This is required for the PowerShell Providers.")]
public IDictionary<string, List<string>> Features {
get {
// todo: this dictionary should be read only (.net 4.0 doesn't have that!)
return _features;
}
}
public new FourPartVersion Version {
get {
return _version;
}
set {
if (_version == 0) {
_version = value;
base.Version = value.ToString();
}
}
}
internal bool IsLoaded {get; set;}
public string ProviderPath { get; set;}
/// <summary>
/// Set swidtag based on provider file
/// </summary>
/// <param name="providerPath"></param>
public void SetSwidTag(string providerPath)
{
if (!string.IsNullOrWhiteSpace(providerPath))
{
// check whether there is swidtag attached to the provider path
var swid = Manifest.LoadFrom(providerPath).FirstOrDefault(manifest => Swidtag.IsSwidtag(manifest));
if (swid != null)
{
// give the manifest to the providers to populate swidtag fields
SetSwidTag(new XDocument(new XDeclaration("1.0", "UTF-8", "yes"), swid));
}
}
}
public IEnumerable<string> SupportedFileExtensions {
get {
return (_supportedFileExtensions ?? (_supportedFileExtensions = Features.ContainsKey(Constants.Features.SupportedExtensions) ? Features[Constants.Features.SupportedExtensions].ToArray() : Constants.Empty));
}
}
public IEnumerable<string> SupportedUriSchemes {
get {
return (_supportedSchemes ?? (_supportedSchemes = Features.ContainsKey(Constants.Features.SupportedSchemes) ? Features[Constants.Features.SupportedSchemes].ToArray() : Constants.Empty));
}
}
internal byte[][] MagicSignatures {
get {
return _magicSignatures ?? (_magicSignatures = Features.ContainsKey(Constants.Features.MagicSignatures) ? Features[Constants.Features.MagicSignatures].Select(each => each.FromHex()).ToArray() : new byte[][] {});
}
}
[SuppressMessage("Microsoft.Naming", "CA1721:PropertyNamesShouldNotMatchGetMethods", Justification = "This is required for the PowerShell Providers.")]
public List<DynamicOption> DynamicOptions {
get {
if (_dynamicOptions == null) {
var nullHostApi = new object().As<IHostApi>();
var result = new List<DynamicOption>();
result.AddRange(GetDynamicOptions(OptionCategory.Install, nullHostApi));
result.AddRange(GetDynamicOptions(OptionCategory.Package, nullHostApi));
result.AddRange(GetDynamicOptions(OptionCategory.Provider, nullHostApi));
result.AddRange(GetDynamicOptions(OptionCategory.Source, nullHostApi));
if ((Features != null) && Features.ContainsKey("IsChainingProvider")) {
// chaining package providers should not cache results
return result;
}
_dynamicOptions = result;
}
return _dynamicOptions;
}
}
public virtual bool IsSupportedFileName(string filename) {
try {
var extension = System.IO.Path.GetExtension(filename);
if (!string.IsNullOrWhiteSpace(extension)) {
return SupportedFileExtensions.ContainsIgnoreCase(extension);
}
} catch {
}
return false;
}
public virtual bool IsSupportedFile(string filename) {
if (filename == null) {
throw new ArgumentNullException("filename");
}
if (filename.FileExists()) {
var buffer = new byte[1024];
var sz = 0;
try {
using (var file = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.Read)) {
sz = file.Read(buffer, 0, 1024);
}
return MagicSignatures.Any(magic => BufferMatchesMagicBytes(magic, buffer, sz));
} catch {
// not openable. whatever.
}
}
return false;
}
public virtual bool IsSupportedFile(byte[] header) {
return MagicSignatures.Any(magic => BufferMatchesMagicBytes(magic, header, header.Length));
}
public virtual bool IsSupportedScheme(Uri uri) {
try {
return SupportedUriSchemes.ContainsIgnoreCase(uri.Scheme);
} catch {
}
return false;
}
private bool BufferMatchesMagicBytes(byte[] magic, byte[] buffer, int maxSize) {
if (magic.Length <= maxSize) {
return !magic.Where((t, i) => t != buffer[i]).Any();
}
return false;
}
public bool IsMethodImplemented(string methodName) {
return Provider.IsMethodImplemented(methodName);
}
internal void Initialize(IHostApi request) {
if (!_initialized) {
_features = GetFeatures(request).Value;
_initialized = true;
}
}
public IAsyncValue<Dictionary<string, List<string>>> GetFeatures(IHostApi requestObject) {
if (requestObject == null) {
throw new ArgumentNullException("requestObject");
}
return new DictionaryRequestObject(this, requestObject, request => Provider.GetFeatures(request));
}
public IAsyncEnumerable<DynamicOption> GetDynamicOptions(OptionCategory category, IHostApi requestObject) {
requestObject = requestObject ?? new object().As<IHostApi>();
return new DynamicOptionRequestObject(this, requestObject, request => Provider.GetDynamicOptions(category.ToString(), request), category);
}
}
}