diff --git a/build/common.targets b/build/common.targets index 9c8d3e4b3a4..93c490c4640 100644 --- a/build/common.targets +++ b/build/common.targets @@ -135,7 +135,7 @@ TaskParameter="TargetOutputs" ItemName="DllsToSign" /> - diff --git a/build/loc.proj b/build/loc.proj index f29c45598f0..eba13bb4432 100644 --- a/build/loc.proj +++ b/build/loc.proj @@ -15,7 +15,7 @@ $(ArtifactsDirectory) - + $(ArtifactsDirectory)microsoft.web.xdt\2.1.2\lib\net40\Microsoft.Web.XmlTransform.dll @@ -37,7 +37,7 @@ - + - + <_MoveLocalizedFiles Include="@(LocalizedUserFiles)"> $(ArtifactsDirectory)$([MSBuild]::MakeRelative($(ArtifactsDirectory)localize\%(LocalizedUserFiles.lang), %(LocalizedUserFiles.RootDir)%(LocalizedUserFiles.Directory)))%(LocalizedUserFiles.Culture)\%(LocalizedUserFiles.Filename)%(LocalizedUserFiles.Extension) @@ -60,7 +60,7 @@ - + @@ -72,7 +72,7 @@ - + <_MoveLcgFiles Include="@(LocalizedToolFiles)" Condition="'%(LocalizedToolFiles.Extension)'== '.lcg'"> $(ArtifactsDirectory)$([MSBuild]::MakeRelative($(ArtifactsDirectory)localize\%(LocalizedToolFiles.lang), %(LocalizedToolFiles.RootDir)%(LocalizedToolFiles.Directory)))%(LocalizedToolFiles.Culture)\%(LocalizedToolFiles.Filename)%(LocalizedToolFiles.Extension) diff --git a/build/vsts_build.yaml b/build/vsts_build.yaml index 4b1d6e22077..d833649615e 100644 --- a/build/vsts_build.yaml +++ b/build/vsts_build.yaml @@ -77,6 +77,9 @@ phases: FullVstsBuildNumber: $[dependencies.Initialize_Build.outputs['updatebuildnumber.FullVstsBuildNumber']] VsTargetChannel: $[dependencies.Initialize_Build.outputs['updatebuildnumber.VsTargetChannel']] VsTargetMajorVersion: $[dependencies.Initialize_Build.outputs['updatebuildnumber.VsTargetMajorVersion']] + LocalizedLanguageCount: "13" + DesktopTargetFramework: "net472" + queue: name: VSEng-MicroBuildVS2019 timeoutInMinutes: 90 @@ -178,7 +181,7 @@ phases: solution: "build\\build.proj" msbuildVersion: "16.0" configuration: "$(BuildConfiguration)" - msbuildArguments: "/t:BuildNoVSIX /p:BuildRTM=$(BuildRTM) /p:BuildNumber=$(BuildNumber)" + msbuildArguments: "/t:BuildNoVSIX /p:BuildRTM=$(BuildRTM) /p:BuildNumber=$(BuildNumber) /p:SkipILMergeOfNuGetExe=true" - task: MSBuild@1 displayName: "Ensure msbuild.exe can parse nuget.sln" @@ -189,6 +192,31 @@ phases: msbuildArguments: "/t:EnsureNewtonsoftJsonVersion" condition: "succeeded()" + - task: MSBuild@1 + displayName: "Localize Assemblies" + inputs: + solution: "build\\loc.proj" + msbuildVersion: "16.0" + configuration: "$(BuildConfiguration)" + msbuildArguments: "/t:AfterBuild" + + - task: MSBuild@1 + displayName: "Build Final NuGet.exe (via ILMerge)" + inputs: + solution: "src\\NuGet.Clients\\NuGet.CommandLine\\NuGet.CommandLine.csproj" + msbuildVersion: "16.0" + configuration: "$(BuildConfiguration)" + msbuildArguments: "/t:ILMergeNuGetExe /p:ExpectedLocalizedArtifactCount=$(LocalizedLanguageCount)" + + - task: MSBuild@1 + displayName: "Publish NuGet.exe (ILMerged) into NuGet.CommandLine.Test (Mac tests use this)" + inputs: + solution: "test\\NuGet.Clients.Tests\\NuGet.CommandLine.Test\\NuGet.CommandLine.Test.csproj" + msbuildVersion: "16.0" + configuration: "$(BuildConfiguration)" + msbuildArguments: "/t:CopyFinalNuGetExeToOutputPath" + condition: "and(succeeded(),eq(variables['BuildRTM'], 'true'))" + - task: MSBuild@1 displayName: "Run unit tests" continueOnError: "true" @@ -196,7 +224,7 @@ phases: solution: "build\\build.proj" msbuildVersion: "16.0" configuration: "$(BuildConfiguration)" - msbuildArguments: "/t:CoreUnitTests;UnitTestsVS /p:BuildRTM=$(BuildRTM) /p:BuildNumber=$(BuildNumber) /p:TestResultOutputFormat=xml" + msbuildArguments: "/t:CoreUnitTests;UnitTestsVS /p:BuildRTM=$(BuildRTM) /p:BuildNumber=$(BuildNumber) /p:TestResultOutputFormat=xml /p:SkipILMergeOfNuGetExe=true" condition: "and(succeeded(),eq(variables['BuildRTM'], 'true'))" - task: PublishTestResults@2 @@ -228,15 +256,6 @@ phases: ArtifactType: "Container" condition: "and(succeeded(),eq(variables['BuildRTM'], 'true'))" - - task: MSBuild@1 - displayName: "Localize Assemblies" - inputs: - solution: "build\\loc.proj" - msbuildVersion: "16.0" - configuration: "$(BuildConfiguration)" - msbuildArguments: "/t:AfterBuild" - condition: " and(succeeded(),eq(variables['BuildRTM'], 'false')) " - - task: MSBuild@1 displayName: "Sign Assemblies" inputs: diff --git a/src/NuGet.Clients/NuGet.CommandLine/CommandLineParser.cs b/src/NuGet.Clients/NuGet.CommandLine/CommandLineParser.cs index 23f17054116..96f6e4c9bf7 100644 --- a/src/NuGet.Clients/NuGet.CommandLine/CommandLineParser.cs +++ b/src/NuGet.Clients/NuGet.CommandLine/CommandLineParser.cs @@ -1,3 +1,6 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + using System; using System.Collections.Generic; using System.Diagnostics; @@ -5,6 +8,7 @@ using System.Globalization; using System.Linq; using System.Reflection; +using NuGet.Commands; using NuGet.Packaging; namespace NuGet.CommandLine @@ -66,7 +70,7 @@ public void ExtractOptions(ICommand command, IEnumerator argsEnumerator) if (value == null) { - throw new CommandLineException(LocalizedResourceManager.GetString("MissingOptionValueError"), option); + throw new CommandException(LocalizedResourceManager.GetString("MissingOptionValueError"), option); } AssignValue(command, propInfo, option, value); @@ -118,13 +122,13 @@ internal static void AssignValue(object command, PropertyInfo property, string o property.SetValue(command, TypeHelper.ChangeType(value, property.PropertyType), index: null); } } - catch (CommandLineException) + catch (CommandException) { throw; } catch { - throw new CommandLineException(LocalizedResourceManager.GetString("InvalidOptionValueError"), option, value); + throw new CommandException(LocalizedResourceManager.GetString("InvalidOptionValueError"), option, value); } } @@ -143,7 +147,7 @@ public ICommand ParseCommandLine(IEnumerable commandLineArgs) ICommand cmd = _commandManager.GetCommand(cmdName); if (cmd == null) { - throw new CommandLineException(LocalizedResourceManager.GetString("UnknowCommandError"), cmdName); + throw new CommandException(LocalizedResourceManager.GetString("UnknowCommandError"), cmdName); } ExtractOptions(cmd, argsEnumerator); @@ -168,7 +172,7 @@ where getDisplayName(item).StartsWith(value, StringComparison.OrdinalIgnoreCase) var result = results.FirstOrDefault(); if (!results.Any()) { - throw new CommandLineException(LocalizedResourceManager.GetString("UnknownOptionError"), option); + throw new CommandException(LocalizedResourceManager.GetString("UnknownOptionError"), option); } else if (results.Skip(1).Any()) { @@ -180,7 +184,7 @@ where getDisplayName(item).StartsWith(value, StringComparison.OrdinalIgnoreCase) } catch (InvalidOperationException) { - throw new CommandLineException(String.Format(CultureInfo.CurrentCulture, LocalizedResourceManager.GetString("AmbiguousOption"), value, + throw new CommandException(String.Format(CultureInfo.CurrentCulture, LocalizedResourceManager.GetString("AmbiguousOption"), value, String.Join(" ", from c in results select getDisplayName(c)))); } } diff --git a/src/NuGet.Clients/NuGet.CommandLine/CommandManager.cs b/src/NuGet.Clients/NuGet.CommandLine/CommandManager.cs index 97e69710061..bf488ca8682 100644 --- a/src/NuGet.Clients/NuGet.CommandLine/CommandManager.cs +++ b/src/NuGet.Clients/NuGet.CommandLine/CommandManager.cs @@ -1,9 +1,13 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + using System; using System.Collections.Generic; using System.ComponentModel.Composition; using System.Globalization; using System.Linq; using System.Reflection; +using NuGet.Commands; namespace NuGet.CommandLine { @@ -26,7 +30,7 @@ where command.CommandAttribute.CommandName.StartsWith(commandName, StringCompari if (!results.Any()) { - throw new CommandLineException(LocalizedResourceManager.GetString("UnknowCommandError"), commandName); + throw new CommandException(LocalizedResourceManager.GetString("UnknowCommandError"), commandName); } var matchedCommand = results.First(); @@ -39,7 +43,7 @@ where command.CommandAttribute.CommandName.StartsWith(commandName, StringCompari if (matchedCommand == null) { // No exact match was found and the result returned multiple prefixes. - throw new CommandLineException(String.Format(CultureInfo.CurrentCulture, LocalizedResourceManager.GetString("AmbiguousCommand"), commandName, + throw new CommandException(String.Format(CultureInfo.CurrentCulture, LocalizedResourceManager.GetString("AmbiguousCommand"), commandName, String.Join(" ", from c in results select c.CommandAttribute.CommandName))); } } diff --git a/src/NuGet.Clients/NuGet.CommandLine/Commands/AddCommand.cs b/src/NuGet.Clients/NuGet.CommandLine/Commands/AddCommand.cs index 79b25a0a36b..1924a3d3a21 100644 --- a/src/NuGet.Clients/NuGet.CommandLine/Commands/AddCommand.cs +++ b/src/NuGet.Clients/NuGet.CommandLine/Commands/AddCommand.cs @@ -3,6 +3,7 @@ using System.Threading; using System.Threading.Tasks; +using NuGet.Commands; using NuGet.Packaging; using NuGet.Packaging.PackageExtraction; using NuGet.Packaging.Signing; @@ -29,7 +30,7 @@ public override async Task ExecuteCommandAsync() if (string.IsNullOrEmpty(Source)) { - throw new CommandLineException( + throw new CommandException( LocalizedResourceManager.GetString(nameof(NuGetResources.AddCommand_SourceNotProvided))); } diff --git a/src/NuGet.Clients/NuGet.CommandLine/Commands/DownloadCommandBase.cs b/src/NuGet.Clients/NuGet.CommandLine/Commands/DownloadCommandBase.cs index 4a7bea06226..3518305b5ba 100644 --- a/src/NuGet.Clients/NuGet.CommandLine/Commands/DownloadCommandBase.cs +++ b/src/NuGet.Clients/NuGet.CommandLine/Commands/DownloadCommandBase.cs @@ -8,6 +8,7 @@ using System.Linq; using System.Xml; using System.Xml.Linq; +using NuGet.Commands; using NuGet.Configuration; using NuGet.Packaging; using NuGet.Protocol; @@ -111,7 +112,7 @@ internal void CalculateEffectivePackageSaveMode() projectConfigFilePath, ex.Message); - throw new CommandLineException(message); + throw new CommandException(message); } } diff --git a/src/NuGet.Clients/NuGet.CommandLine/Commands/InstallCommand.cs b/src/NuGet.Clients/NuGet.CommandLine/Commands/InstallCommand.cs index c27f9d080c3..a7356c9d10f 100644 --- a/src/NuGet.Clients/NuGet.CommandLine/Commands/InstallCommand.cs +++ b/src/NuGet.Clients/NuGet.CommandLine/Commands/InstallCommand.cs @@ -10,6 +10,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using NuGet.Commands; using NuGet.Common; using NuGet.Configuration; using NuGet.Frameworks; @@ -250,7 +251,7 @@ private DependencyBehavior TryGetDependencyBehavior(string behaviorStr) if (!Enum.TryParse(behaviorStr, ignoreCase: true, result: out dependencyBehavior) || !Enum.IsDefined(typeof(DependencyBehavior), dependencyBehavior)) { - throw new CommandLineException(string.Format(CultureInfo.CurrentCulture, LocalizedResourceManager.GetString("InstallCommandUnknownDependencyVersion"), behaviorStr)); + throw new CommandException(string.Format(CultureInfo.CurrentCulture, LocalizedResourceManager.GetString("InstallCommandUnknownDependencyVersion"), behaviorStr)); } return dependencyBehavior; @@ -341,7 +342,7 @@ private async Task InstallPackageAsync( LocalizedResourceManager.GetString("InstallCommandUnableToFindPackage"), packageId); - throw new CommandLineException(message); + throw new CommandException(message); } version = resolvePackage.LatestVersion; diff --git a/src/NuGet.Clients/NuGet.CommandLine/Commands/PackCommand.cs b/src/NuGet.Clients/NuGet.CommandLine/Commands/PackCommand.cs index c07e6ae69cd..4a2504f4e2d 100644 --- a/src/NuGet.Clients/NuGet.CommandLine/Commands/PackCommand.cs +++ b/src/NuGet.Clients/NuGet.CommandLine/Commands/PackCommand.cs @@ -1,3 +1,6 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + using System; using System.Collections.Generic; using System.IO; @@ -129,7 +132,7 @@ public override void ExecuteCommand() { if (!System.Version.TryParse(MinClientVersion, out _minClientVersionValue)) { - throw new CommandLineException(LocalizedResourceManager.GetString("PackageCommandInvalidMinClientVersion")); + throw new CommandException(LocalizedResourceManager.GetString("PackageCommandInvalidMinClientVersion")); } } diff --git a/src/NuGet.Clients/NuGet.CommandLine/Commands/RestoreCommand.cs b/src/NuGet.Clients/NuGet.CommandLine/Commands/RestoreCommand.cs index fb2488e4513..ecfd9b35af6 100644 --- a/src/NuGet.Clients/NuGet.CommandLine/Commands/RestoreCommand.cs +++ b/src/NuGet.Clients/NuGet.CommandLine/Commands/RestoreCommand.cs @@ -475,7 +475,7 @@ private void CheckRequireConsent() LocalizedResourceManager.GetString("InstallCommandPackageRestoreConsentNotFound"), NuGetResources.PackageRestoreConsentCheckBoxText.Replace("&", "")); - throw new CommandLineException(message); + throw new CommandException(message); } } } diff --git a/src/NuGet.Clients/NuGet.CommandLine/Commands/SourcesCommand.cs b/src/NuGet.Clients/NuGet.CommandLine/Commands/SourcesCommand.cs index dc371e25db1..a396c4f2ead 100644 --- a/src/NuGet.Clients/NuGet.CommandLine/Commands/SourcesCommand.cs +++ b/src/NuGet.Clients/NuGet.CommandLine/Commands/SourcesCommand.cs @@ -2,18 +2,12 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Globalization; using System.Linq; -using NuGet.Common; -using NuGet.Configuration; +using NuGet.Commands; namespace NuGet.CommandLine { - public enum SourcesListFormat - { - Detailed, - Short - } - [Command(typeof(NuGetCommand), "sources", "SourcesCommandDescription", UsageSummaryResourceName = "SourcesCommandUsageSummary", MinArgs = 0, MaxArgs = 1)] public class SourcesCommand : Command @@ -39,6 +33,7 @@ public class SourcesCommand : Command [Option(typeof(NuGetCommand), "SourcesCommandFormatDescription")] public SourcesListFormat Format { get; set; } + public override void ExecuteCommand() { if (SourceProvider == null) @@ -46,260 +41,47 @@ public override void ExecuteCommand() throw new InvalidOperationException(LocalizedResourceManager.GetString("Error_SourceProviderIsNull")); } - // Convert to update - var action = Arguments.FirstOrDefault(); - - - // TODO: Change these in to switches so we don't have to parse them here. - if (string.IsNullOrEmpty(action) || action.Equals("List", StringComparison.OrdinalIgnoreCase)) - { - switch (Format) - { - case SourcesListFormat.Short: - PrintRegisteredSourcesShort(); - break; - default: - PrintRegisteredSourcesDetailed(); - break; - } - } - else if (action.Equals("Add", StringComparison.OrdinalIgnoreCase)) - { - AddNewSource(); - } - else if (action.Equals("Remove", StringComparison.OrdinalIgnoreCase)) - { - RemoveSource(); - } - else if (action.Equals("Enable", StringComparison.OrdinalIgnoreCase)) - { - EnableOrDisableSource(enabled: true); - } - else if (action.Equals("Disable", StringComparison.OrdinalIgnoreCase)) - { - EnableOrDisableSource(enabled: false); - } - else if (action.Equals("Update", StringComparison.OrdinalIgnoreCase)) - { - UpdatePackageSource(); - } - } - - private void EnableOrDisableSource(bool enabled) - { - if (string.IsNullOrEmpty(Name)) - { - throw new CommandLineException(LocalizedResourceManager.GetString("SourcesCommandNameRequired")); - } - - var packageSource = SourceProvider.GetPackageSourceByName(Name); - if (packageSource == null) - { - throw new CommandLineException(LocalizedResourceManager.GetString("SourcesCommandNoMatchingSourcesFound"), Name); - } - - if (enabled && !packageSource.IsEnabled) - { - SourceProvider.EnablePackageSource(Name); - } - else if (!enabled && packageSource.IsEnabled) - { - SourceProvider.DisablePackageSource(Name); - } - - Console.WriteLine( - enabled ? LocalizedResourceManager.GetString("SourcesCommandSourceEnabledSuccessfully") : LocalizedResourceManager.GetString("SourcesCommandSourceDisabledSuccessfully"), - Name); - } - - private void RemoveSource() - { - if (string.IsNullOrEmpty(Name)) - { - throw new CommandLineException(LocalizedResourceManager.GetString("SourcesCommandNameRequired")); - } - - // Check to see if we already have a registered source with the same name or source - var sourceList = SourceProvider.LoadPackageSources().ToList(); - - var source = SourceProvider.GetPackageSourceByName(Name); - if (source == null) - { - throw new CommandLineException(LocalizedResourceManager.GetString("SourcesCommandNoMatchingSourcesFound"), Name); - } - - SourceProvider.RemovePackageSource(Name); - Console.WriteLine(LocalizedResourceManager.GetString("SourcesCommandSourceRemovedSuccessfully"), Name); - } - - private void AddNewSource() - { - if (string.IsNullOrEmpty(Name)) - { - throw new CommandLineException(LocalizedResourceManager.GetString("SourcesCommandNameRequired")); - } - if (string.Equals(Name, LocalizedResourceManager.GetString("ReservedPackageNameAll"))) - { - throw new CommandLineException(LocalizedResourceManager.GetString("SourcesCommandAllNameIsReserved")); - } - if (string.IsNullOrEmpty(Source)) - { - throw new CommandLineException(LocalizedResourceManager.GetString("SourcesCommandSourceRequired")); - } - - // Make sure that the Source given is a valid one. - if (!PathValidator.IsValidSource(Source)) + SourcesAction action = SourcesAction.None; + var actionArg = Arguments.FirstOrDefault(); + if (string.IsNullOrEmpty(actionArg)) { - throw new CommandLineException(LocalizedResourceManager.GetString("SourcesCommandInvalidSource")); + action = SourcesAction.List; } - - ValidateCredentials(); - - // Check to see if we already have a registered source with the same name or source - var existingSourceWithName = SourceProvider.GetPackageSourceByName(Name); - if (existingSourceWithName != null) + else { - throw new CommandLineException(LocalizedResourceManager.GetString("SourcesCommandUniqueName")); - } - var existingSourceWithSource = SourceProvider.GetPackageSourceBySource(Source); - if (existingSourceWithSource != null) - { - throw new CommandLineException(LocalizedResourceManager.GetString("SourcesCommandUniqueSource")); - } - - var newPackageSource = new Configuration.PackageSource(Source, Name); - - if (!string.IsNullOrEmpty(Username)) - { - var credentials = Configuration.PackageSourceCredential.FromUserInput( - Name, - Username, - Password, - StorePasswordInClearText, - ValidAuthenticationTypes); - newPackageSource.Credentials = credentials; - } - - SourceProvider.AddPackageSource(newPackageSource); - Console.WriteLine(LocalizedResourceManager.GetString("SourcesCommandSourceAddedSuccessfully"), Name); - } - - private void UpdatePackageSource() - { - if (string.IsNullOrEmpty(Name)) - { - throw new CommandLineException(LocalizedResourceManager.GetString("SourcesCommandNameRequired")); - } - - var existingSource = SourceProvider.GetPackageSourceByName(Name); - if (existingSource == null) - { - throw new CommandLineException(LocalizedResourceManager.GetString("SourcesCommandNoMatchingSourcesFound"), Name); - } - - if (!string.IsNullOrEmpty(Source) && !existingSource.Source.Equals(Source, StringComparison.OrdinalIgnoreCase)) - { - if (!PathValidator.IsValidSource(Source)) - { - throw new CommandLineException(LocalizedResourceManager.GetString("SourcesCommandInvalidSource")); - } - - // If the user is updating the source, verify we don't have a duplicate. - var duplicateSource = SourceProvider.GetPackageSourceBySource(Source); - if (duplicateSource != null) + if (!Enum.TryParse(actionArg, ignoreCase: true, out action)) { - throw new CommandLineException(LocalizedResourceManager.GetString("SourcesCommandUniqueSource")); + Console.WriteLine(LocalizedResourceManager.GetString("SourcesCommandUsageSummary")); } - existingSource = new Configuration.PackageSource(Source, existingSource.Name); - } - - ValidateCredentials(); - - if (!string.IsNullOrEmpty(Username)) - { - var hasExistingAuthTypes = existingSource.Credentials?.ValidAuthenticationTypes.Any() ?? false; - if (hasExistingAuthTypes && string.IsNullOrEmpty(ValidAuthenticationTypes)) - { - Console.WriteLine(LocalizedResourceManager.GetString("SourcesCommandClearingExistingAuthTypes"), Name); - } - - var credentials = Configuration.PackageSourceCredential.FromUserInput( - Name, - Username, - Password, - StorePasswordInClearText, - ValidAuthenticationTypes); - existingSource.Credentials = credentials; } - SourceProvider.UpdatePackageSource(existingSource, updateCredentials: existingSource.Credentials != null, updateEnabled: false); - - Console.WriteLine(LocalizedResourceManager.GetString("SourcesCommandUpdateSuccessful"), Name); - } - - private void ValidateCredentials() - { - var isUsernameEmpty = string.IsNullOrEmpty(Username); - var isPasswordEmpty = string.IsNullOrEmpty(Password); - var isAuthTypesEmpty = string.IsNullOrEmpty(ValidAuthenticationTypes); - - if (isUsernameEmpty ^ isPasswordEmpty) - { - // If only one of them is set, throw. - throw new CommandLineException(LocalizedResourceManager.GetString("SourcesCommandCredentialsRequired")); - } - - if (isPasswordEmpty && !isAuthTypesEmpty) - { - // can't specify auth types without credentials - throw new CommandLineException(LocalizedResourceManager.GetString("SourcesCommandCredentialsRequiredWithAuthTypes")); - } - - - } - - private void PrintRegisteredSourcesShort() - { - foreach (var source in SourceProvider.LoadPackageSources()) - { - Console.Write(source.IsEnabled ? 'E' : 'D'); - if (source.IsMachineWide) - { - Console.Write('M'); - } - if (source.IsOfficial) - { - Console.Write('O'); - } - Console.Write(' '); - Console.WriteLine(source.Source); - } - } - - private void PrintRegisteredSourcesDetailed() - { - var sourcesList = SourceProvider.LoadPackageSources().ToList(); - if (!sourcesList.Any()) - { - Console.WriteLine(LocalizedResourceManager.GetString("SourcesCommandNoSources")); - return; - } - Console.PrintJustified(0, LocalizedResourceManager.GetString("SourcesCommandRegisteredSources")); - Console.WriteLine(); - var sourcePadding = new string(' ', 6); - for (var i = 0; i < sourcesList.Count; i++) - { - var source = sourcesList[i]; - var indexNumber = i + 1; - var namePadding = new string(' ', i >= 9 ? 1 : 2); - Console.WriteLine( - " {0}.{1}{2} [{3}]", - indexNumber, - namePadding, - source.Name, - source.IsEnabled ? LocalizedResourceManager.GetString("SourcesCommandEnabled") : LocalizedResourceManager.GetString("SourcesCommandDisabled")); - Console.WriteLine("{0}{1}", sourcePadding, source.Source); + switch (action) + { + case SourcesAction.Add: + var addArgs = new AddSourceArgs() { Name = Name, Source = Source, Username = Username, Password = Password, StorePasswordInClearText = StorePasswordInClearText, ValidAuthenticationTypes = ValidAuthenticationTypes, Configfile = ConfigFile }; + AddSourceRunner.Run(addArgs, () => Console); + break; + case SourcesAction.Update: + var updateSourceArgs = new UpdateSourceArgs() { Name = Name, Source = Source, Username = Username, Password = Password, StorePasswordInClearText = StorePasswordInClearText, ValidAuthenticationTypes = ValidAuthenticationTypes, Configfile = ConfigFile }; + UpdateSourceRunner.Run(updateSourceArgs, () => Console); + break; + case SourcesAction.Remove: + var removeSourceArgs = new RemoveSourceArgs() { Name = Name, Configfile = ConfigFile }; + RemoveSourceRunner.Run(removeSourceArgs, () => Console); + break; + case SourcesAction.Disable: + var disableSourceArgs = new DisableSourceArgs() { Name = Name, Configfile = ConfigFile }; + DisableSourceRunner.Run(disableSourceArgs, () => Console); + break; + case SourcesAction.Enable: + var enableSourceArgs = new EnableSourceArgs() { Name = Name, Configfile = ConfigFile }; + EnableSourceRunner.Run(enableSourceArgs, () => Console); + break; + case SourcesAction.List: + var listSourceArgs = new ListSourceArgs() { Configfile = ConfigFile, Format = Format.ToString() }; + ListSourceRunner.Run(listSourceArgs, () => Console); + break; } } } -} \ No newline at end of file +} diff --git a/src/NuGet.Clients/NuGet.CommandLine/Commands/UpdateCommand.cs b/src/NuGet.Clients/NuGet.CommandLine/Commands/UpdateCommand.cs index f4b59694744..ed7ce666b37 100644 --- a/src/NuGet.Clients/NuGet.CommandLine/Commands/UpdateCommand.cs +++ b/src/NuGet.Clients/NuGet.CommandLine/Commands/UpdateCommand.cs @@ -10,6 +10,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using NuGet.Commands; using NuGet.Common; using NuGet.Configuration; using NuGet.PackageManagement; @@ -77,7 +78,7 @@ public override async Task ExecuteCommandAsync() if (string.IsNullOrEmpty(inputFile)) { - throw new CommandLineException(NuGetResources.InvalidFile); + throw new CommandException(NuGetResources.InvalidFile); } _msbuildDirectory = MsBuildUtility.GetMsBuildDirectoryFromMsBuildPath(MSBuildPath, MSBuildVersion, Console).Value.Path; @@ -105,7 +106,7 @@ public override async Task ExecuteCommandAsync() { if (!File.Exists(inputFile)) { - throw new CommandLineException(NuGetResources.UnableToFindProject, inputFile); + throw new CommandException(NuGetResources.UnableToFindProject, inputFile); } var projectSystem = new MSBuildProjectSystem( @@ -118,7 +119,7 @@ public override async Task ExecuteCommandAsync() if (!File.Exists(inputFile)) { - throw new CommandLineException(NuGetResources.UnableToFindSolution, inputFile); + throw new CommandException(NuGetResources.UnableToFindSolution, inputFile); } // update with solution as parameter @@ -188,7 +189,7 @@ private MSBuildProjectSystem GetProject(string path, INuGetProjectContext projec { return GetMSBuildProject(path, projectContext); } - catch (CommandLineException e) + catch (CommandException e) { if (Console.Verbosity == Verbosity.Detailed || ExceptionLogger.Instance.ShowStack) { @@ -270,7 +271,7 @@ private async Task UpdatePackagesAsync(MSBuildProjectSystem project, string pack var nugetProject = new MSBuildNuGetProject(project, packagesDirectory, project.ProjectFullPath); if (!nugetProject.PackagesConfigNuGetProject.PackagesConfigExists()) { - throw new CommandLineException(LocalizedResourceManager.GetString("NoPackagesConfig")); + throw new CommandException(LocalizedResourceManager.GetString("NoPackagesConfig")); } var versionConstraints = Safe ? @@ -412,7 +413,7 @@ private string GetPackagesDirectory(string packagesDir) } } - throw new CommandLineException(LocalizedResourceManager.GetString("UnableToLocatePackagesFolder")); + throw new CommandException(LocalizedResourceManager.GetString("UnableToLocatePackagesFolder")); } private MSBuildProjectSystem GetMSBuildProject(string packageReferenceFilePath, INuGetProjectContext projectContext) @@ -423,12 +424,12 @@ private MSBuildProjectSystem GetMSBuildProject(string packageReferenceFilePath, if (projectFiles.Length == 0) { - throw new CommandLineException(LocalizedResourceManager.GetString("UnableToLocateProjectFile"), packageReferenceFilePath); + throw new CommandException(LocalizedResourceManager.GetString("UnableToLocateProjectFile"), packageReferenceFilePath); } if (projectFiles.Length > 1) { - throw new CommandLineException(LocalizedResourceManager.GetString("MultipleProjectFilesFound"), packageReferenceFilePath); + throw new CommandException(LocalizedResourceManager.GetString("MultipleProjectFilesFound"), packageReferenceFilePath); } return new MSBuildProjectSystem(_msbuildDirectory, projectFiles[0], projectContext); diff --git a/src/NuGet.Clients/NuGet.CommandLine/Common/CommandLineException.cs b/src/NuGet.Clients/NuGet.CommandLine/Common/CommandLineException.cs deleted file mode 100644 index 91c6b917a23..00000000000 --- a/src/NuGet.Clients/NuGet.CommandLine/Common/CommandLineException.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System; -using System.Globalization; -using System.Runtime.Serialization; - -namespace NuGet.CommandLine -{ - [Serializable] - public class CommandLineException : Exception - { - public CommandLineException() - { - } - - public CommandLineException(string message) - : base(message) - { - } - - public CommandLineException(string format, params object[] args) - : base(String.Format(CultureInfo.CurrentCulture, format, args)) - { - } - - public CommandLineException(string message, Exception exception) - : base(message, exception) - { - } - - protected CommandLineException(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } - } -} diff --git a/src/NuGet.Clients/NuGet.CommandLine/Common/CommandLineUtility.cs b/src/NuGet.Clients/NuGet.CommandLine/Common/CommandLineUtility.cs index 999f8edcbd6..2a33b3e9a1e 100644 --- a/src/NuGet.Clients/NuGet.CommandLine/Common/CommandLineUtility.cs +++ b/src/NuGet.Clients/NuGet.CommandLine/Common/CommandLineUtility.cs @@ -6,6 +6,7 @@ using System.Globalization; using System.IO; using System.Linq; +using NuGet.Commands; using NuGet.Common; using NuGet.Configuration; using NuGet.Packaging.Signing; @@ -19,7 +20,7 @@ public static void ValidateSource(string source) Uri result; if (!Uri.TryCreate(source, UriKind.Absolute, out result)) { - throw new CommandLineException(LocalizedResourceManager.GetString("InvalidSource"), source); + throw new CommandException(LocalizedResourceManager.GetString("InvalidSource"), source); } } diff --git a/src/NuGet.Clients/NuGet.CommandLine/Common/ExitCodeException.cs b/src/NuGet.Clients/NuGet.CommandLine/Common/ExitCodeException.cs index 30bedf89a52..db912aef95b 100644 --- a/src/NuGet.Clients/NuGet.CommandLine/Common/ExitCodeException.cs +++ b/src/NuGet.Clients/NuGet.CommandLine/Common/ExitCodeException.cs @@ -1,9 +1,13 @@ -using System; +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using NuGet.Commands; namespace NuGet.CommandLine { [Serializable] - public class ExitCodeException : CommandLineException + public sealed class ExitCodeException : CommandException { public ExitCodeException(int exitCode) { @@ -12,4 +16,4 @@ public ExitCodeException(int exitCode) public int ExitCode { get; } } -} \ No newline at end of file +} diff --git a/src/NuGet.Clients/NuGet.CommandLine/Common/SelfUpdater.cs b/src/NuGet.Clients/NuGet.CommandLine/Common/SelfUpdater.cs index 40e9cd5ffdd..2bcb755642c 100644 --- a/src/NuGet.Clients/NuGet.CommandLine/Common/SelfUpdater.cs +++ b/src/NuGet.Clients/NuGet.CommandLine/Common/SelfUpdater.cs @@ -9,6 +9,7 @@ using System.Reflection; using System.Threading; using System.Threading.Tasks; +using NuGet.Commands; using NuGet.Common; using NuGet.PackageManagement; using NuGet.Packaging; @@ -111,7 +112,7 @@ internal async Task UpdateSelfFromVersionAsync(string exePath, bool prerelease, // If for some reason this package doesn't have NuGet.exe then we don't want to use it if (nugetExeInPackageFilePath == null) { - throw new CommandLineException(LocalizedResourceManager.GetString("UpdateCommandUnableToLocateNuGetExe")); + throw new CommandException(LocalizedResourceManager.GetString("UpdateCommandUnableToLocateNuGetExe")); } string renamedPath = exePath + ".old"; diff --git a/src/NuGet.Clients/NuGet.CommandLine/Common/Verbosity.cs b/src/NuGet.Clients/NuGet.CommandLine/Common/Verbosity.cs index 373b10a5cfc..ce9ebc61ad0 100644 --- a/src/NuGet.Clients/NuGet.CommandLine/Common/Verbosity.cs +++ b/src/NuGet.Clients/NuGet.CommandLine/Common/Verbosity.cs @@ -1,4 +1,6 @@ - +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + namespace NuGet.CommandLine { public enum Verbosity diff --git a/src/NuGet.Clients/NuGet.CommandLine/MsBuildUtility.cs b/src/NuGet.Clients/NuGet.CommandLine/MsBuildUtility.cs index 8050290aafe..a6c859df13c 100644 --- a/src/NuGet.Clients/NuGet.CommandLine/MsBuildUtility.cs +++ b/src/NuGet.Clients/NuGet.CommandLine/MsBuildUtility.cs @@ -13,8 +13,8 @@ using System.Threading.Tasks; using System.Xml.Linq; using Microsoft.VisualStudio.Setup.Configuration; +using NuGet.Commands; using NuGet.Common; -using NuGet.Configuration; using NuGet.ProjectModel; namespace NuGet.CommandLine @@ -40,7 +40,7 @@ public static int Build(string msbuildDirectory, if (!File.Exists(msbuildPath)) { - throw new CommandLineException( + throw new CommandException( string.Format( CultureInfo.CurrentCulture, LocalizedResourceManager.GetString(nameof(NuGetResources.MsBuildDoesNotExistAtPath)), @@ -84,7 +84,7 @@ public static async Task GetProjectReferencesAsync( if (!File.Exists(msbuildPath)) { - throw new CommandLineException( + throw new CommandException( string.Format( CultureInfo.CurrentCulture, LocalizedResourceManager.GetString(nameof(NuGetResources.MsBuildDoesNotExistAtPath)), @@ -157,7 +157,7 @@ public static async Task GetProjectReferencesAsync( } catch (Exception ex) { - throw new CommandLineException( + throw new CommandException( LocalizedResourceManager.GetString(nameof(NuGetResources.Error_CannotKillMsBuild)) + " : " + ex.Message, ex); @@ -189,7 +189,7 @@ public static async Task GetProjectReferencesAsync( if (!finished) { // MSBuild timed out - throw new CommandLineException( + throw new CommandException( LocalizedResourceManager.GetString(nameof(NuGetResources.Error_MsBuildTimedOut))); } @@ -394,7 +394,7 @@ public static IEnumerable GetAllProjectFileNamesWithXBuild(string soluti var solutionParserType = assembly.GetType("Mono.XBuild.CommandLine.SolutionParser"); if (solutionParserType == null) { - throw new CommandLineException( + throw new CommandException( LocalizedResourceManager.GetString("Error_CannotGetXBuildSolutionParser")); } @@ -403,7 +403,7 @@ public static IEnumerable GetAllProjectFileNamesWithXBuild(string soluti new Type[] { typeof(string) }); if (getAllProjectFileNamesMethod == null) { - throw new CommandLineException( + throw new CommandException( LocalizedResourceManager.GetString("Error_CannotGetGetAllProjectFileNamesMethod")); } @@ -419,7 +419,7 @@ public static IEnumerable GetAllProjectFileNamesWithXBuild(string soluti solutionFile, ex.Message); - throw new CommandLineException(message); + throw new CommandException(message); } } @@ -451,7 +451,7 @@ public static IEnumerable GetAllProjectFileNamesWithMsBuild( solutionFile, exMessage); - throw new CommandLineException(message); + throw new CommandException(message); } } @@ -535,7 +535,7 @@ public static MsBuildToolset GetMsBuildToolset(string userVersion, IConsole cons if (!installedToolsets.Any()) { - throw new CommandLineException( + throw new CommandException( LocalizedResourceManager.GetString( nameof(NuGetResources.Error_CannotFindMsbuild))); } @@ -721,7 +721,7 @@ private static MsBuildToolset GetToolsetFromPath( if (selectedToolset == null) { - throw new CommandLineException( + throw new CommandException( LocalizedResourceManager.GetString( nameof(NuGetResources.Error_MSBuildNotInstalled))); } @@ -773,7 +773,7 @@ private static MsBuildToolset GetToolsetFromUserVersion( nameof(NuGetResources.Error_CannotFindMsbuild)), userVersion); - throw new CommandLineException(message); + throw new CommandException(message); } return selectedToolset; @@ -827,7 +827,7 @@ public static Lazy GetMsBuildDirectoryFromMsBuildPath(string msb nameof(NuGetResources.MsbuildPathNotExist)), msbuildPath); - throw new CommandLineException(message); + throw new CommandException(message); } return new Lazy(() => new MsBuildToolset(msbuildVersion, msbuildPath)); diff --git a/src/NuGet.Clients/NuGet.CommandLine/NuGet.CommandLine.csproj b/src/NuGet.Clients/NuGet.CommandLine/NuGet.CommandLine.csproj index cf3ea3d8075..8a6eb76994c 100644 --- a/src/NuGet.Clients/NuGet.CommandLine/NuGet.CommandLine.csproj +++ b/src/NuGet.Clients/NuGet.CommandLine/NuGet.CommandLine.csproj @@ -121,16 +121,28 @@ - + + + + + + 0 + + + + $(OutputPath)NuGet.exe $(ILMergeExePath) /lib:$(OutputPath) /out:$(ArtifactsDirectory)$(VsixOutputDirName)\NuGet.exe @(MergeAllowDup -> '/allowdup:%(Identity)', ' ') /log:$(OutputPath)IlMergeLog.txt $(IlmergeCommand) /delaysign /keyfile:$(MS_PFX_PATH) - $(IlmergeCommand) $(PathToBuiltNuGetExe) @(BuildArtifacts->'%(filename)%(extension)', ' ') + + $(IlmergeCommand) $(PathToBuiltNuGetExe) @(BuildArtifacts->'%(filename)%(extension)', ' ') @(LocalizedArtifacts->'%(fullpath)', ' ') diff --git a/src/NuGet.Clients/NuGet.CommandLine/NuGetCommand.resx b/src/NuGet.Clients/NuGet.CommandLine/NuGetCommand.resx index 1ab50bd03c5..05ca0b0cb0c 100644 --- a/src/NuGet.Clients/NuGet.CommandLine/NuGetCommand.resx +++ b/src/NuGet.Clients/NuGet.CommandLine/NuGetCommand.resx @@ -370,8 +370,7 @@ nuget setapikey 4003d786-cc37-4004-bfdf-c4f3e8ef9b3a -Source http://example.com/ <API key> [options] - Provides the ability to manage list of sources located in %AppData%\NuGet\NuGet.config - Please don't localize " %AppData%\NuGet\NuGet.config" + Provides the ability to manage list of sources located in NuGet.config files. Name of the source. diff --git a/src/NuGet.Clients/NuGet.CommandLine/NuGetResources.resx b/src/NuGet.Clients/NuGet.CommandLine/NuGetResources.resx index 44a54ea1f47..8f139c26cc2 100644 --- a/src/NuGet.Clients/NuGet.CommandLine/NuGetResources.resx +++ b/src/NuGet.Clients/NuGet.CommandLine/NuGetResources.resx @@ -303,42 +303,6 @@ Package "{0}" is already installed. - - No sources found. - - - Registered Sources: - - - The source specified is invalid. Please provide a valid source. - - - The name specified cannot be empty. Please provide a valid name. - - - Package source with Name: {0} added successfully. - - - The source specified cannot be empty. Please provide a valid source. - - - The name specified has already been added to the list of available package sources. Please provide a unique name. - - - The source specified has already been added to the list of available package sources. Please provide a unique source. - - - Unable to find any package source(s) matching name: {0}. - - - Package source with Name: {0} removed successfully. - - - Package source name 'All' is a reserved name. - - - All - Failed to build package. Ensure '{0}' includes assembly files. For help on building symbols package, visit {1}. @@ -375,18 +339,6 @@ Please provide proxy credentials: - - Disabled - - - Enabled - - - Package source with Name: {0} disabled successfully. - - - Package source with Name: {0} enabled successfully. - Version "{0}" does not follow semantic versioning guidelines. @@ -405,12 +357,6 @@ File from dependency is not changed. File '{0}' is not added. - - Package source "{0}" was successfully updated. - - - Both UserName and Password must be specified. - Package restore is disabled. To enable it, open the Visual Studio Options dialog, click on Package Manager node and check '{0}'. You can also enable package restore by setting the environment variable 'EnableNuGetPackageRestore' to 'true'. @@ -438,9 +384,6 @@ Property Settings is null. - - Property SourceProvider is null. - The value of MinClientVersion argument is not a valid version. @@ -3047,474 +2990,6 @@ To prevent NuGet from downloading packages during build, open the Visual Studio 已安裝封裝 "{0}"。 - - Nebyly nalezeny žádné zdroje. - - - Es wurden keine Quellen gefunden. - - - No se ha encontrado ningún origen. - - - Aucune source trouvée. - - - Nessuna fonte trovata. - - - ソースが見つかりません。 - - - 소스를 찾을 수 없습니다. - - - Nie znaleziono żadnych źródeł. - - - Nenhuma origem encontrada. - - - Источники не обнаружены. - - - Hiçbir kaynak bulunamadı. - - - 找不到源。 - - - 找不到來源。 - - - Registrované zdroje: - - - Registrierte Quellen: - - - Orígenes registrados: - - - Sources inscrites : - - - Fonti registrate: - - - 登録されているソース: - - - 등록된 소스: - - - Zarejestrowane źródła: - - - Origens registradas: - - - Зарегистрированные источники: - - - Kayıtlı Kaynaklar: - - - 已注册的源: - - - 已註冊來源: - - - Zadaný zdroj je neplatný. Zadejte platný zdroj. - - - Die angegebene Quelle ist ungültig. Bitte geben Sie eine gültige Quelle an. - - - El origen especificado no es válido. Proporcione un origen válido. - - - La source spécifiée n'est pas valide. Veuillez fournir une source valide. - - - La fonte specificata non è valida. Fornire una fonte valida. - - - 指定されたソースは無効です。有効なソースを指定してください。 - - - 지정한 소스가 잘못되었습니다. 올바른 소스를 제공하십시오. - - - Podane źródło jest nieprawidłowe. Określ prawidłowe źródło. - - - A origem especificada é inválida. Forneça uma origem válida. - - - Указан недопустимый источник. Укажите допустимый источник. - - - Belirtilen kaynak geçersiz. Lütfen geçerli bir kaynak belirtin. - - - 指定的源无效。请提供有效源。 - - - 指定的來源無效。請提供有效來源。 - - - Zadaný název nesmí být prázdný. Zadejte platný název. - - - Der angegebene Name darf nicht leer sein. Bitte geben Sie einen gültigen Namen an. - - - El nombre especificado no puede estar vacío. Proporcione un nombre válido. - - - Le nom spécifié ne peut pas être vide. Veuillez fournir un nom valide. - - - Il nome specificato non può essere vuoto. Fornire un nome valido. - - - 空の名前は指定できません。有効な名前を指定してください。 - - - 지정한 이름은 비워둘 수 없습니다. 올바른 이름을 제공하십시오. - - - Nazwa nie może być pusta. Określ prawidłową nazwę. - - - O nome especificado não pode ficar vazio. Forneça um nome válido. - - - Указанное имя не может быть пустым. Укажите допустимое имя. - - - Belirtilen ad boş olamaz. Lütfen geçerli bir ad belirtin. - - - 指定的名称不能为空。请提供有效的名称。 - - - 指定的名稱不能為空。請提供有效名稱。 - - - Zdroj balíčku s názvem {0} byl úspěšně přidán. - - - Die Paketquelle mit dem Namen "{0}" wurde erfolgreich hinzugefügt. - - - Origen del paquete con nombre: {0} agregado correctamente. - - - Source de package avec nom : {0} ajouté correctement. - - - Fonte pacchetto con nome: {0} aggiunto correttamente. - - - 次の名前のパッケージ ソース:{0} が正常に追加されました。 - - - {0} 이름의 패키지 소스가 추가되었습니다. - - - Pomyślnie dodano źródło pakietów o nazwie: {0}. - - - Origem de pacote com o nome: {0} adicionada com sucesso. - - - Источник пакетов с именем: {0} успешно добавлен. - - - {0} Adlı Paket Kaynağı başarıyla eklendi. - - - 已成功添加名为 {0} 的程序包源。 - - - 具有名稱的封裝來源: {0} 已成功新增。 - - - Zadaný zdroj nesmí být prázdný. Zadejte platný zdroj. - - - Die angegebene Quelle darf nicht leer sein. Bitte geben Sie eine gültige Quelle an. - - - El origen especificado no puede estar vacío. Proporcione un origen válido. - - - La source spécifiée ne peut pas être vide. Veuillez fournir une source valide. - - - La fonte specificata non può essere vuota. Fornire una fonte valida. - - - 空のソースは指定できません。有効なソースを指定してください。 - - - 지정한 소스는 비워둘 수 없습니다. 올바른 소스를 제공하십시오. - - - Źródło nie może być puste. Podaj prawidłowe źródło. - - - A origem especificada não ficar vazia. Forneça uma origem válida. - - - Указанный источник не может быть пустым. Укажите допустимый источник. - - - Belirtilen kaynak boş olamaz. Lütfen geçerli bir kaynak belirtin. - - - 指定的源不能为空。请提供有效源。 - - - 指定的來源不能為空。請提供有效的來源。 - - - Zadaný název již byl přidán do seznamu dostupných zdrojů balíčků. Zadejte jedinečný název. - - - Der angegebene Name wurde der Liste der verfügbaren Paketquellen bereits hinzugefügt. Bitte geben Sie einen eindeutigen Namen an. - - - El nombre especificado ya se ha agregado a la lista de orígenes de paquete disponibles. Proporcione un nombre único. - - - Le nom spécifié a déjà été ajouté à la liste de sources de package disponibles. Veuillez fournir un nom unique. - - - Il nome specificato è stato aggiunto alla lista di fonti pacchetto disponibili. Fornire un nome unico - - - 指定された名前は既に利用可能なパッケージ ソースの一覧に追加されています。一意の名前を指定してください。 - - - 지정한 이름은 이미 사용 가능한 패키지 소스 목록에 추가되어 있습니다. 고유한 이름을 제공하십시오. - - - Określona nazwa została już dodana do listy dostępnych źródeł pakietów. Podaj unikatową nazwę. - - - O nome especificado já foi adicionado à lista de origens de pacotes disponíveis. Forneça um nome exclusivo. - - - Указанное имя уже было добавлено в список доступных источников пакетов. Укажите уникальное имя. - - - Belirtilen ad zaten kullanılabilir paket kaynakları listesine eklenmiş. Lütfen benzersiz bir ad belirtin. - - - 指定的名称已添加到可用程序包源列表。请提供唯一名称。 - - - 指定的名稱已新增到可用封裝來源清單。請提供唯一名稱。 - - - Zadaný zdroj již byl přidán do seznamu dostupných zdrojů balíčků. Zadejte jedinečný zdroj. - - - Der angegebene Name wurde der Liste der verfügbaren Paketquellen bereits hinzugefügt. Bitte geben Sie eine eindeutige Quelle an. - - - El origen especificado ya se ha agregado a la lista de orígenes de paquete disponibles. Proporcione un nombre único. - - - La source spécifiée a déjà été ajoutée à la liste de sources de package disponibles. Veuillez fournir une source unique. - - - La fonte specificata è stato aggiunta alla lista di fonti pacchetto disponibili. Fornire una fonte unica. - - - 指定されたソースは既に利用可能なパッケージ ソースの一覧に追加されています。一意のソースを指定してください。 - - - 지정한 소스는 이미 사용 가능한 패키지 소스 목록에 추가되어 있습니다. 고유한 소스를 제공하십시오. - - - Określone źródło zostało już dodane do listy dostępnych źródeł pakietów. Podaj unikatowe źródło. - - - A origem especificada já foi adicionada à lista de origens de pacotes disponíveis. Forneça uma origem única. - - - Указанный источник имя уже был добавлен в список доступных источников пакетов. Укажите уникальный источник. - - - Belirtilen kaynak zaten kullanılabilir paket kaynakları listesine eklenmiş. Lütfen benzersiz bir kaynak belirtin. - - - 指定的源已添加到可用程序包源列表。请提供唯一源。 - - - 指定的來源已新增到可用封裝來源清單。請提供唯一名稱。 - - - Nebyly nalezen žádné zdroje balíčků odpovídající názvu: {0}. - - - Es wurden keine Paketquellen gefunden, die mit dem folgenden Namen übereinstimmen: {0}. - - - No se puede encontrar ningún nombre que coincida con los orígenes del paquete: {0}. - - - Impossible de trouver un nom de source de package correspondant : {0}. - - - Impossibile trovare il nome del pacchetto: {0}. - - - 名前と一致するパッケージ ソースが見つかりません: {0}. - - - {0} 이름과 일치하는 패키지 소스를 찾을 수 없습니다. - - - Nie można odnaleźć żadnych zgodnych nazw źródeł pakietów: {0}. - - - Não é possível encontrar nenhum nome correspondente de origem de pacote: {0}. - - - Не удалось найти источники пакетов, соответствующие имени: {0}. - - - Bu adla eşleşen herhangi bir paket kaynağı bulunamadı: {0}. - - - 找不到与名称 {0} 匹配的任何程序包源。 - - - 找不到入封裝來源相符名稱: {0}. - - - Zdroj balíčku s názvem {0} byl úspěšně odebrán. - - - Die Paketquelle mit dem Namen "{0}" wurde erfolgreich entfernt. - - - Origen del paquete con nombre: {0} quitado correctamente. - - - Source de package avec nom : {0} supprimé correctement. - - - Fonte pacchetto con nome: {0} rimossa correttamente.. - - - 次の名前のパッケージ ソース:{0} は正常に削除されました。 - - - {0} 이름의 패키지 소스가 제거되었습니다. - - - Pomyślnie usunięto źródło pakietów o nazwie: {0}. - - - Origem do pacote com o nome: {0} removida com sucesso. - - - Источник пакетов с именем: {0} успешно удален. - - - {0} Adlı Paket Kaynağı başarıyla kaldırıldı. - - - 已成功删除名为 {0} 的程序包源。 - - - 具有名稱的封裝來源: {3} 已成功移除。 - - - Název zdroje balíčku All je vyhrazený název. - - - Der Paketquellname "All" ist ein reservierter Name. - - - El nombre de origen del paquete 'Todo' es un nombre reservado. - - - Le nom de source de package 'All' est réservé. - - - Nome pacchetto 'Tutti' è un nome riservato. - - - パッケージ ソース名 'All' は予約名です。 - - - 패키지 소스 이름 'All'은 예약된 이름입니다. - - - Nazwa źródła pakietów „Wszystkie” jest nazwą zarezerwowaną. - - - O nome de origem do pacote 'Todos' é um nome reservado. - - - Имя источника пакетов "All" является зарезервированным именем. - - - Tümü' paket kaynak adı ayrılmış bir addır. - - - 程序包源名称 "All" 是保留名称。 - - - 封裝來源名稱 'All' 為保留的名稱。 - - - Vše - - - Alle - - - Todos - - - Tous - - - Tutto - - - すべて - - - 모두 - - - Wszystkie - - - Tudo - - - Все - - - Tümü - - - 全部 - - - 全部 - Sestavení balíčku se nezdařilo. Ověřte, zda {0} zahrnuje soubory sestavení. Nápovědu týkající se sestavení balíčku symbolů naleznete na webu {1}. @@ -3983,162 +3458,6 @@ To prevent NuGet from downloading packages during build, open the Visual Studio 請提供 Proxy 認證: - - Zakázáno - - - Deaktiviert - - - Deshabilitado - - - Désactivé - - - Disabilitato - - - 無効 - - - 사용 안 함 - - - Wyłączone - - - Desativado - - - Отключено - - - Devre dışı - - - 已禁用 - - - 已停用 - - - Povoleno - - - Aktiviert - - - Habilitado - - - Activé - - - Abilitato - - - 有効 - - - 사용 - - - Włączone - - - Ativado - - - Включено - - - Etkin - - - 已启用 - - - 已啟用 - - - Zdroj balíčku s názvem {0} byl úspěšně zakázán. - - - Die Paketquelle mit dem Namen "{0}" wurde erfolgreich deaktiviert. - - - Origen del paquete con nombre: {0} deshabilitado correctamente. - - - Source de package avec nom : {0} désactivé correctement. - - - Fonte pacchetto con nome: {0} disabilitata correttamente. - - - 次の名前のパッケージ ソース:{0} は正常に無効になりました。 - - - {0} 이름의 패키지 소스가 사용되지 않도록 설정되었습니다. - - - Pomyślnie wyłączono źródło pakietów o nazwie: {0}. - - - Origem de pacote com o nome: {0} desativada com sucesso. - - - Источник пакетов с именем: {0} успешно отключен. - - - {0} Adlı Paket Kaynağı başarıyla devre dışı bırakıldı. - - - 已成功禁用名为 {0} 的程序包源。 - - - 具有名稱的封裝來源: {1} 已成功停用。 - - - Zdroj balíčku s názvem {0} byl úspěšně povolen. - - - Die Paketquelle mit dem Namen "{0}" wurde erfolgreich aktiviert. - - - Origen del paquete con nombre: {0} habilitado correctamente. - - - Source de package avec nom : {0} activé correctement. - - - Fonte pacchetto con nome: {0} abilitata correttamente. - - - 次の名前のパッケージ ソース:{0} は正常に有効になりました。 - - - {0} 이름의 패키지 소스가 사용되도록 설정되었습니다. - - - Pomyślnie włączono źródło pakietów o nazwie: {0}. - - - Origem de pacote com o nome: {0} ativada com sucesso. - - - Источник пакетов с именем: {0} успешно включен. - - - {0} Adlı Paket Kaynağı başarıyla etkinleştirildi. - - - 已成功启用名为 {0} 的程序包源。 - - - 具有名稱的封裝來源: {2} 已成功啟用。 - Verze {0} nedodržuje pokyny pro správu sémantických verzí. @@ -4451,84 +3770,6 @@ To prevent NuGet from downloading packages during build, open the Visual Studio 檔案不存在 ({0})。 - - Zdroj balíčku {0} byl úspěšně aktualizován. - - - Die Paketquelle "{0}" wurde erfolgreich aktualisiert. - - - El origen del paquete '{0}' se ha actualizado correctamente. - - - La source de package « {0} » a été mise à jour correctement. - - - Fonte pacchetto "{0}" aggiornata correttamente. - - - パッケージ ソース "{0}" は正常に更新されました。 - - - 패키지 소스 "{0}"이(가) 업데이트되었습니다. - - - Źródło pakietów „{0}” zostało pomyślnie zaktualizowane. - - - A origem de pacote '{0}' foi atualizada com sucesso. - - - Источник пакетов "{0}" успешно обновлен. - - - "{0}" paket kaynağı başarıyla güncellendi. - - - 已成功更新程序包源“{0}”。 - - - 封裝來源 "{0}" 已成功更新。 - - - Je třeba zadat uživatelské jméno i heslo. - - - "UserName" und "Password" müssen angegeben werden. - - - Se deben especificar tanto el nombre de usuario como la contraseña. - - - Le @@@nom d'utilisateur et le mot de passe doivent être spécifiés. - - - Specificare nome utente e password. - - - UserName と Password の両方を指定する必要があります。 - - - 사용자 이름 및 암호를 모두 지정해야 합니다. - - - Należy określić zarówno nazwę użytkownika, jak i hasło. - - - O Nome de usuário e senha devem ser especificados. - - - Следует указать имя пользователя и пароль. - - - KullanıcıAdı ve Parolanın belirtilmesi gerekir. - - - 必须同时指定用户名和密码。 - - - 必須指定使用者名稱和密碼。 - Obnovení balíčku je zakázáno. Chcete-li je povolit, otevřete dialogové okno Možnosti sady Visual Studio, klikněte na uzel Správce balíčků a zaškrtněte položku {0}. Obnovení balíčku můžete rovněž povolit nastavením proměnné prostředí EnableNuGetPackageRestore na hodnotu true. @@ -6167,12 +5408,6 @@ Oluşturma sırasında NuGet'in paketleri indirmesini önlemek için, Visual Stu Long file path is currently only supported on Windows 10. Fore more details, please refer to https://aka.ms/nuget-long-path. - - Both UserName and Password must be specified if ValidAuthenticationTypes is specified - - - Clearing existing authentication types settings for package source '{0}'. - The action '{0}' is not recognized. 0 - action diff --git a/src/NuGet.Core/NuGet.CommandLine.XPlat/Commands/CommandParsers.cs b/src/NuGet.Core/NuGet.CommandLine.XPlat/Commands/CommandParsers.cs new file mode 100644 index 00000000000..6859660772c --- /dev/null +++ b/src/NuGet.Core/NuGet.CommandLine.XPlat/Commands/CommandParsers.cs @@ -0,0 +1,26 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +// Do not manually edit this autogenerated file: +// instead modify the neighboring .tt file (text template) and/or NuGet.CommandLine.Xplat\Commands\Commands.xml (data file), +// then re-execute the text template via "run custom tool" on VS context menu for .tt file, or via dotnet-t4 global tool. + +using System; +using Microsoft.Extensions.CommandLineUtils; +using NuGet.Common; + +namespace NuGet.CommandLine.XPlat +{ + internal static class CommandParsers + { + public static void Register(CommandLineApplication app, Func getLogger) + { + AddVerbParser.Register(app, getLogger); + DisableVerbParser.Register(app, getLogger); + EnableVerbParser.Register(app, getLogger); + ListVerbParser.Register(app, getLogger); + RemoveVerbParser.Register(app, getLogger); + UpdateVerbParser.Register(app, getLogger); + } + } +} diff --git a/src/NuGet.Core/NuGet.CommandLine.XPlat/Commands/CommandParsers.tt b/src/NuGet.Core/NuGet.CommandLine.XPlat/Commands/CommandParsers.tt new file mode 100644 index 00000000000..aed560beac7 --- /dev/null +++ b/src/NuGet.Core/NuGet.CommandLine.XPlat/Commands/CommandParsers.tt @@ -0,0 +1,226 @@ +<#@ template debug="false" hostspecific="true" language="C#" #> +<#@ assembly name="System.Xml.XDocument" #> +<#@ assembly name="System.Xml.Linq" #> +<#@ assembly name="System.Xml" #> +<#@ assembly name="System.Core" #> +<#@ import namespace="System.Xml.Linq" #> +<#@ import namespace="System.Linq" #> +<#@ output extension=".cs" #> +<# + string InitCaps(string input) + { + string output = input.Substring(0,1).ToUpper() + input.Substring(1); + return output; + } + + bool IsArgument(string type) + { + return type == "Argument"; + } + + string GetProperty(XElement element) + { + switch (element.Name.LocalName) + { + case "SingleValueOption": + return "Option"; + case "SwitchOption": + return "Option"; + case "Argument": + return "Argument"; + default: + return "Unknown Element Type" + element.Name.LocalName; + } + } + + string GetOptionType(XElement element) + { + switch (element.Name.LocalName) + { + case "SingleValueOption": + return "SingleValue"; + case "SwitchOption": + return "NoValue"; + case "Value": + return "Value"; + default: + return "Unknown Element Type" + element.Name.LocalName; + } + } + + var commandFile = this.Host.ResolvePath("Commands.xml"); + var commands = XDocument.Load(commandFile); +#> +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +// Do not manually edit this autogenerated file: +// instead modify the neighboring .tt file (text template) and/or NuGet.CommandLine.Xplat\Commands\Commands.xml (data file), +// then re-execute the text template via "run custom tool" on VS context menu for .tt file, or via dotnet-t4 global tool. + +using System; +using Microsoft.Extensions.CommandLineUtils; +using NuGet.Common; + +namespace NuGet.CommandLine.XPlat +{ + internal static class CommandParsers + { + public static void Register(CommandLineApplication app, Func getLogger) + { +<# + foreach (var command in commands.Descendants(XName.Get("Verb",""))) + { + var verbName = command.Attribute(XName.Get("Name", "")).Value; + var verbFormalName = InitCaps(verbName); +#> + <#= verbFormalName #>VerbParser.Register(app, getLogger); +<# + } +#> +<# + foreach (var command in commands.Descendants(XName.Get("Command",""))) + { + var commandName = command.Attribute(XName.Get("Name", "")).Value; + var commandFormalName = InitCaps(commandName); +#> + <#= commandFormalName #>CommandParser.Register(app, getLogger); +<# +} +#> } + } +<# + foreach (var command in commands.Descendants(XName.Get("Command",""))) + { + var commandName = command.Attribute(XName.Get("Name", "")).Value; + var commandFormalName = InitCaps(commandName); +#> + + internal partial class <#= commandFormalName #>CommandParser + { + internal static void Register(CommandLineApplication app, Func getLogger) + { + app.Command("<#= commandName #>", <#= commandFormalName #>Cmd => + { +<# + foreach (var option in command.Descendants()) { + var optionName = option.Attribute(XName.Get("Name", "")).Value; + var optionHelp = option.Attribute(XName.Get("Help", ""))?.Value; + var optionFormalName = optionName.Replace("-",""); + var optionCapsName = InitCaps(optionName); + if (IsArgument(GetProperty(option))) + { +#> + var <#= optionFormalName #> = <#= commandFormalName #>Cmd.Argument( + "<#= optionName #>", "<#= optionHelp != null ? optionHelp : "" #>"); +<# + } + else + { + var optionShortcut = option.Attribute(XName.Get("Shortcut",""))?.Value; +#> + var <#= optionFormalName #> = <#= commandFormalName #>Cmd.Option( + "<#= (optionShortcut != null ? "-" + optionShortcut + "|" : "") + "--" + optionName #>", + Strings.Source_Description, + CommandOptionType.<#= GetOptionType(option) #>); +<# + } + } +#> + <#= commandFormalName #>Cmd.HelpOption("-h|--help"); + + <#= commandFormalName #>Cmd.OnExecute(() => + { + var args = new <#= commandFormalName #>FArgs() + { +<# + foreach (var option in command.Descendants()) { + var optionName = option.Attribute(XName.Get("Name", "")).Value; + var optionFormalName = optionName.Replace("-",""); + var optionCapsName = InitCaps(optionFormalName); + if (IsArgument(GetProperty(option))) + { +#> + <#= optionCapsName #> = <#=optionFormalName#>.Value, +<# + } + else + { + var optionType = GetOptionType(option); + switch (optionType) + { + case "SingleValue": +#> + <#= optionCapsName #> = <#= optionFormalName #>.Value(), +<# + break; + case "NoValue": +#> + <#= optionCapsName #> = <#= optionFormalName #>.HasValue(), +<# + break; + } + + } + } + +#> + }; + + +<# // ****** IMPLEMENT REQUIRED ARGUMENTS ******** + + + foreach (var option in command.Descendants()) { + var optionName = option.Attribute(XName.Get("Name", "")).Value; + var required = option.Attribute(XName.Get("Required", ""))?.Value == "true"; + var optionFormalName = optionName.Replace("-",""); + var optionCapsName = InitCaps(optionFormalName); + + if (required) + { + if (IsArgument(GetProperty(option))) + { +#> + if (args.<#= optionCapsName #> == null) + { + throw new CommandException("'<#=optionFormalName#>' argument is missing but required."); + } +<# + } + else + { + var optionType = GetOptionType(option); + switch (optionType) + { + case "SingleValue": +#> + if (args.<#= optionCapsName #> == null) + { + throw new CommandException("'<#=optionFormalName#>' option is missing but required."); + } +<# + break; + case "NoValue": +#> + //TODO: implement required for bool +<# + break; + } + + } + } + } +// ****** END - IMPLEMENT REQUIRED ARGUMENTS ******** +#> + + <#= commandFormalName #>FRunner.Run(args, getLogger); + return 0; + }); + }); + } + } +<# +} // End of CommandParser class +#> +} diff --git a/src/NuGet.Core/NuGet.CommandLine.XPlat/Commands/Commands.xml b/src/NuGet.Core/NuGet.CommandLine.XPlat/Commands/Commands.xml new file mode 100644 index 00000000000..319f5211700 --- /dev/null +++ b/src/NuGet.Core/NuGet.CommandLine.XPlat/Commands/Commands.xml @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/NuGet.Core/NuGet.CommandLine.XPlat/Commands/Verbs.cs b/src/NuGet.Core/NuGet.CommandLine.XPlat/Commands/Verbs.cs new file mode 100644 index 00000000000..cb9dd1480fa --- /dev/null +++ b/src/NuGet.Core/NuGet.CommandLine.XPlat/Commands/Verbs.cs @@ -0,0 +1,307 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +// Do not manually edit this autogenerated file: +// instead modify the neighboring .tt file (text template) and/or NuGet.CommandLine.Xplat\Commands\Commands.xml (data file), +// then re-execute the text template via "run custom tool" on VS context menu for .tt file, or via dotnet-t4 global tool. + +using System; +using Microsoft.Extensions.CommandLineUtils; +using NuGet.Commands; +using NuGet.Common; + +namespace NuGet.CommandLine.XPlat +{ + internal partial class AddVerbParser + { + internal static void Register(CommandLineApplication app, + Func getLogger) + { + app.Command("add", AddCmd => + { + AddCmd.Command("source", SourceCmd => + { + var Source = SourceCmd.Argument( + "PackageSourcePath", Strings.SourcesCommandSourceDescription); + var name = SourceCmd.Option( + "-n|--name", + Strings.SourcesCommandNameDescription, + CommandOptionType.SingleValue); + var username = SourceCmd.Option( + "-u|--username", + Strings.SourcesCommandUserNameDescription, + CommandOptionType.SingleValue); + var password = SourceCmd.Option( + "-p|--password", + Strings.SourcesCommandPasswordDescription, + CommandOptionType.SingleValue); + var storePasswordInClearText = SourceCmd.Option( + "--store-password-in-clear-text", + Strings.SourcesCommandStorePasswordInClearTextDescription, + CommandOptionType.NoValue); + var validAuthenticationTypes = SourceCmd.Option( + "--valid-authentication-types", + Strings.SourcesCommandValidAuthenticationTypesDescription, + CommandOptionType.SingleValue); + var configfile = SourceCmd.Option( + "--configfile", + Strings.Option_ConfigFile, + CommandOptionType.SingleValue); + SourceCmd.HelpOption("-h|--help"); + SourceCmd.Description = Strings.AddSourceCommandDescription; + SourceCmd.OnExecute(() => + { + var args = new AddSourceArgs() + { + Source = Source.Value, + Name = name.Value(), + Username = username.Value(), + Password = password.Value(), + StorePasswordInClearText = storePasswordInClearText.HasValue(), + ValidAuthenticationTypes = validAuthenticationTypes.Value(), + Configfile = configfile.Value(), + }; + + AddSourceRunner.Run(args, getLogger); + return 0; + }); + }); + AddCmd.HelpOption("-h|--help"); + AddCmd.Description = Strings.Add_Description; + AddCmd.OnExecute(() => + { + app.ShowHelp("add"); + return 0; + }); + }); + } + } + + internal partial class DisableVerbParser + { + internal static void Register(CommandLineApplication app, + Func getLogger) + { + app.Command("disable", DisableCmd => + { + DisableCmd.Command("source", SourceCmd => + { + var name = SourceCmd.Argument( + "name", Strings.SourcesCommandNameDescription); + var configfile = SourceCmd.Option( + "--configfile", + Strings.Option_ConfigFile, + CommandOptionType.SingleValue); + SourceCmd.HelpOption("-h|--help"); + SourceCmd.Description = Strings.DisableSourceCommandDescription; + SourceCmd.OnExecute(() => + { + var args = new DisableSourceArgs() + { + Name = name.Value, + Configfile = configfile.Value(), + }; + + DisableSourceRunner.Run(args, getLogger); + return 0; + }); + }); + DisableCmd.HelpOption("-h|--help"); + DisableCmd.Description = Strings.Disable_Description; + DisableCmd.OnExecute(() => + { + app.ShowHelp("disable"); + return 0; + }); + }); + } + } + + internal partial class EnableVerbParser + { + internal static void Register(CommandLineApplication app, + Func getLogger) + { + app.Command("enable", EnableCmd => + { + EnableCmd.Command("source", SourceCmd => + { + var name = SourceCmd.Argument( + "name", Strings.SourcesCommandNameDescription); + var configfile = SourceCmd.Option( + "--configfile", + Strings.Option_ConfigFile, + CommandOptionType.SingleValue); + SourceCmd.HelpOption("-h|--help"); + SourceCmd.Description = Strings.EnableSourceCommandDescription; + SourceCmd.OnExecute(() => + { + var args = new EnableSourceArgs() + { + Name = name.Value, + Configfile = configfile.Value(), + }; + + EnableSourceRunner.Run(args, getLogger); + return 0; + }); + }); + EnableCmd.HelpOption("-h|--help"); + EnableCmd.Description = Strings.Enable_Description; + EnableCmd.OnExecute(() => + { + app.ShowHelp("enable"); + return 0; + }); + }); + } + } + + internal partial class ListVerbParser + { + internal static void Register(CommandLineApplication app, + Func getLogger) + { + app.Command("list", ListCmd => + { + ListCmd.Command("source", SourceCmd => + { + var format = SourceCmd.Option( + "--format", + Strings.SourcesCommandFormatDescription, + CommandOptionType.SingleValue); + var configfile = SourceCmd.Option( + "--configfile", + Strings.Option_ConfigFile, + CommandOptionType.SingleValue); + SourceCmd.HelpOption("-h|--help"); + SourceCmd.Description = Strings.ListSourceCommandDescription; + SourceCmd.OnExecute(() => + { + var args = new ListSourceArgs() + { + Format = format.Value(), + Configfile = configfile.Value(), + }; + + ListSourceRunner.Run(args, getLogger); + return 0; + }); + }); + ListCmd.HelpOption("-h|--help"); + ListCmd.Description = Strings.List_Description; + ListCmd.OnExecute(() => + { + app.ShowHelp("list"); + return 0; + }); + }); + } + } + + internal partial class RemoveVerbParser + { + internal static void Register(CommandLineApplication app, + Func getLogger) + { + app.Command("remove", RemoveCmd => + { + RemoveCmd.Command("source", SourceCmd => + { + var name = SourceCmd.Argument( + "name", Strings.SourcesCommandNameDescription); + var configfile = SourceCmd.Option( + "--configfile", + Strings.Option_ConfigFile, + CommandOptionType.SingleValue); + SourceCmd.HelpOption("-h|--help"); + SourceCmd.Description = Strings.RemoveSourceCommandDescription; + SourceCmd.OnExecute(() => + { + var args = new RemoveSourceArgs() + { + Name = name.Value, + Configfile = configfile.Value(), + }; + + RemoveSourceRunner.Run(args, getLogger); + return 0; + }); + }); + RemoveCmd.HelpOption("-h|--help"); + RemoveCmd.Description = Strings.Remove_Description; + RemoveCmd.OnExecute(() => + { + app.ShowHelp("remove"); + return 0; + }); + }); + } + } + + internal partial class UpdateVerbParser + { + internal static void Register(CommandLineApplication app, + Func getLogger) + { + app.Command("update", UpdateCmd => + { + UpdateCmd.Command("source", SourceCmd => + { + var name = SourceCmd.Argument( + "name", Strings.SourcesCommandNameDescription); + var source = SourceCmd.Option( + "-s|--source", + Strings.SourcesCommandSourceDescription, + CommandOptionType.SingleValue); + var username = SourceCmd.Option( + "-u|--username", + Strings.SourcesCommandUserNameDescription, + CommandOptionType.SingleValue); + var password = SourceCmd.Option( + "-p|--password", + Strings.SourcesCommandPasswordDescription, + CommandOptionType.SingleValue); + var storePasswordInClearText = SourceCmd.Option( + "--store-password-in-clear-text", + Strings.SourcesCommandStorePasswordInClearTextDescription, + CommandOptionType.NoValue); + var validAuthenticationTypes = SourceCmd.Option( + "--valid-authentication-types", + Strings.SourcesCommandValidAuthenticationTypesDescription, + CommandOptionType.SingleValue); + var configfile = SourceCmd.Option( + "--configfile", + Strings.Option_ConfigFile, + CommandOptionType.SingleValue); + SourceCmd.HelpOption("-h|--help"); + SourceCmd.Description = Strings.UpdateSourceCommandDescription; + SourceCmd.OnExecute(() => + { + var args = new UpdateSourceArgs() + { + Name = name.Value, + Source = source.Value(), + Username = username.Value(), + Password = password.Value(), + StorePasswordInClearText = storePasswordInClearText.HasValue(), + ValidAuthenticationTypes = validAuthenticationTypes.Value(), + Configfile = configfile.Value(), + }; + + UpdateSourceRunner.Run(args, getLogger); + return 0; + }); + }); + UpdateCmd.HelpOption("-h|--help"); + UpdateCmd.Description = Strings.Update_Description; + UpdateCmd.OnExecute(() => + { + app.ShowHelp("update"); + return 0; + }); + }); + } + } + +} diff --git a/src/NuGet.Core/NuGet.CommandLine.XPlat/Commands/Verbs.tt b/src/NuGet.Core/NuGet.CommandLine.XPlat/Commands/Verbs.tt new file mode 100644 index 00000000000..f435019d6e3 --- /dev/null +++ b/src/NuGet.Core/NuGet.CommandLine.XPlat/Commands/Verbs.tt @@ -0,0 +1,221 @@ +<#@ template debug="false" hostspecific="true" language="C#" #> +<#@ assembly name="System.Xml.XDocument" #> +<#@ assembly name="System.Xml.Linq" #> +<#@ assembly name="System.Xml" #> +<#@ assembly name="System.Core" #> +<#@ import namespace="System.Xml.Linq" #> +<#@ import namespace="System.Linq" #> +<#@ output extension=".cs" #> +<# + string InitCaps(string input) + { + string output = input.Substring(0,1).ToUpper() + input.Substring(1); + return output; + } + + bool IsArgument(string type) + { + return type == "Argument"; + } + + string GetProperty(XElement element) + { + switch (element.Name.LocalName) + { + case "SingleValueOption": + return "Option"; + case "SwitchOption": + return "Option"; + case "Argument": + return "Argument"; + default: + return "Unknown Element Type" + element.Name.LocalName; + } + } + + string GetOptionType(XElement element) + { + switch (element.Name.LocalName) + { + case "SingleValueOption": + return "SingleValue"; + case "SwitchOption": + return "NoValue"; + case "Value": + return "Value"; + default: + return "Unknown Element Type" + element.Name.LocalName; + } + } + + var commandFile = this.Host.ResolvePath("Commands.xml"); + var commands = XDocument.Load(commandFile); +#> +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +// Do not manually edit this autogenerated file: +// instead modify the neighboring .tt file (text template) and/or NuGet.CommandLine.Xplat\Commands\Commands.xml (data file), +// then re-execute the text template via "run custom tool" on VS context menu for .tt file, or via dotnet-t4 global tool. + +using System; +using Microsoft.Extensions.CommandLineUtils; +using NuGet.Commands; +using NuGet.Common; + +namespace NuGet.CommandLine.XPlat +{ +<# +// ********************** Verb-Parser Template +foreach (var verb in commands.Descendants(XName.Get("Verb",""))) +{ + var commandName = verb.Attribute(XName.Get("Name", "")).Value; + var commandFormalName = InitCaps(commandName); +#> + internal partial class <#= commandFormalName #>VerbParser + { + internal static void Register(CommandLineApplication app, + Func getLogger) + { + app.Command("<#= commandName #>", <#= commandFormalName #>Cmd => + { +<# + foreach (var noun in verb.Descendants(XName.Get("Noun"))) + { + var nounName = noun.Attribute(XName.Get("Name", ""))?.Value; + var nounFormalName = InitCaps(nounName); + if (nounName != null) + { +#> + <#= commandFormalName #>Cmd.Command("<#= nounName #>", <#= nounFormalName #>Cmd => + { +<# + } + foreach (var option in noun.Descendants()) { + var optionName = option.Attribute(XName.Get("Name", "")).Value; + var optionLongName = option.Attribute(XName.Get("LongName", ""))?.Value; + var optionHelp = option.Attribute(XName.Get("Help", ""))?.Value; + var optionFormalName = optionName.Replace("-",""); + + if (IsArgument(GetProperty(option))) + { + +#> + var <#= optionFormalName #> = <#= nounFormalName #>Cmd.Argument( + "<#= optionLongName != null ? optionLongName : optionName #>", <#= optionHelp != null ? "Strings."+optionHelp : "" #>); +<# + } + else + { + var optionShortcut = option.Attribute(XName.Get("Shortcut",""))?.Value; +#> + var <#= optionFormalName #> = <#= nounFormalName #>Cmd.Option( + "<#= (optionShortcut != null ? "-" + optionShortcut + "|" : "") + "--" + optionName.ToLower() #>", + <#= optionHelp != null ? "Strings."+optionHelp : "" #>, + CommandOptionType.<#= GetOptionType(option) #>); +<# + } + } +#> + <#= nounFormalName #>Cmd.HelpOption("-h|--help"); + <#= nounFormalName #>Cmd.Description = Strings.<#= commandFormalName #><#= nounFormalName #>CommandDescription; + <#= nounFormalName #>Cmd.OnExecute(() => + { + var args = new <#= commandFormalName #><#= nounFormalName #>Args() + { +<# + foreach (var option in noun.Descendants()) + { + var optionName = option.Attribute(XName.Get("Name", "")).Value; + var optionFormalName = optionName.Replace("-",""); + var optionCapsName = InitCaps(optionFormalName); + if (IsArgument(GetProperty(option))) + { +#> + <#= optionCapsName #> = <#=optionFormalName#>.Value, +<# + } + else + { + var optionType = GetOptionType(option); + switch (optionType) + { + case "SingleValue": +#> + <#= optionCapsName #> = <#= optionFormalName #>.Value(), +<# + break; + case "NoValue": +#> + <#= optionCapsName #> = <#= optionFormalName #>.HasValue(), +<# + break; + } + } + } +#> + }; + +<# // ****** IMPLEMENT REQUIRED ARGUMENTS ******** + + foreach (var option2 in noun.Descendants()) + { + var required = option2.Attribute(XName.Get("Required", ""))?.Value == "true"; + if (required) + { + var optionName2 = option2.Attribute(XName.Get("Name", "")).Value; + var optionFormalName2 = optionName2.Replace("-",""); + var optionCapsName2 = InitCaps(optionFormalName2); + + if (IsArgument(GetProperty(option2))) + { +#> + if (args.<#= optionCapsName2 #> == null) + { + throw new CommandException("'<#=optionFormalName2#>' argument is missing but required."); + } +<# + } + else + { + var optionType2 = GetOptionType(option2); + switch (optionType2) + { + case "SingleValue": +#> + if (args.<#= optionCapsName2 #> == null) + { + throw new CommandException("'<#=optionFormalName2#>' option is missing but required."); + } +<# + break; + case "NoValue": +#> + //TODO: implement required for bool +<# + break; + } + } + } + } +#> <#= commandFormalName #><#= nounFormalName #>Runner.Run(args, getLogger); + return 0; + }); + }); +<# + } +#> + <#= commandFormalName #>Cmd.HelpOption("-h|--help"); + <#= commandFormalName #>Cmd.Description = Strings.<#= commandFormalName #>_Description; + <#= commandFormalName #>Cmd.OnExecute(() => + { + app.ShowHelp("<#= commandName #>"); + return 0; + }); + }); + } + } + +<# +} +#>} diff --git a/src/NuGet.Core/NuGet.CommandLine.XPlat/NuGet.CommandLine.XPlat.csproj b/src/NuGet.Core/NuGet.CommandLine.XPlat/NuGet.CommandLine.XPlat.csproj index 582e8183535..990001360ed 100644 --- a/src/NuGet.Core/NuGet.CommandLine.XPlat/NuGet.CommandLine.XPlat.csproj +++ b/src/NuGet.Core/NuGet.CommandLine.XPlat/NuGet.CommandLine.XPlat.csproj @@ -39,6 +39,16 @@ + + True + True + Verbs.tt + + + True + True + CommandParsers.tt + True True @@ -70,6 +80,21 @@ <_Parameter1>NuGet.CommandLine.Xplat.Tests + + + + + + + + Verbs.cs + TextTemplatingFileGenerator + + + CommandParsers.cs + TextTemplatingFileGenerator + + diff --git a/src/NuGet.Core/NuGet.CommandLine.XPlat/Program.cs b/src/NuGet.Core/NuGet.CommandLine.XPlat/Program.cs index ca20b753ca7..aab657bfdcb 100644 --- a/src/NuGet.Core/NuGet.CommandLine.XPlat/Program.cs +++ b/src/NuGet.Core/NuGet.CommandLine.XPlat/Program.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Linq; @@ -23,7 +24,6 @@ public class Program public static int Main(string[] args) { - // Start with a default logger, this will be updated according to the passed in verbosity var log = new CommandOutputLogger(LogLevel.Information); return MainInternal(args, log); } @@ -71,17 +71,19 @@ public static int MainInternal(string[] args, CommandOutputLogger log) CultureUtility.DisableLocalization(); } - var app = InitializeApp(args); - args = args - .Where(e => e != "package") - .ToArray(); + log.LogLevel = LogLevel.Information; - var verbosity = app.Option(XPlatUtility.VerbosityOption, Strings.Switch_Verbosity, CommandOptionType.SingleValue); + var app = InitializeApp(args, log); - // Options aren't parsed until we call app.Execute(), so look directly for the verbosity option ourselves - LogLevel logLevel; - TryParseVerbosity(args, verbosity, out logLevel); - log.LogLevel = logLevel; + // Remove the correct item in array for "package" commands. Only do this when "add package", "remove package", etc... are being run. + if (app.Name == DotnetPackageAppName) + { + // package add ... + args[0] = null; + args = args + .Where(e => e != null) + .ToArray(); + } NetworkProtocolUtility.SetConnectionLimit(); @@ -90,9 +92,6 @@ public static int MainInternal(string[] args, CommandOutputLogger log) // This method has no effect on .NET Core. NetworkProtocolUtility.ConfigureSupportedSslProtocols(); - // Register commands - RegisterCommands(app, log); - app.OnExecute(() => { app.ShowHelp(); @@ -110,20 +109,59 @@ public static int MainInternal(string[] args, CommandOutputLogger log) } catch (Exception e) { - // Log the error - if (ExceptionLogger.Instance.ShowStack) + bool handled = false; + string verb = null; + if (args.Length > 1) { - log.LogError(e.ToString()); + // Redirect users nicely if they do 'dotnet nuget sources add' or 'dotnet nuget add sources' + if (StringComparer.OrdinalIgnoreCase.Compare(args[0], "sources") == 0) + { + verb = args[1]; + } + else if (StringComparer.OrdinalIgnoreCase.Compare(args[1], "sources") == 0) + { + verb = args[0]; + } + + if (verb != null) + { + switch (verb.ToLowerInvariant()) + { + case "add": + case "remove": + case "update": + case "enable": + case "disable": + case "list": + log.LogMinimal(string.Format(CultureInfo.CurrentCulture, + Strings.Sources_Redirect, $"dotnet nuget {verb} source")); + handled = true; + break; + default: + break; + } + } } - else + + if (!handled) { - log.LogError(ExceptionUtilities.DisplayMessage(e)); - } + // Log the error + if (ExceptionLogger.Instance.ShowStack) + { + log.LogError(e.ToString()); + } + else + { + log.LogError(ExceptionUtilities.DisplayMessage(e)); + } - // Log the stack trace as verbose output. - log.LogVerbose(e.ToString()); + // Log the stack trace as verbose output. + log.LogVerbose(e.ToString()); - exitCode = 1; + exitCode = 1; + + ShowBestHelp(app, args); + } } // Limit the exit code range to 0-255 to support POSIX @@ -135,95 +173,69 @@ public static int MainInternal(string[] args, CommandOutputLogger log) return exitCode; } - private static CommandLineApplication InitializeApp(string[] args) + + private static CommandLineApplication InitializeApp(string[] args, CommandOutputLogger log) { + // Many commands don't want prefixes output. Use loggerFunc(log) instead of log to set the HidePrefix property first. + Func> loggerFunc = (commandOutputLogger) => + { + commandOutputLogger.HidePrefixForInfoAndMinimal = true; + return () => commandOutputLogger; + }; + var app = new CommandLineApplication(); if (args.Any() && args[0] == "package") { + // "dotnet * package" commands app.Name = DotnetPackageAppName; - } - else - { - app.Name = DotnetNuGetAppName; - } - app.FullName = Strings.App_FullName; - app.HelpOption(XPlatUtility.HelpOption); - app.VersionOption("--version", typeof(Program).GetTypeInfo().Assembly.GetName().Version.ToString()); - - return app; - } - - private static void RegisterCommands(CommandLineApplication app, CommandOutputLogger log) - { - // Register commands - if (app.Name == DotnetPackageAppName) - { AddPackageReferenceCommand.Register(app, () => log, () => new AddPackageReferenceCommandRunner()); RemovePackageReferenceCommand.Register(app, () => log, () => new RemovePackageReferenceCommandRunner()); ListPackageCommand.Register(app, () => log, () => new ListPackageCommandRunner()); } else { + // "dotnet nuget *" commands + app.Name = DotnetNuGetAppName; + CommandParsers.Register(app, loggerFunc(log)); DeleteCommand.Register(app, () => log); PushCommand.Register(app, () => log); LocalsCommand.Register(app, () => log); } - } - /// - /// Attempts to parse the desired log verbosity from the arguments. Returns true if the - /// arguments contains a valid verbosity option. If no valid verbosity option was - /// specified, the log level is set to a default log level and false is returned. - /// - private static bool TryParseVerbosity(string[] args, CommandOption verbosity, out LogLevel logLevel) - { - bool found = false; + app.FullName = Strings.App_FullName; + app.HelpOption(XPlatUtility.HelpOption); + app.VersionOption("--version", typeof(Program).GetTypeInfo().Assembly.GetName().Version.ToString()); - for (var index = 0; index < args.Length; index++) + return app; + } + + private static void ShowBestHelp(CommandLineApplication app, string[] args) + { + CommandLineApplication lastCommand = null; + List commands = app.Commands; + // tunnel down into the args, and show the best help possible. + foreach (string arg in args) { - var arg = args[index]; - string[] option; - if (arg.StartsWith("--")) - { - option = arg.Substring(2).Split(new[] { ':', '=' }, 2); - if (!string.Equals(option[0], verbosity.LongName, StringComparison.Ordinal)) - { - continue; - } - } - else if (arg.StartsWith("-")) + foreach (CommandLineApplication command in commands) { - option = arg.Substring(1).Split(new[] { ':', '=' }, 2); - if (!string.Equals(option[0], verbosity.ShortName, StringComparison.Ordinal)) + if (arg == command.Name) { - continue; + lastCommand = command; + commands = command.Commands; + break; } } - else - { - continue; - } - - if (option.Length == 2) - { - found = verbosity.TryParse(option[1]); - } - else if (index < args.Length - 1) - { - found = verbosity.TryParse(args[index + 1]); - } - - break; } - logLevel = XPlatUtility.GetLogLevel(verbosity); - - // Reset the parsed value since the application execution expects the option to not be - // populated yet, as this is a single-valued option. - verbosity.Values.Clear(); - - return found; + if (lastCommand != null) + { + lastCommand.ShowHelp(); + } + else + { + app.ShowHelp(); + } } } } diff --git a/src/NuGet.Core/NuGet.CommandLine.XPlat/Strings.Designer.cs b/src/NuGet.Core/NuGet.CommandLine.XPlat/Strings.Designer.cs index 466a52b15f6..a15d5d1dfc6 100644 --- a/src/NuGet.Core/NuGet.CommandLine.XPlat/Strings.Designer.cs +++ b/src/NuGet.Core/NuGet.CommandLine.XPlat/Strings.Designer.cs @@ -60,6 +60,15 @@ internal Strings() { } } + /// + /// Looks up a localized string similar to Add a NuGet source.. + /// + internal static string Add_Description { + get { + return ResourceManager.GetString("Add_Description", resourceCulture); + } + } + /// /// Looks up a localized string similar to all. /// @@ -168,6 +177,15 @@ internal static string AddPkg_UserSpecified { } } + /// + /// Looks up a localized string similar to Add a NuGet source.. + /// + internal static string AddSourceCommandDescription { + get { + return ResourceManager.GetString("AddSourceCommandDescription", resourceCulture); + } + } + /// /// Looks up a localized string similar to The API key for the server.. /// @@ -258,6 +276,15 @@ internal static string Delete_PackageIdAndVersion_Description { } } + /// + /// Looks up a localized string similar to Disable a NuGet source.. + /// + internal static string Disable_Description { + get { + return ResourceManager.GetString("Disable_Description", resourceCulture); + } + } + /// /// Looks up a localized string similar to Disable buffering when pushing to an HTTP(S) server to decrease memory usage.. /// @@ -267,6 +294,33 @@ internal static string DisableBuffering_Description { } } + /// + /// Looks up a localized string similar to Disable a NuGet source.. + /// + internal static string DisableSourceCommandDescription { + get { + return ResourceManager.GetString("DisableSourceCommandDescription", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Enable a NuGet source.. + /// + internal static string Enable_Description { + get { + return ResourceManager.GetString("Enable_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Enable a NuGet source.. + /// + internal static string EnableSourceCommandDescription { + get { + return ResourceManager.GetString("EnableSourceCommandDescription", resourceCulture); + } + } + /// /// Looks up a localized string similar to Item '{0}' for '{1}' in Imported file '{2}'.. /// @@ -483,6 +537,15 @@ internal static string InputFile_Description { } } + /// + /// Looks up a localized string similar to List configured NuGet sources.. + /// + internal static string List_Description { + get { + return ResourceManager.GetString("List_Description", resourceCulture); + } + } + /// /// Looks up a localized string similar to (A) : Auto-referenced package.. /// @@ -807,6 +870,15 @@ internal static string ListPkg_TransitiveHeader { } } + /// + /// Looks up a localized string similar to Lists all configured NuGet sources.. + /// + internal static string ListSourceCommandDescription { + get { + return ResourceManager.GetString("ListSourceCommandDescription", resourceCulture); + } + } + /// /// Looks up a localized string similar to Specifies the cache location(s) to list or clear. ///<all | http-cache | global-packages | temp>. @@ -1031,6 +1103,15 @@ internal static string NuGetXplatCommand_Interactive { } } + /// + /// Looks up a localized string similar to The NuGet configuration file. If specified, only the settings from this file will be used. If not specified, the hierarchy of configuration files from the current directory will be used. To learn more about NuGet configuration go to https://docs.microsoft.com/en-us/nuget/consume-packages/configuring-nuget-behavior.. + /// + internal static string Option_ConfigFile { + get { + return ResourceManager.GetString("Option_ConfigFile", resourceCulture); + } + } + /// /// Looks up a localized string similar to Specifies the directory for the created NuGet package file. If not specified, uses the current directory. /// @@ -1148,6 +1229,15 @@ internal static string PushCommandSkipDuplicateDescription { } } + /// + /// Looks up a localized string similar to Remove a NuGet source.. + /// + internal static string Remove_Description { + get { + return ResourceManager.GetString("Remove_Description", resourceCulture); + } + } + /// /// Looks up a localized string similar to Removes a package reference from a project.. /// @@ -1175,6 +1265,15 @@ internal static string RemovePkg_ProjectPathDescription { } } + /// + /// Looks up a localized string similar to Remove a NuGet source.. + /// + internal static string RemoveSourceCommandDescription { + get { + return ResourceManager.GetString("RemoveSourceCommandDescription", resourceCulture); + } + } + /// /// Looks up a localized string similar to List of projects and project folders to restore. Each value can be: a path to a project.json or global.json file, or a folder to recursively search for project.json files.. /// @@ -1283,6 +1382,96 @@ internal static string Source_Description { } } + /// + /// Looks up a localized string similar to The proper command is '{0}'.. + /// + internal static string Sources_Redirect { + get { + return ResourceManager.GetString("Sources_Redirect", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Provides the ability to manage list of sources located in %AppData%\NuGet\NuGet.config. + /// + internal static string SourcesCommandDescription { + get { + return ResourceManager.GetString("SourcesCommandDescription", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Applies to the list action. Accepts two values: Detailed (the default) and Short.. + /// + internal static string SourcesCommandFormatDescription { + get { + return ResourceManager.GetString("SourcesCommandFormatDescription", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Name of the source.. + /// + internal static string SourcesCommandNameDescription { + get { + return ResourceManager.GetString("SourcesCommandNameDescription", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Password to be used when connecting to an authenticated source.. + /// + internal static string SourcesCommandPasswordDescription { + get { + return ResourceManager.GetString("SourcesCommandPasswordDescription", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Path to the package(s) source.. + /// + internal static string SourcesCommandSourceDescription { + get { + return ResourceManager.GetString("SourcesCommandSourceDescription", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Enables storing portable package source credentials by disabling password encryption.. + /// + internal static string SourcesCommandStorePasswordInClearTextDescription { + get { + return ResourceManager.GetString("SourcesCommandStorePasswordInClearTextDescription", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to <List|Add|Remove|Enable|Disable|Update> -Name [name] -Source [source]. + /// + internal static string SourcesCommandUsageSummary { + get { + return ResourceManager.GetString("SourcesCommandUsageSummary", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to UserName to be used when connecting to an authenticated source.. + /// + internal static string SourcesCommandUserNameDescription { + get { + return ResourceManager.GetString("SourcesCommandUserNameDescription", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Comma-separated list of valid authentication types for this source. By default, all authentication types are valid. Example: basic,negotiate. + /// + internal static string SourcesCommandValidAuthenticationTypesDescription { + get { + return ResourceManager.GetString("SourcesCommandValidAuthenticationTypesDescription", resourceCulture); + } + } + /// /// Looks up a localized string similar to Appends a pre-release suffix to the internally generated version number.. /// @@ -1337,6 +1526,24 @@ internal static string Tool_Description { } } + /// + /// Looks up a localized string similar to Update a NuGet source.. + /// + internal static string Update_Description { + get { + return ResourceManager.GetString("Update_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Update a NuGet source.. + /// + internal static string UpdateSourceCommandDescription { + get { + return ResourceManager.GetString("UpdateSourceCommandDescription", resourceCulture); + } + } + /// /// Looks up a localized string similar to Overrides the version number from the nuspec file.. /// diff --git a/src/NuGet.Core/NuGet.CommandLine.XPlat/Strings.resx b/src/NuGet.Core/NuGet.CommandLine.XPlat/Strings.resx index 5948fb10efd..4e0228f171f 100644 --- a/src/NuGet.Core/NuGet.CommandLine.XPlat/Strings.resx +++ b/src/NuGet.Core/NuGet.CommandLine.XPlat/Strings.resx @@ -594,4 +594,75 @@ For more information, visit https://docs.nuget.org/docs/reference/command-line-r If a package and version already exists, skip it and continue with the next package in the push, if any. + + Provides the ability to manage list of sources located in NuGet.config files. + + + Add a NuGet source. + + + Disable a NuGet source. + + + Enable a NuGet source. + + + Lists all configured NuGet sources. + + + Remove a NuGet source. + + + Update a NuGet source. + + + Name of the source. + + + Password to be used when connecting to an authenticated source. + + + Path to the package(s) source. + + + Applies to the list action. Accepts two values: Detailed (the default) and Short. + + + <List|Add|Remove|Enable|Disable|Update> -Name [name] -Source [source] + Only localize "[name]" and "[source]" + + + UserName to be used when connecting to an authenticated source. + + + Enables storing portable package source credentials by disabling password encryption. + + + Comma-separated list of valid authentication types for this source. By default, all authentication types are valid. Example: basic,negotiate + Please don't localize "basic,negotiate" + + + The NuGet configuration file. If specified, only the settings from this file will be used. If not specified, the hierarchy of configuration files from the current directory will be used. To learn more about NuGet configuration go to https://docs.microsoft.com/en-us/nuget/consume-packages/configuring-nuget-behavior. + + + Add a NuGet source. + + + Disable a NuGet source. + + + Enable a NuGet source. + + + List configured NuGet sources. + + + Remove a NuGet source. + + + Update a NuGet source. + + + The proper command is '{0}'. + \ No newline at end of file diff --git a/src/NuGet.Core/NuGet.CommandLine.XPlat/Utility/CommandOutputLogger.cs b/src/NuGet.Core/NuGet.CommandLine.XPlat/Utility/CommandOutputLogger.cs index 04e889ee177..21840d563cd 100644 --- a/src/NuGet.Core/NuGet.CommandLine.XPlat/Utility/CommandOutputLogger.cs +++ b/src/NuGet.Core/NuGet.CommandLine.XPlat/Utility/CommandOutputLogger.cs @@ -1,4 +1,4 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; @@ -65,6 +65,11 @@ public override void LogInformationSummary(string data) } } + public bool HidePrefixForInfoAndMinimal + { + get; set; + } + protected virtual void LogInternal(LogLevel logLevel, string message) { if (logLevel < _logLevel) @@ -78,22 +83,22 @@ protected virtual void LogInternal(LogLevel logLevel, string message) switch (logLevel) { case LogLevel.Debug: - caption = "debug"; + caption = "debug: "; break; case LogLevel.Verbose: - caption = "trace"; + caption = "trace: "; break; case LogLevel.Information: - caption = "info "; + caption = HidePrefixForInfoAndMinimal ? null : "info : "; break; case LogLevel.Minimal: - caption = "log "; + caption = HidePrefixForInfoAndMinimal ? null : "log : "; break; case LogLevel.Warning: - caption = "warn "; + caption = "warn : "; break; case LogLevel.Error: - caption = "error"; + caption = "error: "; break; } } @@ -108,7 +113,7 @@ protected virtual void LogInternal(LogLevel logLevel, string message) } else { - Console.WriteLine($"{caption}: {message}"); + Console.WriteLine($"{caption}{message}"); } } @@ -122,7 +127,6 @@ private static string PrefixAllLines(string caption, string message) while ((line = reader.ReadLine()) != null) { builder.Append(caption); - builder.Append(": "); builder.AppendLine(line); } } diff --git a/src/NuGet.Core/NuGet.CommandLine.XPlat/Utility/XPlatUtility.cs b/src/NuGet.Core/NuGet.CommandLine.XPlat/Utility/XPlatUtility.cs index dbb8a4f475e..376a5c704fa 100644 --- a/src/NuGet.Core/NuGet.CommandLine.XPlat/Utility/XPlatUtility.cs +++ b/src/NuGet.Core/NuGet.CommandLine.XPlat/Utility/XPlatUtility.cs @@ -28,17 +28,6 @@ public static ISettings CreateDefaultSettings() machineWideSettings: new XPlatMachineWideSetting()); } - public static LogLevel GetLogLevel(CommandOption verbosity) - { - LogLevel level; - if (!Enum.TryParse(value: verbosity.Value(), ignoreCase: true, result: out level)) - { - level = LogLevel.Information; - } - - return level; - } - public static void ConfigureProtocol() { // Set connection limit diff --git a/src/NuGet.Core/NuGet.Commands/CommandArgs/VerbArgs.cs b/src/NuGet.Core/NuGet.Commands/CommandArgs/VerbArgs.cs new file mode 100644 index 00000000000..ab0ea891c5f --- /dev/null +++ b/src/NuGet.Core/NuGet.Commands/CommandArgs/VerbArgs.cs @@ -0,0 +1,60 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +// Do not manually edit this autogenerated file: +// instead modify the neighboring .tt file (text template) and/or NuGet.CommandLine.Xplat\Commands\Commands.xml (data file), +// then re-execute the text template via "run custom tool" on VS context menu for .tt file, or via dotnet-t4 global tool. + +using System; +using System.Threading.Tasks; +using NuGet.Common; + +namespace NuGet.Commands +{ + public partial class AddSourceArgs + { + public string Source { get; set; } + public string Name { get; set; } + public string Username { get; set; } + public string Password { get; set; } + public bool StorePasswordInClearText { get; set; } + public string ValidAuthenticationTypes { get; set; } + public string Configfile { get; set; } + } + + public partial class DisableSourceArgs + { + public string Name { get; set; } + public string Configfile { get; set; } + } + + public partial class EnableSourceArgs + { + public string Name { get; set; } + public string Configfile { get; set; } + } + + public partial class ListSourceArgs + { + public string Format { get; set; } + public string Configfile { get; set; } + } + + public partial class RemoveSourceArgs + { + public string Name { get; set; } + public string Configfile { get; set; } + } + + public partial class UpdateSourceArgs + { + public string Name { get; set; } + public string Source { get; set; } + public string Username { get; set; } + public string Password { get; set; } + public bool StorePasswordInClearText { get; set; } + public string ValidAuthenticationTypes { get; set; } + public string Configfile { get; set; } + } + +} diff --git a/src/NuGet.Core/NuGet.Commands/CommandArgs/VerbArgs.tt b/src/NuGet.Core/NuGet.Commands/CommandArgs/VerbArgs.tt new file mode 100644 index 00000000000..8bdefd810b4 --- /dev/null +++ b/src/NuGet.Core/NuGet.Commands/CommandArgs/VerbArgs.tt @@ -0,0 +1,120 @@ +<#@ template debug="false" hostspecific="true" language="C#" #> +<#@ assembly name="System.Xml.XDocument" #> +<#@ assembly name="System.Xml.Linq" #> +<#@ assembly name="System.Xml" #> +<#@ assembly name="System.Core" #> +<#@ import namespace="System.Xml.Linq" #> +<#@ import namespace="System.Linq" #> +<#@ output extension=".cs" #> +<# + string InitCaps(string input) + { + string output = input.Substring(0,1).ToUpper() + input.Substring(1); + return output; + } + + bool IsArgument(string type) + { + return type == "Argument"; + } + + string GetProperty(XElement element) + { + switch (element.Name.LocalName) + { + case "SingleValueOption": + return "Option"; + case "SwitchOption": + return "Option"; + case "Argument": + return "Argument"; + default: + return "Unknown Element Type" + element.Name.LocalName; + } + } + + string GetOptionType(XElement element) + { + switch (element.Name.LocalName) + { + case "SingleValueOption": + return "SingleValue"; + case "SwitchOption": + return "NoValue"; + case "Value": + return "Value"; + default: + return "Unknown Element Type" + element.Name.LocalName; + } + } + + var commandFile = this.Host.ResolvePath("..\\..\\NuGet.CommandLine.XPlat\\Commands\\Commands.xml"); + var commands = XDocument.Load(commandFile); +#> +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +// Do not manually edit this autogenerated file: +// instead modify the neighboring .tt file (text template) and/or NuGet.CommandLine.Xplat\Commands\Commands.xml (data file), +// then re-execute the text template via "run custom tool" on VS context menu for .tt file, or via dotnet-t4 global tool. + +using System; +using System.Threading.Tasks; +using NuGet.Common; + +namespace NuGet.Commands +{ +<# + // VerbNounArgs class + foreach (var verb in commands.Descendants(XName.Get("Verb",""))) + { + var verbName = verb.Attribute(XName.Get("Name", "")).Value; + var verbFormalName = InitCaps(verbName); + foreach (var noun in verb.Descendants(XName.Get("Noun"))) + { + var nounName = noun.Attribute(XName.Get("Name", ""))?.Value; + var nounFormalName = InitCaps(nounName); +#> + public partial class <#= verbFormalName #><#= nounFormalName #>Args + { +<# + foreach (var option in noun.Descendants()) + { + var optionName = option.Attribute(XName.Get("Name", "")).Value; + var optionType = option.Attribute(XName.Get("Type", ""))?.Value; + var optionFormalName = InitCaps(optionName.Replace("-","")); + if (IsArgument(GetProperty(option))) + { +#> + public string <#= optionFormalName #> { get; set; } +<# + } + else + { + switch (GetOptionType(option)) + { + case "SingleValue": +#> + public string <#= optionFormalName #> { get; set; } +<# + break; + case "NoValue": +#> + public bool <#= optionFormalName #> { get; set; } +<# + break; + case "Value": +#> + public <#= optionType #> <#= optionFormalName #> { get; set; } +<# + break; + } + } + } +#> + } + +<# + } + } +#>} diff --git a/src/NuGet.Core/NuGet.Commands/Common/CommandException.cs b/src/NuGet.Core/NuGet.Commands/Common/CommandException.cs new file mode 100644 index 00000000000..0b2ded3fcb1 --- /dev/null +++ b/src/NuGet.Core/NuGet.Commands/Common/CommandException.cs @@ -0,0 +1,37 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Globalization; +using System.Runtime.Serialization; + +namespace NuGet.Commands +{ + [Serializable] + public class CommandException : Exception + { + public CommandException() + { + } + + public CommandException(string message) + : base(message) + { + } + + public CommandException(string format, params object[] args) + : base(string.Format(CultureInfo.CurrentCulture, format, args)) + { + } + + public CommandException(string message, Exception exception) + : base(message, exception) + { + } + + protected CommandException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + } +} diff --git a/src/NuGet.Core/NuGet.Commands/NuGet.Commands.csproj b/src/NuGet.Core/NuGet.Commands/NuGet.Commands.csproj index 7ba4fe0eb09..56435222644 100644 --- a/src/NuGet.Core/NuGet.Commands/NuGet.Commands.csproj +++ b/src/NuGet.Core/NuGet.Commands/NuGet.Commands.csproj @@ -1,4 +1,4 @@ - + @@ -37,6 +37,11 @@ + + True + True + VerbArgs.tt + True True @@ -87,6 +92,17 @@ + + + VerbArgs.cs + TextTemplatingFileGenerator + + + + + + + diff --git a/src/NuGet.Core/NuGet.Commands/SourcesCommands/SourceRunners.cs b/src/NuGet.Core/NuGet.Commands/SourcesCommands/SourceRunners.cs new file mode 100644 index 00000000000..f85d464fc69 --- /dev/null +++ b/src/NuGet.Core/NuGet.Commands/SourcesCommands/SourceRunners.cs @@ -0,0 +1,342 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Globalization; +using System.IO; +using System.Linq; +using NuGet.Common; +using NuGet.Configuration; + +namespace NuGet.Commands +{ + public partial class AddSourceRunner + { + public static void Run(AddSourceArgs args, Func getLogger) + { + var settings = RunnerHelper.GetSettings(args.Configfile); + var sourceProvider = RunnerHelper.GetSourceProvider(settings); + + if (string.IsNullOrEmpty(args.Name)) + { + // find first unused name of pattern: prefixN, where N is an integer. + string defaultNamePrefix = Strings.Source_DefaultNamePrefix; + var namesSet = sourceProvider.GetPackageSourceNamesMatchingNamePrefix(defaultNamePrefix); + int i = 1; + while (true) + { + var defaultNameToUse = defaultNamePrefix + i.ToString(); + if (!namesSet.Contains(defaultNameToUse)) + { + args.Name = defaultNameToUse; + break; + } + i++; + } + } + else if (string.Equals(args.Name, Strings.ReservedPackageNameAll)) + { + throw new CommandException(Strings.SourcesCommandAllNameIsReserved); + } + + // Make sure that the Source given is a valid one. + if (!PathValidator.IsValidSource(args.Source)) + { + throw new CommandException(Strings.SourcesCommandInvalidSource); + } + + RunnerHelper.ValidateCredentials(args.Username, args.Password, args.ValidAuthenticationTypes); + + // Check to see if we already have a registered source with the same name or source + var existingSourceWithName = sourceProvider.GetPackageSourceByName(args.Name); + if (existingSourceWithName != null) + { + throw new CommandException(Strings.SourcesCommandUniqueName); + } + + var existingSourceWithSource = sourceProvider.GetPackageSourceBySource(args.Source); + if (existingSourceWithSource != null) + { + throw new CommandException(Strings.SourcesCommandUniqueSource); + } + + var newPackageSource = new Configuration.PackageSource(args.Source, args.Name); + + if (!string.IsNullOrEmpty(args.Username)) + { + var credentials = Configuration.PackageSourceCredential.FromUserInput( + args.Name, + args.Username, + args.Password, + args.StorePasswordInClearText, + args.ValidAuthenticationTypes); + newPackageSource.Credentials = credentials; + } + + sourceProvider.AddPackageSource(newPackageSource); + getLogger().LogMinimal(string.Format(CultureInfo.CurrentCulture, + Strings.SourcesCommandSourceAddedSuccessfully, args.Name)); + } + } + + public partial class DisableSourceRunner + { + public static void Run(DisableSourceArgs args, Func getLogger) + { + var settings = RunnerHelper.GetSettings(args.Configfile); + var sourceProvider = RunnerHelper.GetSourceProvider(settings); + RunnerHelper.EnableOrDisableSource(sourceProvider, args.Name, enabled: false, getLogger); + } + } + + public partial class EnableSourceRunner + { + public static void Run(EnableSourceArgs args, Func getLogger) + { + var settings = RunnerHelper.GetSettings(args.Configfile); + var sourceProvider = RunnerHelper.GetSourceProvider(settings); + RunnerHelper.EnableOrDisableSource(sourceProvider, args.Name, enabled: true, getLogger); + } + } + + public partial class ListSourceRunner + { + public static void Run(ListSourceArgs args, Func getLogger) + { + SourcesListFormat format; + if (string.IsNullOrEmpty(args.Format)) + { + format = SourcesListFormat.Detailed; + } + else + { + Enum.TryParse(args.Format, ignoreCase: true, out format); + } + + switch (format) + { + case SourcesListFormat.Detailed: + { + var settings = RunnerHelper.GetSettings(args.Configfile); + var sourceProvider = RunnerHelper.GetSourceProvider(settings); + + var sourcesList = sourceProvider.LoadPackageSources().ToList(); + if (!sourcesList.Any()) + { + getLogger().LogMinimal(string.Format(CultureInfo.CurrentCulture, + Strings.SourcesCommandNoSources)); + + return; + } + + getLogger().LogMinimal(string.Format(CultureInfo.CurrentCulture, Strings.SourcesCommandRegisteredSources)); + var sourcePadding = new string(' ', 6); + for (var i = 0; i < sourcesList.Count; i++) + { + var source = sourcesList[i]; + var indexNumber = i + 1; + var namePadding = new string(' ', i >= 9 ? 1 : 2); + + getLogger().LogMinimal(string.Format( + " {0}.{1}{2} [{3}]", + indexNumber, + namePadding, + source.Name, + source.IsEnabled ? string.Format(CultureInfo.CurrentCulture, Strings.SourcesCommandEnabled) : string.Format(CultureInfo.CurrentCulture, Strings.SourcesCommandDisabled))); + getLogger().LogMinimal(string.Format("{0}{1}", sourcePadding, source.Source)); + } + } + break; + case SourcesListFormat.Short: + { + var settings = RunnerHelper.GetSettings(args.Configfile); + var sourceProvider = RunnerHelper.GetSourceProvider(settings); + + var sourcesList = sourceProvider.LoadPackageSources(); + + foreach (var source in sourcesList) + { + string legend = source.IsEnabled ? "E" : "D"; + + if (source.IsMachineWide) + { + legend += "M"; + } + if (source.IsOfficial) + { + legend += "O"; + } + legend += " "; + getLogger().LogMinimal(legend + source.Source); + } + } + break; + case SourcesListFormat.None: + // This validation could move to the Command or Args and be code-generated. + throw new CommandException(string.Format(Strings.Source_InvalidFormatValue, args.Format)); + } + } + } + + public partial class RemoveSourceRunner + { + public static void Run(RemoveSourceArgs args, Func getLogger) + { + var settings = RunnerHelper.GetSettings(args.Configfile); + var sourceProvider = RunnerHelper.GetSourceProvider(settings); + + // Check to see if we already have a registered source with the same name or source + var source = sourceProvider.GetPackageSourceByName(args.Name); + if (source == null) + { + throw new CommandException(Strings.SourcesCommandNoMatchingSourcesFound, args.Name); + } + + sourceProvider.RemovePackageSource(args.Name); + getLogger().LogMinimal(string.Format(CultureInfo.CurrentCulture, + Strings.SourcesCommandSourceRemovedSuccessfully, args.Name)); + } + } + + public partial class UpdateSourceRunner + { + public static void Run(UpdateSourceArgs args, Func getLogger) + { + var settings = RunnerHelper.GetSettings(args.Configfile); + var sourceProvider = RunnerHelper.GetSourceProvider(settings); + + var existingSource = sourceProvider.GetPackageSourceByName(args.Name); + if (existingSource == null) + { + throw new CommandException(Strings.SourcesCommandNoMatchingSourcesFound, args.Name); + } + + if (!string.IsNullOrEmpty(args.Source) && !existingSource.Source.Equals(args.Source, StringComparison.OrdinalIgnoreCase)) + { + if (!PathValidator.IsValidSource(args.Source)) + { + throw new CommandException(Strings.SourcesCommandInvalidSource); + } + + // If the user is updating the source, verify we don't have a duplicate. + var duplicateSource = sourceProvider.GetPackageSourceBySource(args.Source); + if (duplicateSource != null) + { + throw new CommandException(Strings.SourcesCommandUniqueSource); + } + + existingSource = new Configuration.PackageSource(args.Source, existingSource.Name); + } + + RunnerHelper.ValidateCredentials(args.Username, args.Password, args.ValidAuthenticationTypes); + + if (!string.IsNullOrEmpty(args.Username)) + { + var hasExistingAuthTypes = existingSource.Credentials?.ValidAuthenticationTypes.Any() ?? false; + if (hasExistingAuthTypes && string.IsNullOrEmpty(args.ValidAuthenticationTypes)) + { + getLogger().LogMinimal(string.Format(CultureInfo.CurrentCulture, + Strings.SourcesCommandClearingExistingAuthTypes, args.Name)); + } + + var credentials = Configuration.PackageSourceCredential.FromUserInput( + args.Name, + args.Username, + args.Password, + args.StorePasswordInClearText, + args.ValidAuthenticationTypes); + existingSource.Credentials = credentials; + } + + sourceProvider.UpdatePackageSource(existingSource, updateCredentials: existingSource.Credentials != null, updateEnabled: false); + + getLogger().LogMinimal(string.Format(CultureInfo.CurrentCulture, + Strings.SourcesCommandUpdateSuccessful, args.Name)); + } + } + + internal static class RunnerHelper + { + public static ISettings GetSettings(string configfile) + { + string currentDirectory = Directory.GetCurrentDirectory(); + if (string.IsNullOrEmpty(configfile)) + { + // Use settings based on probing given currentDirectory + return NuGet.Configuration.Settings.LoadDefaultSettings(currentDirectory, + configFileName: null, + machineWideSettings: new XPlatMachineWideSetting()); + } + else + { + // Use ConfigFile only + var configFileFullPath = Path.GetFullPath(configfile); + var configDirectory = Path.GetDirectoryName(configFileFullPath); + var configFileName = Path.GetFileName(configFileFullPath); + + return NuGet.Configuration.Settings.LoadSpecificSettings(configDirectory, + configFileName: configFileName); + } + } + + public static PackageSourceProvider GetSourceProvider(ISettings settings) + { +#pragma warning disable CS0618 // Type or member is obsolete + var sourceProvider = new PackageSourceProvider(settings, enablePackageSourcesChangedEvent: false); +#pragma warning restore CS0618 // Type or member is obsolete + return sourceProvider; + } + + public static void EnableOrDisableSource(PackageSourceProvider sourceProvider, string name, bool enabled, Func getLogger) + { + var packageSource = sourceProvider.GetPackageSourceByName(name); + if (packageSource == null) + { + throw new CommandException(Strings.SourcesCommandNoMatchingSourcesFound, name); + } + + // Use casing consistent with existing source. + name = packageSource.Name; + + if (enabled && !packageSource.IsEnabled) + { + sourceProvider.EnablePackageSource(name); + } + else if (!enabled && packageSource.IsEnabled) + { + sourceProvider.DisablePackageSource(name); + } + + if (enabled) + { + getLogger().LogMinimal(string.Format(CultureInfo.CurrentCulture, + Strings.SourcesCommandSourceEnabledSuccessfully, name)); + } + else + { + getLogger().LogMinimal(string.Format(CultureInfo.CurrentCulture, + Strings.SourcesCommandSourceDisabledSuccessfully, name)); + } + } + + public static void ValidateCredentials(string username, string password, string validAuthenticationTypes) + { + var isUsernameEmpty = string.IsNullOrEmpty(username); + var isPasswordEmpty = string.IsNullOrEmpty(password); + var isAuthTypesEmpty = string.IsNullOrEmpty(validAuthenticationTypes); + + if (isUsernameEmpty ^ isPasswordEmpty) + { + // If only one of them is set, throw. + throw new CommandException(Strings.SourcesCommandCredentialsRequired); + } + + if (isPasswordEmpty && !isAuthTypesEmpty) + { + // can't specify auth types without credentials + throw new CommandException(Strings.SourcesCommandCredentialsRequiredWithAuthTypes); + } + } + } + +} diff --git a/src/NuGet.Core/NuGet.Commands/SourcesCommands/SourcesAction.cs b/src/NuGet.Core/NuGet.Commands/SourcesCommands/SourcesAction.cs new file mode 100644 index 00000000000..47653f667ae --- /dev/null +++ b/src/NuGet.Core/NuGet.Commands/SourcesCommands/SourcesAction.cs @@ -0,0 +1,16 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +namespace NuGet.Commands +{ + public enum SourcesAction + { + None = 0, + List, + Add, + Remove, + Enable, + Disable, + Update, + } +} diff --git a/src/NuGet.Core/NuGet.Commands/SourcesCommands/SourcesListFormat.cs b/src/NuGet.Core/NuGet.Commands/SourcesCommands/SourcesListFormat.cs new file mode 100644 index 00000000000..8dc60b6c47c --- /dev/null +++ b/src/NuGet.Core/NuGet.Commands/SourcesCommands/SourcesListFormat.cs @@ -0,0 +1,12 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +namespace NuGet.Commands +{ + public enum SourcesListFormat + { + None = 0, + Detailed, + Short + } +} diff --git a/src/NuGet.Core/NuGet.Commands/Strings.Designer.cs b/src/NuGet.Core/NuGet.Commands/Strings.Designer.cs index c73d7c998d1..72f908775f7 100644 --- a/src/NuGet.Core/NuGet.Commands/Strings.Designer.cs +++ b/src/NuGet.Core/NuGet.Commands/Strings.Designer.cs @@ -519,6 +519,15 @@ internal static string Error_ServiceIndexShouldBeHttps { } } + /// + /// Looks up a localized string similar to Property SourceProvider is null.. + /// + internal static string Error_SourceProviderIsNull { + get { + return ResourceManager.GetString("Error_SourceProviderIsNull", resourceCulture); + } + } + /// /// Looks up a localized string similar to Invalid tools package {0} {1}. Tools packages cannot contain more than one PackageType.. /// @@ -1609,6 +1618,15 @@ internal static string RegsiteredTrustedSigners { } } + /// + /// Looks up a localized string similar to All. + /// + internal static string ReservedPackageNameAll { + get { + return ResourceManager.GetString("ReservedPackageNameAll", resourceCulture); + } + } + /// /// Looks up a localized string similar to {0} (via {1}). /// @@ -1735,6 +1753,195 @@ internal static string SignCommandSuccess { } } + /// + /// Looks up a localized string similar to Package source {0}. + /// + internal static string Source_DefaultNamePrefix { + get { + return ResourceManager.GetString("Source_DefaultNamePrefix", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to invalid value for --format: {0}. Allowed values: 'detailed' or 'short'. + /// + internal static string Source_InvalidFormatValue { + get { + return ResourceManager.GetString("Source_InvalidFormatValue", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Package source name 'All' is a reserved name.. + /// + internal static string SourcesCommandAllNameIsReserved { + get { + return ResourceManager.GetString("SourcesCommandAllNameIsReserved", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Clearing existing authentication types settings for package source '{0}'.. + /// + internal static string SourcesCommandClearingExistingAuthTypes { + get { + return ResourceManager.GetString("SourcesCommandClearingExistingAuthTypes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Both UserName and Password must be specified.. + /// + internal static string SourcesCommandCredentialsRequired { + get { + return ResourceManager.GetString("SourcesCommandCredentialsRequired", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Both UserName and Password must be specified if ValidAuthenticationTypes is specified.. + /// + internal static string SourcesCommandCredentialsRequiredWithAuthTypes { + get { + return ResourceManager.GetString("SourcesCommandCredentialsRequiredWithAuthTypes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disabled. + /// + internal static string SourcesCommandDisabled { + get { + return ResourceManager.GetString("SourcesCommandDisabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Enabled. + /// + internal static string SourcesCommandEnabled { + get { + return ResourceManager.GetString("SourcesCommandEnabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The source specified is invalid. Please provide a valid source.. + /// + internal static string SourcesCommandInvalidSource { + get { + return ResourceManager.GetString("SourcesCommandInvalidSource", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The name specified cannot be empty. Please provide a valid name.. + /// + internal static string SourcesCommandNameRequired { + get { + return ResourceManager.GetString("SourcesCommandNameRequired", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unable to find any package source(s) matching name: {0}.. + /// + internal static string SourcesCommandNoMatchingSourcesFound { + get { + return ResourceManager.GetString("SourcesCommandNoMatchingSourcesFound", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No sources found.. + /// + internal static string SourcesCommandNoSources { + get { + return ResourceManager.GetString("SourcesCommandNoSources", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Registered Sources:. + /// + internal static string SourcesCommandRegisteredSources { + get { + return ResourceManager.GetString("SourcesCommandRegisteredSources", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Package source with Name: {0} added successfully.. + /// + internal static string SourcesCommandSourceAddedSuccessfully { + get { + return ResourceManager.GetString("SourcesCommandSourceAddedSuccessfully", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Package source with Name: {0} disabled successfully.. + /// + internal static string SourcesCommandSourceDisabledSuccessfully { + get { + return ResourceManager.GetString("SourcesCommandSourceDisabledSuccessfully", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Package source with Name: {0} enabled successfully.. + /// + internal static string SourcesCommandSourceEnabledSuccessfully { + get { + return ResourceManager.GetString("SourcesCommandSourceEnabledSuccessfully", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Package source with Name: {0} removed successfully.. + /// + internal static string SourcesCommandSourceRemovedSuccessfully { + get { + return ResourceManager.GetString("SourcesCommandSourceRemovedSuccessfully", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The source specified cannot be empty. Please provide a valid source.. + /// + internal static string SourcesCommandSourceRequired { + get { + return ResourceManager.GetString("SourcesCommandSourceRequired", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The name specified has already been added to the list of available package sources. Please provide a unique name.. + /// + internal static string SourcesCommandUniqueName { + get { + return ResourceManager.GetString("SourcesCommandUniqueName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The source specified has already been added to the list of available package sources. Please provide a unique source.. + /// + internal static string SourcesCommandUniqueSource { + get { + return ResourceManager.GetString("SourcesCommandUniqueSource", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Package source "{0}" was successfully updated.. + /// + internal static string SourcesCommandUpdateSuccessful { + get { + return ResourceManager.GetString("SourcesCommandUpdateSuccessful", resourceCulture); + } + } + /// /// Looks up a localized string similar to Duplicate frameworks found: '{0}'.. /// diff --git a/src/NuGet.Core/NuGet.Commands/Strings.resx b/src/NuGet.Core/NuGet.Commands/Strings.resx index fc84721997e..ec2f550ebe1 100644 --- a/src/NuGet.Core/NuGet.Commands/Strings.resx +++ b/src/NuGet.Core/NuGet.Commands/Strings.resx @@ -279,7 +279,7 @@ Added file '{0}'. - The specified source '{0}' is invalid. Please provide a valid source. + The specified source '{0}' is invalid. Provide a valid source. Description: {0} @@ -390,7 +390,7 @@ One or more projects are incompatible with {0}. - Please specify a nuspec, project.json, or project file to use + Specify a nuspec, project.json, or project file to use Failed to build using '{0} {1}'. @@ -432,7 +432,7 @@ {0} : Path to be deleted - An invalid local resource name was provided. Please provide one of the following values: http-cache, temp, global-packages, all. + An invalid local resource name was provided. Provide one of the following values: http-cache, temp, global-packages, all. The location of local resource '{0}' is undefined. @@ -564,7 +564,7 @@ For more information, visit https://docs.nuget.org/docs/reference/command-line-r Unable to find project '{0}'. Check that the project reference is valid and that the project file exists. - Unable to find project information for '{0}'. If you are using Visual Studio, this may be because the project is unloaded or not part of the current solution so please run a restore from the command-line. Otherwise, the project file may be invalid or missing targets required for restore. + Unable to find project information for '{0}'. If you are using Visual Studio, this may be because the project is unloaded or not part of the current solution so run a restore from the command-line. Otherwise, the project file may be invalid or missing targets required for restore. Found {0} version(s) in {1} [ Nearest version: {2} ] @@ -603,7 +603,7 @@ For more information, visit https://docs.nuget.org/docs/reference/command-line-r Signing package(s) with certificate: - Please select a valid certificate + Select a valid certificate NuGet Sign Certificate Selection @@ -613,21 +613,21 @@ For more information, visit https://docs.nuget.org/docs/reference/command-line-r 0 - CertificateFingerprint option - No certificates were found that meet all the given criteria. For a list of accepted ways to provide a certificate, please visit https://docs.nuget.org/docs/reference/command-line-reference + No certificates were found that meet all the given criteria. For a list of accepted ways to provide a certificate, visit https://docs.nuget.org/docs/reference/command-line-reference Package(s) signed successfully. - Certificate file '{0}' not found. For a list of accepted ways to provide a certificate, please visit https://docs.nuget.org/docs/reference/command-line-reference + Certificate file '{0}' not found. For a list of accepted ways to provide a certificate, visit https://docs.nuget.org/docs/reference/command-line-reference {0} is the certificate file path - Certificate file '{0}' is invalid. For a list of accepted ways to provide a certificate, please visit https://docs.nuget.org/docs/reference/command-line-reference + Certificate file '{0}' is invalid. For a list of accepted ways to provide a certificate, visit https://docs.nuget.org/docs/reference/command-line-reference 0 - certificate file path - Invalid password was provided for the certificate file '{0}'. Please provide a valid password using the '-{1}' option + Invalid password was provided for the certificate file '{0}'. Provide a valid password using the '-{1}' option 0 - certificate file path 1 - certificate password option @@ -645,7 +645,7 @@ For more information, visit https://docs.nuget.org/docs/reference/command-line-r '{0}' is not a valid package file. - Verification type not supported. Please use only one of the following supported types: -All, -Signatures + Verification type not supported. Use only one of the following supported types: -All, -Signatures Signed package(s) output path: @@ -669,7 +669,7 @@ For more information, visit https://docs.nuget.org/docs/reference/command-line-r Package signature validation failed. - Certificate store '{0}' not found. For a list of accepted ways to provide a certificate, please visit https://docs.nuget.org/docs/reference/command-line-reference + Certificate store '{0}' not found. For a list of accepted ways to provide a certificate, visit https://docs.nuget.org/docs/reference/command-line-reference {0} is the certificate store name @@ -726,7 +726,7 @@ For more information, visit https://docs.nuget.org/docs/reference/command-line-r Invalid combination of arguments. - No signature to be trusted was specified for the package '{0}'. Please specify either Author or Repository. + No signature to be trusted was specified for the package '{0}'. Specify either Author or Repository. 0 - Package path @@ -896,4 +896,75 @@ For more information, visit https://docs.nuget.org/docs/reference/command-line-r Package content hash validation failed for {0}. Expected: {1} Actual: {2} 0 - package ID, 1 - expected Sha, 2 - actual sha + + Property SourceProvider is null. + + + The name specified cannot be empty. Provide a valid name. + + + Unable to find any package source(s) matching name: {0}. + + + Package source with Name: {0} disabled successfully. + + + Package source with Name: {0} enabled successfully. + + + Package source with Name: {0} removed successfully. + + + All + + + Package source name 'All' is a reserved name. + + + The source specified cannot be empty. Provide a valid source. + + + The source specified is invalid. Provide a valid source. + + + The name specified has already been added to the list of available package sources. Provide a unique name. + + + The source specified has already been added to the list of available package sources. Provide a unique source. + + + Package source with Name: {0} added successfully. + + + Clearing existing authentication types settings for package source '{0}'. + + + Package source "{0}" was successfully updated. + + + Both UserName and Password must be specified. + + + Both UserName and Password must be specified if ValidAuthenticationTypes is specified. + + + No sources found. + + + Registered Sources: + + + Disabled + + + Enabled + + + Package source {0} + {0} will be a number + + + invalid value for --format: {0}. Allowed values: 'detailed' or 'short' + don't localize 'format', 'detailed' or 'short' + \ No newline at end of file diff --git a/src/NuGet.Core/NuGet.Configuration/PackageSource/PackageSourceProvider.cs b/src/NuGet.Core/NuGet.Configuration/PackageSource/PackageSourceProvider.cs index 6b85d2a3784..1d9a85656ab 100644 --- a/src/NuGet.Core/NuGet.Configuration/PackageSource/PackageSourceProvider.cs +++ b/src/NuGet.Core/NuGet.Configuration/PackageSource/PackageSourceProvider.cs @@ -316,6 +316,22 @@ public PackageSource GetPackageSourceByName(string name) return GetPackageSource(name, LoadPackageSourceLookupByName(Settings)); } + public HashSet GetPackageSourceNamesMatchingNamePrefix(string namePrefix) + { + var names = new HashSet(); + + IEnumerable packageSources = LoadPackageSources(); + foreach (PackageSource packageSource in packageSources) + { + if (packageSource.Name.StartsWith(namePrefix)) + { + names.Add(packageSource.Name); + } + } + + return names; + } + public PackageSource GetPackageSourceBySource(string source) { if (string.IsNullOrEmpty(source)) diff --git a/test/NuGet.Clients.FuncTests/NuGet.CommandLine.FuncTest/NuGet.CommandLine.FuncTest.csproj b/test/NuGet.Clients.FuncTests/NuGet.CommandLine.FuncTest/NuGet.CommandLine.FuncTest.csproj index 68de5c5903d..c3942a7e6db 100644 --- a/test/NuGet.Clients.FuncTests/NuGet.CommandLine.FuncTest/NuGet.CommandLine.FuncTest.csproj +++ b/test/NuGet.Clients.FuncTests/NuGet.CommandLine.FuncTest/NuGet.CommandLine.FuncTest.csproj @@ -25,11 +25,10 @@ - - - xcopy /diy $(ArtifactsDirectory)$(VsixOutputDirName)\NuGet.exe $(OutputPath)NuGet\ - - + + + diff --git a/test/NuGet.Clients.FuncTests/NuGet.MSSigning.Extensions.FuncTest/NuGet.MSSigning.Extensions.FuncTest.csproj b/test/NuGet.Clients.FuncTests/NuGet.MSSigning.Extensions.FuncTest/NuGet.MSSigning.Extensions.FuncTest.csproj index 87265b6c52e..13e6f555250 100644 --- a/test/NuGet.Clients.FuncTests/NuGet.MSSigning.Extensions.FuncTest/NuGet.MSSigning.Extensions.FuncTest.csproj +++ b/test/NuGet.Clients.FuncTests/NuGet.MSSigning.Extensions.FuncTest/NuGet.MSSigning.Extensions.FuncTest.csproj @@ -17,11 +17,10 @@ - - - xcopy /diy $(ArtifactsDirectory)$(VsixOutputDirName)\NuGet.exe $(OutputPath)NuGet\ - - + + + diff --git a/test/NuGet.Clients.Tests/NuGet.CommandLine.Test/Common/SelfUpdaterTests.cs b/test/NuGet.Clients.Tests/NuGet.CommandLine.Test/Common/SelfUpdaterTests.cs index 33ad95f35f8..11787099af1 100644 --- a/test/NuGet.Clients.Tests/NuGet.CommandLine.Test/Common/SelfUpdaterTests.cs +++ b/test/NuGet.Clients.Tests/NuGet.CommandLine.Test/Common/SelfUpdaterTests.cs @@ -5,6 +5,7 @@ using System.Threading; using System.Threading.Tasks; using Moq; +using NuGet.Commands; using NuGet.Test.Utility; using NuGet.Versioning; using Xunit; @@ -59,7 +60,7 @@ await SimpleTestPackageUtility.CreatePackagesAsync( new SimpleTestPackageContext("NuGet.CommandLine", "6.0.0")); // Act & Assert - await Assert.ThrowsAsync(() => + await Assert.ThrowsAsync(() => tc.Target.UpdateSelfFromVersionAsync( tc.Target.AssemblyLocation, prerelease: false, diff --git a/test/NuGet.Clients.Tests/NuGet.CommandLine.Test/MSBuildUtilityTest.cs b/test/NuGet.Clients.Tests/NuGet.CommandLine.Test/MSBuildUtilityTest.cs index 84c7954c513..852da3b4461 100644 --- a/test/NuGet.Clients.Tests/NuGet.CommandLine.Test/MSBuildUtilityTest.cs +++ b/test/NuGet.Clients.Tests/NuGet.CommandLine.Test/MSBuildUtilityTest.cs @@ -1,14 +1,16 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + using System; +using System.Collections.Generic; using System.IO; using System.Linq; -using System.Collections.Generic; +using System.Text; +using Moq; +using NuGet.Commands; using NuGet.Common; using NuGet.Test.Utility; using Xunit; -using System.Text; -using System.Security.Permissions; -using System.Security; -using Moq; namespace NuGet.CommandLine.Test { @@ -112,7 +114,7 @@ public void TestVersionMatchByStringFailure(List toolsets, strin // Arrange // Act - var ex = Assert.Throws(() => + var ex = Assert.Throws(() => { var directory = MsBuildUtility.GetMsBuildDirectoryInternal( userVersion: userVersion, diff --git a/test/NuGet.Clients.Tests/NuGet.CommandLine.Test/NuGet.CommandLine.Test.csproj b/test/NuGet.Clients.Tests/NuGet.CommandLine.Test/NuGet.CommandLine.Test.csproj index 37f71dcde7e..8361aa6c6a0 100644 --- a/test/NuGet.Clients.Tests/NuGet.CommandLine.Test/NuGet.CommandLine.Test.csproj +++ b/test/NuGet.Clients.Tests/NuGet.CommandLine.Test/NuGet.CommandLine.Test.csproj @@ -3,8 +3,8 @@ - $(NETFXTargetFramework) - + $(NETFXTargetFramework) + true @@ -56,10 +56,15 @@ xcopy /diy $(ArtifactsDirectory)TestableCredentialProvider\$(BuildVariationFolder)\bin\$(Configuration)\$(TargetFramework)\CredentialProvider.Testable.exe $(OutputPath)TestableCredentialProvider\ xcopy /diy $(ArtifactsDirectory)TestableCredentialProvider\$(BuildVariationFolder)\bin\$(Configuration)\$(TargetFramework)\*.dll $(OutputPath)TestableCredentialProvider\ xcopy /diy $(ArtifactsDirectory)SampleCommandLineExtensions\$(BuildVariationFolder)\bin\$(Configuration)\$(TargetFramework)\SampleCommandLineExtensions.dll $(OutputPath)NuGet\ - xcopy /diy $(ArtifactsDirectory)$(VsixOutputDirName)\NuGet.exe $(OutputPath)NuGet\ + if exist $(ArtifactsDirectory)$(VsixOutputDirName)\NuGet.exe xcopy /diy $(ArtifactsDirectory)$(VsixOutputDirName)\NuGet.exe $(OutputPath)NuGet\ + + + + \ No newline at end of file diff --git a/test/NuGet.Clients.Tests/NuGet.CommandLine.Test/NuGetLocalsCommandTest.cs b/test/NuGet.Clients.Tests/NuGet.CommandLine.Test/NuGetLocalsCommandTest.cs index 31e0da1f260..e62e4d5531c 100644 --- a/test/NuGet.Clients.Tests/NuGet.CommandLine.Test/NuGetLocalsCommandTest.cs +++ b/test/NuGet.Clients.Tests/NuGet.CommandLine.Test/NuGetLocalsCommandTest.cs @@ -54,7 +54,7 @@ public void LocalsCommand_Success_InvalidLocalResourceName_HelpMessage(string ar waitForExit: true); // Assert - Util.VerifyResultFailure(result, "An invalid local resource name was provided. Please provide one of the following values: http-cache, temp, global-packages, all."); + Util.VerifyResultFailure(result, "An invalid local resource name was provided. Provide one of the following values: http-cache, temp, global-packages, all."); } [Theory] diff --git a/test/NuGet.Clients.Tests/NuGet.CommandLine.Test/NuGetPushCommandTest.cs b/test/NuGet.Clients.Tests/NuGet.CommandLine.Test/NuGetPushCommandTest.cs index 09e58356398..0df2440201c 100644 --- a/test/NuGet.Clients.Tests/NuGet.CommandLine.Test/NuGetPushCommandTest.cs +++ b/test/NuGet.Clients.Tests/NuGet.CommandLine.Test/NuGetPushCommandTest.cs @@ -1864,7 +1864,7 @@ public void PushCommand_InvalidInput_NonSource(string invalidInput) Assert.True( result.Item3.Contains( string.Format( - "The specified source '{0}' is invalid. Please provide a valid source.", + "The specified source '{0}' is invalid. Provide a valid source.", invalidInput)), "Expected error message not found in " + result.Item3 ); diff --git a/test/NuGet.Clients.Tests/NuGet.CommandLine.Test/NuGetSourcesCommandTest.cs b/test/NuGet.Clients.Tests/NuGet.CommandLine.Test/NuGetSourcesCommandTest.cs index 812a4ecd210..187a8aabd61 100644 --- a/test/NuGet.Clients.Tests/NuGet.CommandLine.Test/NuGetSourcesCommandTest.cs +++ b/test/NuGet.Clients.Tests/NuGet.CommandLine.Test/NuGetSourcesCommandTest.cs @@ -2,17 +2,11 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using System.Collections.Generic; using System.IO; using System.Linq; -using System.Text; -using System.Threading.Tasks; +using NuGet.Configuration; using NuGet.Test.Utility; -using Test.Utility; using Xunit; -using Xunit.Extensions; -using NuGet.Common; -using NuGet.Configuration; namespace NuGet.CommandLine.Test { @@ -143,7 +137,7 @@ public void SourcesCommandTest_AddWithUserNamePasswordInClearText() } } - [Fact(Skip = "This scenario does not work as desired. Created a github issue")] + [Fact] public void SourcesCommandTest_AddWithUserNamePassword_UserDefinedConfigFile() { // Arrange @@ -154,8 +148,7 @@ public void SourcesCommandTest_AddWithUserNamePassword_UserDefinedConfigFile() var configFilePath = Path.Combine(configFileDirectory, configFileName); Util.CreateFile(configFileDirectory, configFileName, - @" - + @" "); diff --git a/test/NuGet.Core.FuncTests/Dotnet.Integration.Test/DotnetSourcesTests.cs b/test/NuGet.Core.FuncTests/Dotnet.Integration.Test/DotnetSourcesTests.cs new file mode 100644 index 00000000000..2e11e29b223 --- /dev/null +++ b/test/NuGet.Core.FuncTests/Dotnet.Integration.Test/DotnetSourcesTests.cs @@ -0,0 +1,467 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.IO; +using System.Linq; +using System.Xml.Linq; +using NuGet.Configuration; +using NuGet.Test.Utility; +using Xunit; + +namespace Dotnet.Integration.Test +{ + [Collection("Dotnet Integration Tests")] + public class DotnetSourcesTests + { + private readonly MsbuildIntegrationTestFixture _fixture; + + public DotnetSourcesTests(MsbuildIntegrationTestFixture fixture) + { + _fixture = fixture; + } + + [PlatformFact(Platform.Windows)] + public void SourcesCommandTest_AddSource() + { + using (var preserver = new NuGet.CommandLine.Test.DefaultConfigurationFilePreserver()) + { + // Arrange + var args = new string[] { + "nuget", + "add", + "source", + "http://test_source", + "--name", + "test_source", + }; + var root = Directory.GetDirectoryRoot(Directory.GetCurrentDirectory()); + + // Act + // Set the working directory to C:\, otherwise, + // the test will change the nuget.config at the code repo's root directory + // And, will fail since global nuget.config is updated + var result = _fixture.RunDotnet(root, string.Join(" ", args), ignoreExitCode: true); + + // Assert + Assert.True(result.ExitCode == 0); + var settings = Settings.LoadDefaultSettings(null, null, null); + var packageSourcesSection = settings.GetSection("packageSources"); + var sourceItem = packageSourcesSection?.GetFirstItemWithAttribute("key", "test_source"); + Assert.Equal("http://test_source", sourceItem.GetValueAsPath()); + } + } + + [PlatformFact(Platform.Windows)] + public void SourcesCommandTest_AddWithUserNamePassword() + { + using (var preserver = new NuGet.CommandLine.Test.DefaultConfigurationFilePreserver()) + { + // Arrange + var args = new string[] { + "nuget", + "add", + "source", + "http://test_source", + "--name", + "test_source", + "--username", + "test_user_name", + "--password", + "test_password" + }; + var root = Directory.GetDirectoryRoot(Directory.GetCurrentDirectory()); + + // Act + // Set the working directory to C:\, otherwise, + // the test will change the nuget.config at the code repo's root directory + // And, will fail since global nuget.config is updated + var result = _fixture.RunDotnet(root, string.Join(" ", args), ignoreExitCode: true); + + + // Assert + Assert.True(0 == result.Item1, result.Item2 + " " + result.Item3); + + var settings = Settings.LoadDefaultSettings(null, null, null); + + var packageSourcesSection = settings.GetSection("packageSources"); + var sourceItem = packageSourcesSection?.GetFirstItemWithAttribute("key", "test_source"); + Assert.Equal("http://test_source", sourceItem.GetValueAsPath()); + + var sourceCredentialsSection = settings.GetSection("packageSourceCredentials"); + var credentialItem = sourceCredentialsSection?.Items.First(c => string.Equals(c.ElementName, "test_source", StringComparison.OrdinalIgnoreCase)) as CredentialsItem; + Assert.NotNull(credentialItem); + + Assert.Equal("test_user_name", credentialItem.Username); + + var password = EncryptionUtility.DecryptString(credentialItem.Password); + Assert.Equal("test_password", password); + } + } + + [PlatformFact(Platform.Windows)] + public void SourcesCommandTest_AddWithUserNamePasswordInClearText() + { + using (var preserver = new NuGet.CommandLine.Test.DefaultConfigurationFilePreserver()) + { + // Arrange + var args = new string[] { + "nuget", + "add", + "source", + "http://test_source", + "--name", + "test_source", + "--username", + "test_user_name", + "--password", + "test_password", + "--store-password-in-clear-text" + }; + var root = Directory.GetDirectoryRoot(Directory.GetCurrentDirectory()); + + // Act + // Set the working directory to C:\, otherwise, + // the test will change the nuget.config at the code repo's root directory + // And, will fail since global nuget.config is updated + var result = _fixture.RunDotnet(root, string.Join(" ", args), ignoreExitCode: true); + + // Assert + Assert.True(0 == result.Item1, result.Item2 + " " + result.Item3); + + var settings = Settings.LoadDefaultSettings(null, null, null); + + var packageSourcesSection = settings.GetSection("packageSources"); + var sourceItem = packageSourcesSection?.GetFirstItemWithAttribute("key", "test_source"); + Assert.Equal("http://test_source", sourceItem.GetValueAsPath()); + + var sourceCredentialsSection = settings.GetSection("packageSourceCredentials"); + var credentialItem = sourceCredentialsSection?.Items.First(c => string.Equals(c.ElementName, "test_source", StringComparison.OrdinalIgnoreCase)) as CredentialsItem; + Assert.NotNull(credentialItem); + + Assert.Equal("test_user_name", credentialItem.Username); + Assert.Equal("test_password", credentialItem.Password); + } + } + + [PlatformFact(Platform.Windows)] + public void SourcesCommandTest_AddWithUserNamePassword_UserDefinedConfigFile() + { + // Arrange + using (var configFileDirectory = TestDirectory.Create()) + { + var configFileName = "nuget.config"; + var configFilePath = Path.Combine(configFileDirectory, configFileName); + + string nugetConfig = + @" + +"; + CreateXmlFile(configFilePath, nugetConfig); + + var args = new string[] { + "nuget", + "add", + "source", + "http://test_source", + "--name", + "test_source", + "--username", + "test_user_name", + "--password", + "test_password", + "--configfile", + configFilePath + }; + + // Act + var result = _fixture.RunDotnet(configFileDirectory, string.Join(" ", args), ignoreExitCode: true); + + // Assert + Assert.Equal(0, result.Item1); + + var settings = Settings.LoadDefaultSettings( + configFileDirectory, + configFileName, + null); + + var packageSourcesSection = settings.GetSection("packageSources"); + var sourceItem = packageSourcesSection?.GetFirstItemWithAttribute("key", "test_source"); + Assert.Equal("http://test_source", sourceItem.GetValueAsPath()); + + var sourceCredentialsSection = settings.GetSection("packageSourceCredentials"); + var credentialItem = sourceCredentialsSection?.Items.First(c => string.Equals(c.ElementName, "test_source", StringComparison.OrdinalIgnoreCase)) as CredentialsItem; + Assert.NotNull(credentialItem); + + Assert.Equal("test_user_name", credentialItem.Username); + + var password = EncryptionUtility.DecryptString(credentialItem.Password); + Assert.Equal("test_password", password); + } + } + + private static void CreateXmlFile(string configFilePath, string nugetConfigString) + { + using (var stream = File.OpenWrite(configFilePath)) + { + var nugetConfigXDoc = XDocument.Parse(nugetConfigString); + ProjectFileUtils.WriteXmlToFile(nugetConfigXDoc, stream); + } + } + + [PlatformFact(Platform.Windows)] + public void SourcesCommandTest_EnableSource() + { + // Arrange + using (var configFileDirectory = TestDirectory.Create()) + { + var configFileName = "nuget.config"; + var configFilePath = Path.Combine(configFileDirectory, configFileName); + + var nugetConfig = + @" + + + + + + + + +"; + CreateXmlFile(configFilePath, nugetConfig); + + var args = new string[] { + "nuget", + "enable", + "source", + "TEST_source", // this should work in a case sensitive manner + "--configfile", + configFilePath + }; + + // Act + var settings = Settings.LoadDefaultSettings( + configFileDirectory, + configFileName, + null); + var packageSourceProvider = new PackageSourceProvider(settings); + var sources = packageSourceProvider.LoadPackageSources().ToList(); + Assert.Single(sources); + + var source = sources.Single(); + Assert.Equal("test_source", source.Name); + Assert.Equal("http://test_source", source.Source); + Assert.False(source.IsEnabled); + + // Main Act + var result = _fixture.RunDotnet(Directory.GetCurrentDirectory(), string.Join(" ", args), ignoreExitCode: true); + + // Assert + Assert.True(result.ExitCode == 0); + + settings = Settings.LoadDefaultSettings( + configFileDirectory, + configFileName, + null); + + var disabledSourcesSection = settings.GetSection("disabledPackageSources"); + var disabledSources = disabledSourcesSection?.Items.Select(c => c as AddItem).Where(c => c != null).ToList(); + Assert.Single(disabledSources); + var disabledSource = disabledSources.Single(); + Assert.Equal("Microsoft and .NET", disabledSource.Key); + + packageSourceProvider = new PackageSourceProvider(settings); + sources = packageSourceProvider.LoadPackageSources().ToList(); + + var testSources = sources.Where(s => s.Name == "test_source"); + Assert.Single(testSources); + source = testSources.Single(); + + Assert.Equal("test_source", source.Name); + Assert.Equal("http://test_source", source.Source); + Assert.True(source.IsEnabled, "Source is not enabled"); + } + } + + [PlatformFact(Platform.Windows)] + public void SourcesCommandTest_DisableSource() + { + // Arrange + using (var configFileDirectory = TestDirectory.Create()) + { + var configFileName = "nuget.config"; + var configFilePath = Path.Combine(configFileDirectory, configFileName); + + var nugetConfig = + @" + + + + +"; + CreateXmlFile(configFilePath, nugetConfig); + + var args = new string[] { + "nuget", + "disable", + "source", + "TEST_source", + "--configfile", + configFilePath + }; + + // Act + var settings = Settings.LoadDefaultSettings( + configFileDirectory, + configFileName, + null); + + var packageSourceProvider = new PackageSourceProvider(settings); + var sources = packageSourceProvider.LoadPackageSources().ToList(); + Assert.Single(sources); + + var source = sources.Single(); + Assert.Equal("test_source", source.Name); + Assert.Equal("http://test_source", source.Source); + Assert.True(source.IsEnabled); + + // Main Act + var result = _fixture.RunDotnet(Directory.GetCurrentDirectory(), string.Join(" ", args), ignoreExitCode: true); + + // Assert + Assert.True(result.ExitCode == 0); + + settings = Settings.LoadDefaultSettings( + configFileDirectory, + configFileName, + null); + + packageSourceProvider = new PackageSourceProvider(settings); + sources = packageSourceProvider.LoadPackageSources().ToList(); + + var testSources = sources.Where(s => s.Name == "test_source"); + Assert.Single(testSources); + source = testSources.Single(); + + Assert.Equal("test_source", source.Name); + Assert.Equal("http://test_source", source.Source); + Assert.False(source.IsEnabled, "Source is not disabled"); + } + } + + [PlatformTheory(Platform.Windows)] + [InlineData("list source --foo", 2)] + [InlineData("add source foo bar", 3)] + [InlineData("remove source a b", 3)] + [InlineData("remove a b c", 1)] + [InlineData("add source B a --configfile file.txt --name x --source y", 3)] + [InlineData("list source --configfile file.txt B a", 4)] + public void SourcesCommandTest_Failure_InvalidArguments(string cmd, int badParam) + { + // all of these commands need to start with "nuget ", and need to adjust bad param to account for those 2 new params + TestCommandInvalidArguments("nuget " + cmd, badParam + 1); + } + + [Fact(Skip = "cutting verbosity Quiet for now. #6374 covers fixing it for `dotnet add package` too.")] + public void TestVerbosityQuiet_DoesNotShowInfoMessages() + { + using (var preserver = new NuGet.CommandLine.Test.DefaultConfigurationFilePreserver()) + { + // Arrange + var args = new string[] { + "nuget", + "add", + "source", + "http://test_source", + "--name", + "test_source", + "--verbosity", + "Quiet" + }; + var root = Directory.GetDirectoryRoot(Directory.GetCurrentDirectory()); + + // Act + // Set the working directory to C:\, otherwise, + // the test will change the nuget.config at the code repo's root directory + // And, will fail since global nuget.config is updated + var result = _fixture.RunDotnet(root, string.Join(" ", args), ignoreExitCode: true); + + // Assert + Assert.True(result.ExitCode == 0); + // Ensure that no messages are shown with Verbosity as Quiet + Assert.Equal(string.Empty, result.Item2); + var settings = Settings.LoadDefaultSettings(null, null, null); + var packageSourcesSection = settings.GetSection("packageSources"); + var sourceItem = packageSourcesSection?.GetFirstItemWithAttribute("key", "test_source"); + + Assert.Equal("http://test_source", sourceItem.GetValueAsPath()); + } + } + + + /// + /// Verify non-zero status code and proper messages + /// + /// Checks invalid arguments message in stderr, check help message in stdout + /// The nuget.exe command name to verify, without "nuget.exe" at the beginning + public void TestCommandInvalidArguments(string command, int badCommandIndex) + { + // Act + var result = _fixture.RunDotnet(Directory.GetCurrentDirectory(), command, ignoreExitCode: true); + + var commandSplit = command.Split(' '); + + // Break the test if no proper command is found + if (commandSplit.Length < 1 || string.IsNullOrEmpty(commandSplit[0])) + Assert.True(false, "command not found"); + + // 0th - "nuget" + // 1st - "source" + // 2nd - action + // 3rd - nextParam + string badCommand = commandSplit[badCommandIndex]; + + //TODO: item2 in dotnet.exe, item3 in nuget.exe - why doesn't it work the same? + // Assert command + Assert.Contains("'" + badCommand + "'", result.Item2, StringComparison.InvariantCultureIgnoreCase); + + + // Assert invalid argument message + string invalidMessage; + if (badCommand.StartsWith("-")) + { + invalidMessage = "error: Unrecognized option"; + } + else + { + invalidMessage = "error: Unrecognized command"; + } + + // Verify Exit code + VerifyResultFailure(result, invalidMessage); + // Verify traits of help message in stdout + Assert.Contains("Specify --help for a list of available options and commands.", result.Item2); + } + + /// + /// Utility for asserting faulty executions of dotnet.exe + /// + /// Asserts a non-zero status code and a message on stderr. + /// + /// An instance of with command execution results + /// A portion of the error message to be sent + public static void VerifyResultFailure(CommandRunnerResult result, + string expectedErrorMessage) + { + Assert.True( + result.Item1 != 0, + "dotnet.exe nuget DID NOT FAIL: Output is " + result.Item2 + ". Error is " + result.Item3); + + Assert.True( + // TODO: Item2 in dotnet, vs Item3 in nuget.exe -- switched + result.Item2.Contains(expectedErrorMessage), + "Expected error is " + expectedErrorMessage + ". Actual error is " + result.Item2); + } + } +} diff --git a/test/NuGet.Core.FuncTests/Dotnet.Integration.Test/MsbuildIntegrationTestFixture.cs b/test/NuGet.Core.FuncTests/Dotnet.Integration.Test/MsbuildIntegrationTestFixture.cs index 592919cf655..17186bfb9c4 100644 --- a/test/NuGet.Core.FuncTests/Dotnet.Integration.Test/MsbuildIntegrationTestFixture.cs +++ b/test/NuGet.Core.FuncTests/Dotnet.Integration.Test/MsbuildIntegrationTestFixture.cs @@ -29,7 +29,6 @@ public MsbuildIntegrationTestFixture() _cliDirectory = CopyLatestCliForPack(); var dotnetExecutableName = RuntimeEnvironmentHelper.IsWindows ? "dotnet.exe" : "dotnet"; TestDotnetCli = Path.Combine(_cliDirectory, dotnetExecutableName); - MsBuildSdksPath = Path.Combine(Directory.GetDirectories (Path.Combine(_cliDirectory, "sdk")) .First(), "Sdks"); @@ -173,7 +172,6 @@ private void RestoreProjectOrSolution(string workingDirectory, string fileName, /// internal CommandRunnerResult RunDotnet(string workingDirectory, string args, bool ignoreExitCode=false) { - var result = CommandRunner.Run(TestDotnetCli, workingDirectory, args, diff --git a/test/NuGet.Core.FuncTests/NuGet.XPlat.FuncTest/BasicLoggingTests.cs b/test/NuGet.Core.FuncTests/NuGet.XPlat.FuncTest/BasicLoggingTests.cs index 638c190c836..51756cd5d79 100644 --- a/test/NuGet.Core.FuncTests/NuGet.XPlat.FuncTest/BasicLoggingTests.cs +++ b/test/NuGet.Core.FuncTests/NuGet.XPlat.FuncTest/BasicLoggingTests.cs @@ -1,83 +1,12 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -using NuGet.CommandLine.XPlat; using Xunit; namespace NuGet.XPlat.FuncTest { public class BasicLoggingTests { - [Fact] - public void BasicLogging_VersionHeading() - { - // Arrange - var log = new TestCommandOutputLogger(observeLogLevel: true); - - var args = new string[] - { - "--verbosity", - "verbose" - }; - - // Act - var exitCode = NuGet.CommandLine.XPlat.Program.MainInternal(args, log); - - // Assert - Assert.Equal(0, exitCode); - Assert.Equal(1, log.VerboseMessages.Count); - Assert.Equal(1, log.Messages.Count); - Assert.Contains("NuGet Command Line Version:", log.ShowMessages()); - } - - [Fact] - public void BasicLogging_VerifyExceptionLoggedWhenVerbose() - { - // Arrange - var log = new TestCommandOutputLogger(observeLogLevel: true); - - var args = new string[] - { - "--verbosity", "verbose", - "--unknown", - }; - - // Act - var exitCode = NuGet.CommandLine.XPlat.Program.MainInternal(args, log); - - // Assert - Assert.Equal(1, exitCode); - Assert.Equal(3, log.Messages.Count); - Assert.Equal(1, log.Errors); - Assert.Equal(0, log.Warnings); - Assert.Contains("--unknown", log.ShowErrors()); // error - Assert.Contains("NuGet.CommandLine.XPlat.Program.", log.ShowMessages()); // verbose stack trace - } - - [Fact] - public void BasicLogging_VerifyExceptionNotLoggedLessThanVerbose() - { - // Arrange - var log = new TestCommandOutputLogger(observeLogLevel: true); - - var args = new string[] - { - "--verbosity", "info", - "--unknown", - }; - - // Act - var exitCode = NuGet.CommandLine.XPlat.Program.MainInternal(args, log); - - // Assert - Assert.Equal(1, exitCode); - Assert.Equal(1, log.Messages.Count); - Assert.Equal(1, log.Errors); - Assert.Equal(0, log.Warnings); - Assert.Contains("--unknown", log.ShowErrors()); // error - Assert.DoesNotContain("NuGet.CommandLine.XPlat.Program.", log.ShowMessages()); // verbose stack trace - } - [Fact] public void BasicLogging_NoParams_ExitCode() { diff --git a/test/NuGet.Core.FuncTests/NuGet.XPlat.FuncTest/XPlatLocalsTests.cs b/test/NuGet.Core.FuncTests/NuGet.XPlat.FuncTest/XPlatLocalsTests.cs index 90f6a6e0ce0..4444f4ec98b 100644 --- a/test/NuGet.Core.FuncTests/NuGet.XPlat.FuncTest/XPlatLocalsTests.cs +++ b/test/NuGet.Core.FuncTests/NuGet.XPlat.FuncTest/XPlatLocalsTests.cs @@ -242,7 +242,7 @@ public static void Locals_Success_InvalidResourceName_HelpMessage(string args) // Arrange var expectedResult = string.Concat("error: An invalid local resource name was provided. " + - "Please provide one of the following values: http-cache, temp, global-packages, all."); + "Provide one of the following values: http-cache, temp, global-packages, all."); // Act var result = CommandRunner.Run( diff --git a/test/NuGet.Core.Tests/NuGet.Commands.Test/SignCommandRunnerTests.cs b/test/NuGet.Core.Tests/NuGet.Commands.Test/SignCommandRunnerTests.cs index 51b4ff1dd56..2c7e52f0737 100644 --- a/test/NuGet.Core.Tests/NuGet.Commands.Test/SignCommandRunnerTests.cs +++ b/test/NuGet.Core.Tests/NuGet.Commands.Test/SignCommandRunnerTests.cs @@ -34,7 +34,7 @@ public async Task ExecuteCommandAsync_WithCertificateFileNotFound_ThrowsAsync() () => test.Runner.ExecuteCommandAsync(test.Args)); Assert.Equal(NuGetLogCode.NU3001, exception.AsLogMessage().Code); - Assert.Equal($"Certificate file '{certificateFilePath}' not found. For a list of accepted ways to provide a certificate, please visit https://docs.nuget.org/docs/reference/command-line-reference", exception.Message); + Assert.Equal($"Certificate file '{certificateFilePath}' not found. For a list of accepted ways to provide a certificate, visit https://docs.nuget.org/docs/reference/command-line-reference", exception.Message); } } @@ -59,7 +59,7 @@ public async Task ExecuteCommandAsync_WithEmptyPkcs7File_ThrowsAsync() () => test.Runner.ExecuteCommandAsync(test.Args)); Assert.Equal(NuGetLogCode.NU3001, exception.AsLogMessage().Code); - Assert.Equal($"Certificate file '{certificateFilePath}' is invalid. For a list of accepted ways to provide a certificate, please visit https://docs.nuget.org/docs/reference/command-line-reference", exception.Message); + Assert.Equal($"Certificate file '{certificateFilePath}' is invalid. For a list of accepted ways to provide a certificate, visit https://docs.nuget.org/docs/reference/command-line-reference", exception.Message); } } @@ -76,7 +76,7 @@ public async Task ExecuteCommandAsync_WithNoCertificateFound_ThrowsAsync() () => test.Runner.ExecuteCommandAsync(test.Args)); Assert.Equal(NuGetLogCode.NU3001, exception.AsLogMessage().Code); - Assert.Equal("No certificates were found that meet all the given criteria. For a list of accepted ways to provide a certificate, please visit https://docs.nuget.org/docs/reference/command-line-reference", exception.Message); + Assert.Equal("No certificates were found that meet all the given criteria. For a list of accepted ways to provide a certificate, visit https://docs.nuget.org/docs/reference/command-line-reference", exception.Message); } } @@ -98,7 +98,7 @@ public async Task ExecuteCommandAsync_WithIncorrectPassword_ThrowsAsync() () => test.Runner.ExecuteCommandAsync(test.Args)); Assert.Equal(NuGetLogCode.NU3001, exception.AsLogMessage().Code); - Assert.Equal($"Invalid password was provided for the certificate file '{certificateFilePath}'. Please provide a valid password using the '-CertificatePassword' option", exception.Message); + Assert.Equal($"Invalid password was provided for the certificate file '{certificateFilePath}'. Provide a valid password using the '-CertificatePassword' option", exception.Message); } } diff --git a/test/NuGet.Clients.Tests/NuGet.CommandLine.Test/DefaultConfigurationFilePreserver.cs b/test/TestUtilities/Test.Utility/DefaultConfigurationFilePreserver.cs similarity index 68% rename from test/NuGet.Clients.Tests/NuGet.CommandLine.Test/DefaultConfigurationFilePreserver.cs rename to test/TestUtilities/Test.Utility/DefaultConfigurationFilePreserver.cs index ec4c328c859..12dfa28abb8 100644 --- a/test/NuGet.Clients.Tests/NuGet.CommandLine.Test/DefaultConfigurationFilePreserver.cs +++ b/test/TestUtilities/Test.Utility/DefaultConfigurationFilePreserver.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; using System.IO; using System.Threading; @@ -7,15 +10,15 @@ namespace NuGet.CommandLine.Test /// /// Helps ensuring only one unit-test can backup/restore the global nuget.config at a time. /// - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1063:ImplementIDisposableCorrectly")] - public class DefaultConfigurationFilePreserver : IDisposable + public sealed class DefaultConfigurationFilePreserver : IDisposable { private const string MutexName = "DefaultConfigurationFilePreserver"; private readonly Mutex _mutex; + private bool _disposed = false; public DefaultConfigurationFilePreserver() { - _mutex = new Mutex(false, MutexName); + _mutex = new Mutex(initiallyOwned: false, MutexName); var owner = _mutex.WaitOne(TimeSpan.FromMinutes(2)); if (!owner) { @@ -24,12 +27,30 @@ public DefaultConfigurationFilePreserver() BackupAndDeleteDefaultConfigurationFile(); } - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1063:ImplementIDisposableCorrectly")] public void Dispose() { - RestoreDefaultConfigurationFile(); - _mutex.ReleaseMutex(); - _mutex.Dispose(); + Dispose(true); + GC.SuppressFinalize(this); + } + + void Dispose(bool disposing) + { + if (!_disposed) + { + if (disposing) + { + RestoreDefaultConfigurationFile(); + _mutex.ReleaseMutex(); + _mutex.Dispose(); + } + + _disposed = true; + } + } + + ~DefaultConfigurationFilePreserver() + { + Dispose(false); } private static void BackupAndDeleteDefaultConfigurationFile() @@ -57,6 +78,5 @@ private static void RestoreDefaultConfigurationFile() File.Delete(backupFileName); } } - } }