//
// 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.PowerShell.PackageManagement.Cmdlets {
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Management.Automation;
using Microsoft.PackageManagement.Internal.Api;
using Microsoft.PackageManagement.Internal.Packaging;
using Microsoft.PackageManagement.Internal.Utility.Async;
using Microsoft.PackageManagement.Internal.Utility.Extensions;
using Microsoft.PackageManagement.Internal.Utility.Plugin;
using Microsoft.PackageManagement.Packaging;
using Utility;
using System.Security;
[Cmdlet(VerbsCommon.Set, Constants.Nouns.PackageSourceNoun, SupportsShouldProcess = true, DefaultParameterSetName = Constants.ParameterSets.SourceBySearchSet, HelpUri = "http://go.microsoft.com/fwlink/?LinkID=517141")]
public sealed class SetPackageSource : CmdletWithProvider {
[Parameter(ValueFromPipeline = true, ParameterSetName = Constants.ParameterSets.SourceByInputObjectSet, Mandatory = true)]
public PackageSource InputObject;
public SetPackageSource() : base(new[] {OptionCategory.Provider, OptionCategory.Source}) {
}
[Parameter]
[ValidateNotNull()]
public Uri Proxy { get; set; }
[Parameter]
[ValidateNotNull()]
public PSCredential ProxyCredential { get; set; }
///
/// Returns web proxy that provider can use
/// Construct the webproxy using InternalWebProxy
///
public override System.Net.IWebProxy WebProxy
{
get
{
if (Proxy != null)
{
return new PackageManagement.Utility.InternalWebProxy(Proxy, ProxyCredential == null ? null : ProxyCredential.GetNetworkCredential());
}
return null;
}
}
[Parameter]
public PSCredential Credential { get; set; }
public override string CredentialUsername
{
get
{
return Credential != null ? Credential.UserName : null;
}
}
public override SecureString CredentialPassword
{
get
{
return Credential != null ? Credential.Password : null;
}
}
protected override IEnumerable ParameterSets {
get {
return new[] {Constants.ParameterSets.SourceByInputObjectSet, Constants.ParameterSets.SourceBySearchSet};
}
}
protected override void GenerateCmdletSpecificParameters(Dictionary unboundArguments) {
if (!IsInvocation) {
var providerNames = PackageManagementService.AllProviderNames;
var whatsOnCmdline = GetDynamicParameterValue("ProviderName");
if (whatsOnCmdline != null) {
providerNames = providerNames.Concat(whatsOnCmdline).Distinct();
}
DynamicParameterDictionary.AddOrSet("ProviderName", new RuntimeDefinedParameter("ProviderName", typeof(string), new Collection {
new ParameterAttribute {
ValueFromPipelineByPropertyName = true,
ParameterSetName = Constants.ParameterSets.SourceBySearchSet,
},
new AliasAttribute("Provider"),
new ValidateSetAttribute(providerNames.ToArray())
}));
}
else {
DynamicParameterDictionary.AddOrSet("ProviderName", new RuntimeDefinedParameter("ProviderName", typeof(string), new Collection {
new ParameterAttribute {
ValueFromPipelineByPropertyName = true,
ParameterSetName = Constants.ParameterSets.SourceBySearchSet,
},
new AliasAttribute("Provider")
}));
}
}
[Alias("SourceName")]
[Parameter(Position = 0, ParameterSetName = Constants.ParameterSets.SourceBySearchSet)]
public string Name {get; set;}
[Parameter(ParameterSetName = Constants.ParameterSets.SourceBySearchSet)]
public string Location {get; set;}
[Parameter]
public string NewLocation {get; set;}
[Parameter]
public string NewName {get; set;}
[Parameter]
public SwitchParameter Trusted {get; set;}
public override IEnumerable Sources {
get {
if (string.IsNullOrWhiteSpace(Name) && string.IsNullOrWhiteSpace(Location)) {
return Microsoft.PackageManagement.Internal.Constants.Empty;
}
return new[] {
Name ?? Location
};
}
}
///
/// This can be used when we want to override some of the functions that are passed
/// in as the implementation of the IHostApi (ie, 'request object').
/// Because the DynamicInterface DuckTyper will use all the objects passed in in order
/// to implement a given API, if we put in delegates to handle some of the functions
/// they will get called instead of the implementation in the current class. ('this')
///
private IHostApi UpdatePackageSourceRequest {
get {
return new object[] {
new {
// override the GetOptionKeys and the GetOptionValues on the fly.
GetOptionKeys = new Func>(() => OptionKeys.ConcatSingleItem("IsUpdatePackageSource")),
GetOptionValues = new Func>((key) => {
if (key != null && key.EqualsIgnoreCase("IsUpdatePackageSource")) {
return "true".SingleItemAsEnumerable();
}
return GetOptionValues(key);
})
},
this,
}.As();
}
}
private void UpdatePackageSource(PackageSource source) {
if (WhatIf) {
var p = new PSObject(source);
if (!string.IsNullOrWhiteSpace(NewName)) {
p.Properties.Remove("Name");
p.Properties.Add( new PSNoteProperty("Name",NewName));
}
if (!string.IsNullOrWhiteSpace(NewLocation)) {
p.Properties.Remove("Location");
p.Properties.Add(new PSNoteProperty("Location", NewLocation));
}
if (Trusted.IsPresent) {
p.Properties.Remove("Trusted");
p.Properties.Add(new PSNoteProperty("Trusted", Trusted.ToBool()));
}
WriteObject(p);
return;
}
if (string.IsNullOrWhiteSpace(NewName)) {
// this is a replacement of an existing package source, we're *not* changing the name. (easy)
foreach (var src in source.Provider.AddPackageSource(string.IsNullOrWhiteSpace(NewName) ? source.Name : NewName, string.IsNullOrWhiteSpace(NewLocation) ? source.Location : NewLocation, Trusted, UpdatePackageSourceRequest)) {
WriteObject(src);
}
} else {
// we're renaming a source.
// a bit more messy at this point
// create a new package source first
bool removed = false;
foreach (var src in source.Provider.AddPackageSource(NewName, string.IsNullOrWhiteSpace(NewLocation) ? source.Location : NewLocation, Trusted.IsPresent ? Trusted.ToBool() : source.IsTrusted, this)) {
WriteObject(src);
if (!removed)
{
// if we are able to successfully add a source, then we remove the original source that was supposed to be replace.
// This will only happen once (as there is only one original source)
source.Provider.RemovePackageSource(source.Name, this);
removed = true;
}
}
}
}
public override bool ProcessRecordAsync() {
if (IsSourceByObject) {
// we've already got the package source
UpdatePackageSource(InputObject);
return true;
}
if (string.IsNullOrWhiteSpace(Name) && string.IsNullOrWhiteSpace(Location)) {
Error(Constants.Errors.NameOrLocationRequired);
return false;
}
// otherwise, we're just changing a source by name
var prov = SelectedProviders.ToArray();
if (Stopping) {
return false;
}
if (prov.Length == 0) {
if (ProviderName.IsNullOrEmpty() || string.IsNullOrWhiteSpace(ProviderName[0])) {
return Error(Constants.Errors.UnableToFindProviderForSource, Name ?? Location);
}
return Error(Constants.Errors.UnknownProvider, ProviderName[0]);
}
if (prov.Length > 0) {
var sources = prov.SelectMany(each => each.ResolvePackageSources(this.SuppressErrorsAndWarnings(IsProcessing)).Where(source => source.IsRegistered &&
(Name == null || source.Name.EqualsIgnoreCase(Name)) || (Location == null || source.Location.EqualsIgnoreCase(Location))).ToArray()).ToArray();
if (sources.Length == 0) {
return Error(Constants.Errors.SourceNotFound, Name);
}
if (sources.Length > 1) {
return Error(Constants.Errors.SourceFoundInMultipleProviders, Name, prov.Select(each => each.ProviderName).JoinWithComma());
}
UpdatePackageSource(sources[0]);
}
return true;
}
}
}