diff --git a/src/dotnet/CommonLocalizableStrings.resx b/src/dotnet/CommonLocalizableStrings.resx
index fd28bb3cf..236b2fd26 100644
--- a/src/dotnet/CommonLocalizableStrings.resx
+++ b/src/dotnet/CommonLocalizableStrings.resx
@@ -610,13 +610,19 @@ setx PATH "%PATH%;{0}"
Failed to uninstall tool package '{0}': {1}
-
- Package '{0}' is missing entry point file {1}.
+
+ Entry point file '{0}' for command '{1}' was not found in the package.
-
- Package '{0}' is missing tool settings file DotnetToolSettings.xml.
+
+ Settings file 'DotnetToolSettings.xml' was not found in the package.
Tool '{0}' (version '{1}') is already installed.
+
+ Failed to find staged tool package '{0}'.
+
+
+ Column maximum width must be greater than zero.
+
diff --git a/src/dotnet/PrintableTable.cs b/src/dotnet/PrintableTable.cs
new file mode 100644
index 000000000..ce31e13cc
--- /dev/null
+++ b/src/dotnet/PrintableTable.cs
@@ -0,0 +1,226 @@
+// Copyright (c) .NET Foundation and contributors. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+using Microsoft.DotNet.Tools;
+
+namespace Microsoft.DotNet.Cli
+{
+ // Represents a table (with rows of type T) that can be printed to a terminal.
+ internal class PrintableTable
+ {
+ private const string ColumnDelimiter = " ";
+ private List _columns = new List();
+
+ private class Column
+ {
+ public string Header { get; set; }
+ public Func GetContent { get; set; }
+ public int MaxWidth { get; set; }
+ public override string ToString() { return Header; }
+ }
+
+ public void AddColumn(string header, Func getContent, int maxWidth = int.MaxValue)
+ {
+ if (getContent == null)
+ {
+ throw new ArgumentNullException(nameof(getContent));
+ }
+
+ if (maxWidth <= 0)
+ {
+ throw new ArgumentException(
+ CommonLocalizableStrings.ColumnMaxWidthMustBeGreaterThanZero,
+ nameof(maxWidth));
+ }
+
+ _columns.Add(
+ new Column() {
+ Header = header,
+ GetContent = getContent,
+ MaxWidth = maxWidth
+ });
+ }
+
+ public void PrintRows(IEnumerable rows, Action writeLine)
+ {
+ if (rows == null)
+ {
+ throw new ArgumentNullException(nameof(rows));
+ }
+
+ if (writeLine == null)
+ {
+ throw new ArgumentNullException(nameof(writeLine));
+ }
+
+ var widths = CalculateColumnWidths(rows);
+ var totalWidth = CalculateTotalWidth(widths);
+ if (totalWidth == 0)
+ {
+ return;
+ }
+
+ foreach (var line in EnumerateHeaderLines(widths))
+ {
+ writeLine(line);
+ }
+
+ writeLine(new string('-', totalWidth));
+
+ foreach (var row in rows)
+ {
+ foreach (var line in EnumerateRowLines(row, widths))
+ {
+ writeLine(line);
+ }
+ }
+ }
+
+ public int CalculateWidth(IEnumerable rows)
+ {
+ if (rows == null)
+ {
+ throw new ArgumentNullException(nameof(rows));
+ }
+
+ return CalculateTotalWidth(CalculateColumnWidths(rows));
+ }
+
+ private IEnumerable EnumerateHeaderLines(int[] widths)
+ {
+ if (_columns.Count != widths.Length)
+ {
+ throw new InvalidOperationException();
+ }
+
+ return EnumerateLines(
+ widths,
+ _columns.Select(c => new StringInfo(c.Header ?? "")).ToArray());
+ }
+
+ private IEnumerable EnumerateRowLines(T row, int[] widths)
+ {
+ if (_columns.Count != widths.Length)
+ {
+ throw new InvalidOperationException();
+ }
+
+ return EnumerateLines(
+ widths,
+ _columns.Select(c => new StringInfo(c.GetContent(row) ?? "")).ToArray());
+ }
+
+ private static IEnumerable EnumerateLines(int[] widths, StringInfo[] contents)
+ {
+ if (widths.Length != contents.Length)
+ {
+ throw new InvalidOperationException();
+ }
+
+ if (contents.Length == 0)
+ {
+ yield break;
+ }
+
+ var builder = new StringBuilder();
+ for (int line = 0; true; ++line)
+ {
+ builder.Clear();
+
+ bool emptyLine = true;
+ bool appendDelimiter = false;
+ for (int i = 0; i < contents.Length; ++i)
+ {
+ // Skip zero-width columns entirely
+ if (widths[i] == 0)
+ {
+ continue;
+ }
+
+ if (appendDelimiter)
+ {
+ builder.Append(ColumnDelimiter);
+ }
+
+ var startIndex = line * widths[i];
+ var length = contents[i].LengthInTextElements;
+ if (startIndex < length)
+ {
+ var endIndex = (line + 1) * widths[i];
+ length = endIndex >= length ? length - startIndex : widths[i];
+ builder.Append(contents[i].SubstringByTextElements(startIndex, length));
+ builder.Append(' ', widths[i] - length);
+ emptyLine = false;
+ }
+ else
+ {
+ // No more content for this column; append whitespace to fill remaining space
+ builder.Append(' ', widths[i]);
+ }
+
+ appendDelimiter = true;
+ }
+
+ if (emptyLine)
+ {
+ // Yield an "empty" line on the first line only
+ if (line == 0)
+ {
+ yield return builder.ToString();
+ }
+ yield break;
+ }
+
+ yield return builder.ToString();
+ }
+ }
+
+ private int[] CalculateColumnWidths(IEnumerable rows)
+ {
+ return _columns
+ .Select(c => {
+ var width = new StringInfo(c.Header ?? "").LengthInTextElements;
+
+ foreach (var row in rows)
+ {
+ width = Math.Max(
+ width,
+ new StringInfo(c.GetContent(row) ?? "").LengthInTextElements);
+ }
+
+ return Math.Min(width, c.MaxWidth);
+ })
+ .ToArray();
+ }
+
+ private static int CalculateTotalWidth(int[] widths)
+ {
+ int sum = 0;
+ int count = 0;
+
+ foreach (var width in widths)
+ {
+ if (width == 0)
+ {
+ // Skip zero-width columns
+ continue;
+ }
+
+ sum += width;
+ ++count;
+ }
+
+ if (count == 0)
+ {
+ return 0;
+ }
+
+ return sum + (ColumnDelimiter.Length * (count - 1));
+ }
+ }
+}
diff --git a/src/dotnet/Properties/AssemblyInfo.cs b/src/dotnet/Properties/AssemblyInfo.cs
index 25bd8cb8c..b5f0b8fe0 100644
--- a/src/dotnet/Properties/AssemblyInfo.cs
+++ b/src/dotnet/Properties/AssemblyInfo.cs
@@ -21,3 +21,4 @@ using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("Microsoft.DotNet.Tools.Tests.ComponentMocks, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.DotNet.ToolPackage.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.DotNet.ShellShim.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
+[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")]
diff --git a/src/dotnet/ToolPackage/IToolPackage.cs b/src/dotnet/ToolPackage/IToolPackage.cs
index 3ee968cb9..c769b002d 100644
--- a/src/dotnet/ToolPackage/IToolPackage.cs
+++ b/src/dotnet/ToolPackage/IToolPackage.cs
@@ -4,14 +4,15 @@
using System;
using System.Collections.Generic;
using Microsoft.Extensions.EnvironmentAbstractions;
+using NuGet.Versioning;
namespace Microsoft.DotNet.ToolPackage
{
internal interface IToolPackage
{
- string PackageId { get; }
+ PackageId Id { get; }
- string PackageVersion { get; }
+ NuGetVersion Version { get; }
DirectoryPath PackageDirectory { get; }
diff --git a/src/dotnet/ToolPackage/IToolPackageInstaller.cs b/src/dotnet/ToolPackage/IToolPackageInstaller.cs
index d8501d22d..c6ef964e1 100644
--- a/src/dotnet/ToolPackage/IToolPackageInstaller.cs
+++ b/src/dotnet/ToolPackage/IToolPackageInstaller.cs
@@ -4,14 +4,15 @@
using System;
using System.Collections.Generic;
using Microsoft.Extensions.EnvironmentAbstractions;
+using NuGet.Versioning;
namespace Microsoft.DotNet.ToolPackage
{
internal interface IToolPackageInstaller
{
IToolPackage InstallPackage(
- string packageId,
- string packageVersion = null,
+ PackageId packageId,
+ VersionRange versionRange = null,
string targetFramework = null,
FilePath? nugetConfig = null,
string source = null,
diff --git a/src/dotnet/ToolPackage/IToolPackageStore.cs b/src/dotnet/ToolPackage/IToolPackageStore.cs
index 31bea417f..4e3e88c65 100644
--- a/src/dotnet/ToolPackage/IToolPackageStore.cs
+++ b/src/dotnet/ToolPackage/IToolPackageStore.cs
@@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using Microsoft.Extensions.EnvironmentAbstractions;
+using NuGet.Versioning;
namespace Microsoft.DotNet.ToolPackage
{
@@ -11,6 +12,18 @@ namespace Microsoft.DotNet.ToolPackage
{
DirectoryPath Root { get; }
- IEnumerable GetInstalledPackages(string packageId);
+ DirectoryPath GetRandomStagingDirectory();
+
+ NuGetVersion GetStagedPackageVersion(DirectoryPath stagingDirectory, PackageId packageId);
+
+ DirectoryPath GetRootPackageDirectory(PackageId packageId);
+
+ DirectoryPath GetPackageDirectory(PackageId packageId, NuGetVersion version);
+
+ IEnumerable EnumeratePackages();
+
+ IEnumerable EnumeratePackageVersions(PackageId packageId);
+
+ IToolPackage GetPackage(PackageId packageId, NuGetVersion version);
}
}
diff --git a/src/dotnet/ToolPackage/PackageId.cs b/src/dotnet/ToolPackage/PackageId.cs
new file mode 100644
index 000000000..07846bf7a
--- /dev/null
+++ b/src/dotnet/ToolPackage/PackageId.cs
@@ -0,0 +1,43 @@
+// Copyright (c) .NET Foundation and contributors. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using System;
+using Microsoft.DotNet.InternalAbstractions;
+
+namespace Microsoft.DotNet.ToolPackage
+{
+ internal struct PackageId : IEquatable, IComparable
+ {
+ private string _id;
+
+ public PackageId(string id)
+ {
+ _id = id?.ToLowerInvariant() ?? throw new ArgumentNullException(nameof(id));
+ }
+
+ public bool Equals(PackageId other)
+ {
+ return ToString() == other.ToString();
+ }
+
+ public int CompareTo(PackageId other)
+ {
+ return string.Compare(ToString(), other.ToString(), StringComparison.Ordinal);
+ }
+
+ public override bool Equals(object obj)
+ {
+ return obj is PackageId id && Equals(id);
+ }
+
+ public override int GetHashCode()
+ {
+ return ToString().GetHashCode();
+ }
+
+ public override string ToString()
+ {
+ return _id ?? "";
+ }
+ }
+}
diff --git a/src/dotnet/ToolPackage/ToolPackageInstaller.cs b/src/dotnet/ToolPackage/ToolPackageInstaller.cs
index e30a4cc7e..cf655a301 100644
--- a/src/dotnet/ToolPackage/ToolPackageInstaller.cs
+++ b/src/dotnet/ToolPackage/ToolPackageInstaller.cs
@@ -7,13 +7,12 @@ using Microsoft.DotNet.Cli;
using Microsoft.DotNet.Configurer;
using Microsoft.DotNet.Tools;
using Microsoft.Extensions.EnvironmentAbstractions;
+using NuGet.Versioning;
namespace Microsoft.DotNet.ToolPackage
{
internal class ToolPackageInstaller : IToolPackageInstaller
{
- public const string StagingDirectory = ".stage";
-
private readonly IToolPackageStore _store;
private readonly IProjectRestorer _projectRestorer;
private readonly FilePath? _tempProject;
@@ -32,33 +31,27 @@ namespace Microsoft.DotNet.ToolPackage
}
public IToolPackage InstallPackage(
- string packageId,
- string packageVersion = null,
+ PackageId packageId,
+ VersionRange versionRange = null,
string targetFramework = null,
FilePath? nugetConfig = null,
string source = null,
string verbosity = null)
{
- if (packageId == null)
- {
- throw new ArgumentNullException(nameof(packageId));
- }
-
- var packageRootDirectory = _store.Root.WithSubDirectories(packageId);
+ var packageRootDirectory = _store.GetRootPackageDirectory(packageId);
string rollbackDirectory = null;
return TransactionalAction.Run(
action: () => {
try
{
-
- var stageDirectory = _store.Root.WithSubDirectories(StagingDirectory, Path.GetRandomFileName());
+ var stageDirectory = _store.GetRandomStagingDirectory();
Directory.CreateDirectory(stageDirectory.Value);
rollbackDirectory = stageDirectory.Value;
var tempProject = CreateTempProject(
packageId: packageId,
- packageVersion: packageVersion,
+ versionRange: versionRange,
targetFramework: targetFramework ?? BundledTargetFramework.GetTargetFrameworkMoniker(),
restoreDirectory: stageDirectory);
@@ -76,29 +69,22 @@ namespace Microsoft.DotNet.ToolPackage
File.Delete(tempProject.Value);
}
- packageVersion = Path.GetFileName(
- Directory.EnumerateDirectories(
- stageDirectory.WithSubDirectories(packageId).Value).Single());
-
- var packageDirectory = packageRootDirectory.WithSubDirectories(packageVersion);
+ var version = _store.GetStagedPackageVersion(stageDirectory, packageId);
+ var packageDirectory = _store.GetPackageDirectory(packageId, version);
if (Directory.Exists(packageDirectory.Value))
{
throw new ToolPackageException(
string.Format(
CommonLocalizableStrings.ToolPackageConflictPackageId,
packageId,
- packageVersion));
+ version.ToNormalizedString()));
}
Directory.CreateDirectory(packageRootDirectory.Value);
Directory.Move(stageDirectory.Value, packageDirectory.Value);
rollbackDirectory = packageDirectory.Value;
- return new ToolPackageInstance(
- _store,
- packageId,
- packageVersion,
- packageDirectory);
+ return new ToolPackageInstance(_store, packageId, version, packageDirectory);
}
catch (Exception ex) when (ex is UnauthorizedAccessException || ex is IOException)
{
@@ -126,8 +112,8 @@ namespace Microsoft.DotNet.ToolPackage
}
private FilePath CreateTempProject(
- string packageId,
- string packageVersion,
+ PackageId packageId,
+ VersionRange versionRange,
string targetFramework,
DirectoryPath restoreDirectory)
{
@@ -159,8 +145,9 @@ namespace Microsoft.DotNet.ToolPackage
new XElement("DisableImplicitNuGetFallbackFolder", "true")), // disable SDK side implicit NuGetFallbackFolder
new XElement("ItemGroup",
new XElement("PackageReference",
- new XAttribute("Include", packageId),
- new XAttribute("Version", packageVersion ?? "*") // nuget will restore * for latest
+ new XAttribute("Include", packageId.ToString()),
+ new XAttribute("Version",
+ versionRange?.ToString("S", new VersionRangeFormatter()) ?? "*") // nuget will restore latest stable for *
))
));
diff --git a/src/dotnet/ToolPackage/ToolPackageInstance.cs b/src/dotnet/ToolPackage/ToolPackageInstance.cs
index 0d28cfe97..74b092109 100644
--- a/src/dotnet/ToolPackage/ToolPackageInstance.cs
+++ b/src/dotnet/ToolPackage/ToolPackageInstance.cs
@@ -6,6 +6,7 @@ using Microsoft.DotNet.Cli;
using Microsoft.DotNet.Tools;
using Microsoft.Extensions.EnvironmentAbstractions;
using NuGet.ProjectModel;
+using NuGet.Versioning;
namespace Microsoft.DotNet.ToolPackage
{
@@ -17,20 +18,21 @@ namespace Microsoft.DotNet.ToolPackage
public ToolPackageInstance(
IToolPackageStore store,
- string packageId,
- string packageVersion,
+ PackageId id,
+ NuGetVersion version,
DirectoryPath packageDirectory)
{
_store = store ?? throw new ArgumentNullException(nameof(store));
- PackageId = packageId ?? throw new ArgumentNullException(nameof(packageId));
- PackageVersion = packageVersion ?? throw new ArgumentNullException(nameof(packageVersion));
- PackageDirectory = packageDirectory;
_commands = new Lazy>(GetCommands);
+
+ Id = id;
+ Version = version ?? throw new ArgumentNullException(nameof(version));
+ PackageDirectory = packageDirectory;
}
- public string PackageId { get; private set; }
+ public PackageId Id { get; private set; }
- public string PackageVersion { get; private set; }
+ public NuGetVersion Version { get; private set; }
public DirectoryPath PackageDirectory { get; private set; }
@@ -53,13 +55,9 @@ namespace Microsoft.DotNet.ToolPackage
{
if (Directory.Exists(PackageDirectory.Value))
{
- // Use the same staging directory for uninstall instead of temp
+ // Use the staging directory for uninstall
// This prevents cross-device moves when temp is mounted to a different device
- var tempPath = _store
- .Root
- .WithSubDirectories(ToolPackageInstaller.StagingDirectory)
- .WithFile(Path.GetRandomFileName())
- .Value;
+ var tempPath = _store.GetRandomStagingDirectory().Value;
Directory.Move(PackageDirectory.Value, tempPath);
tempPackageDirectory = tempPath;
}
@@ -75,7 +73,7 @@ namespace Microsoft.DotNet.ToolPackage
throw new ToolPackageException(
string.Format(
CommonLocalizableStrings.FailedToUninstallToolPackage,
- PackageId,
+ Id,
ex.Message),
ex);
}
@@ -109,16 +107,14 @@ namespace Microsoft.DotNet.ToolPackage
var dotnetToolSettings = FindItemInTargetLibrary(library, ToolSettingsFileName);
if (dotnetToolSettings == null)
{
- throw new ToolPackageException(
- string.Format(
- CommonLocalizableStrings.ToolPackageMissingSettingsFile,
- PackageId));
+ throw new ToolConfigurationException(
+ CommonLocalizableStrings.MissingToolSettingsFile);
}
var toolConfigurationPath =
PackageDirectory
.WithSubDirectories(
- PackageId,
+ Id.ToString(),
library.Version.ToNormalizedString())
.WithFile(dotnetToolSettings.Path);
@@ -127,11 +123,11 @@ namespace Microsoft.DotNet.ToolPackage
var entryPointFromLockFile = FindItemInTargetLibrary(library, configuration.ToolAssemblyEntryPoint);
if (entryPointFromLockFile == null)
{
- throw new ToolPackageException(
+ throw new ToolConfigurationException(
string.Format(
- CommonLocalizableStrings.ToolPackageMissingEntryPointFile,
- PackageId,
- configuration.ToolAssemblyEntryPoint));
+ CommonLocalizableStrings.MissingToolEntryPointFile,
+ configuration.ToolAssemblyEntryPoint,
+ configuration.CommandName));
}
// Currently only "dotnet" commands are supported
@@ -140,7 +136,7 @@ namespace Microsoft.DotNet.ToolPackage
"dotnet",
PackageDirectory
.WithSubDirectories(
- PackageId,
+ Id.ToString(),
library.Version.ToNormalizedString())
.WithFile(entryPointFromLockFile.Path)));
@@ -148,10 +144,9 @@ namespace Microsoft.DotNet.ToolPackage
}
catch (Exception ex) when (ex is UnauthorizedAccessException || ex is IOException)
{
- throw new ToolPackageException(
+ throw new ToolConfigurationException(
string.Format(
CommonLocalizableStrings.FailedToRetrieveToolConfiguration,
- PackageId,
ex.Message),
ex);
}
@@ -161,7 +156,8 @@ namespace Microsoft.DotNet.ToolPackage
{
return lockFile
?.Targets?.SingleOrDefault(t => t.RuntimeIdentifier != null)
- ?.Libraries?.SingleOrDefault(l => l.Name == PackageId);
+ ?.Libraries?.SingleOrDefault(l =>
+ string.Compare(l.Name, Id.ToString(), StringComparison.CurrentCultureIgnoreCase) == 0);
}
private static LockFileItem FindItemInTargetLibrary(LockFileTargetLibrary library, string targetRelativeFilePath)
diff --git a/src/dotnet/ToolPackage/ToolPackageStore.cs b/src/dotnet/ToolPackage/ToolPackageStore.cs
index d2a9f79f1..f424b6062 100644
--- a/src/dotnet/ToolPackage/ToolPackageStore.cs
+++ b/src/dotnet/ToolPackage/ToolPackageStore.cs
@@ -2,12 +2,16 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
+using Microsoft.DotNet.Tools;
using Microsoft.Extensions.EnvironmentAbstractions;
+using NuGet.Versioning;
namespace Microsoft.DotNet.ToolPackage
{
internal class ToolPackageStore : IToolPackageStore
{
+ public const string StagingDirectory = ".stage";
+
public ToolPackageStore(DirectoryPath root)
{
Root = root;
@@ -15,14 +19,72 @@ namespace Microsoft.DotNet.ToolPackage
public DirectoryPath Root { get; private set; }
- public IEnumerable GetInstalledPackages(string packageId)
+ public DirectoryPath GetRandomStagingDirectory()
{
- if (packageId == null)
+ return Root.WithSubDirectories(StagingDirectory, Path.GetRandomFileName());
+ }
+
+ public NuGetVersion GetStagedPackageVersion(DirectoryPath stagingDirectory, PackageId packageId)
+ {
+ if (NuGetVersion.TryParse(
+ Path.GetFileName(
+ Directory.EnumerateDirectories(
+ stagingDirectory.WithSubDirectories(packageId.ToString()).Value).FirstOrDefault()),
+ out var version))
{
- throw new ArgumentNullException(nameof(packageId));
+ return version;
}
- var packageRootDirectory = Root.WithSubDirectories(packageId);
+ throw new ToolPackageException(
+ string.Format(
+ CommonLocalizableStrings.FailedToFindStagedToolPackage,
+ packageId));
+ }
+
+ public DirectoryPath GetRootPackageDirectory(PackageId packageId)
+ {
+ return Root.WithSubDirectories(packageId.ToString());
+ }
+
+ public DirectoryPath GetPackageDirectory(PackageId packageId, NuGetVersion version)
+ {
+ if (version == null)
+ {
+ throw new ArgumentNullException(nameof(version));
+ }
+
+ return GetRootPackageDirectory(packageId)
+ .WithSubDirectories(version.ToNormalizedString().ToLowerInvariant());
+ }
+
+ public IEnumerable EnumeratePackages()
+ {
+ if (!Directory.Exists(Root.Value))
+ {
+ yield break;
+ }
+
+ foreach (var subdirectory in Directory.EnumerateDirectories(Root.Value))
+ {
+ var name = Path.GetFileName(subdirectory);
+ var packageId = new PackageId(name);
+
+ // Ignore the staging directory and any directory that isn't the same as the package id
+ if (name == StagingDirectory || name != packageId.ToString())
+ {
+ continue;
+ }
+
+ foreach (var package in EnumeratePackageVersions(packageId))
+ {
+ yield return package;
+ }
+ }
+ }
+
+ public IEnumerable EnumeratePackageVersions(PackageId packageId)
+ {
+ var packageRootDirectory = Root.WithSubDirectories(packageId.ToString());
if (!Directory.Exists(packageRootDirectory.Value))
{
yield break;
@@ -30,13 +92,27 @@ namespace Microsoft.DotNet.ToolPackage
foreach (var subdirectory in Directory.EnumerateDirectories(packageRootDirectory.Value))
{
- var version = Path.GetFileName(subdirectory);
yield return new ToolPackageInstance(
this,
packageId,
- version,
- packageRootDirectory.WithSubDirectories(version));
+ NuGetVersion.Parse(Path.GetFileName(subdirectory)),
+ new DirectoryPath(subdirectory));
}
}
+
+ public IToolPackage GetPackage(PackageId packageId, NuGetVersion version)
+ {
+ if (version == null)
+ {
+ throw new ArgumentNullException(nameof(version));
+ }
+
+ var directory = GetPackageDirectory(packageId, version);
+ if (!Directory.Exists(directory.Value))
+ {
+ return null;
+ }
+ return new ToolPackageInstance(this, packageId, version, directory);
+ }
}
}
diff --git a/src/dotnet/commands/dotnet-add/dotnet-add-proj/xlf/LocalizableStrings.cs.xlf b/src/dotnet/commands/dotnet-add/dotnet-add-proj/xlf/LocalizableStrings.cs.xlf
deleted file mode 100644
index 944be9708..000000000
--- a/src/dotnet/commands/dotnet-add/dotnet-add-proj/xlf/LocalizableStrings.cs.xlf
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
-
-
- .NET Add Project to Solution Command
- Příkaz rozhraní .NET pro přidání projektu do řešení
-
-
-
- Command to add project to solution
- Příkaz pro přidání projektu do řešení
-
-
-
- Projects to add to solution
- Projekty přidané do řešení
-
-
-
-
-
\ No newline at end of file
diff --git a/src/dotnet/commands/dotnet-add/dotnet-add-proj/xlf/LocalizableStrings.de.xlf b/src/dotnet/commands/dotnet-add/dotnet-add-proj/xlf/LocalizableStrings.de.xlf
deleted file mode 100644
index ed33e3f3d..000000000
--- a/src/dotnet/commands/dotnet-add/dotnet-add-proj/xlf/LocalizableStrings.de.xlf
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
-
-
- .NET Add Project to Solution Command
- .NET-Befehl zum Hinzufügen eines Projekts zur Projektmappe
-
-
-
- Command to add project to solution
- Befehl zum Hinzufügen eines Projekts zur Projektmappe
-
-
-
- Projects to add to solution
- Zur Projektmappe hinzuzufügende Projekte
-
-
-
-
-
\ No newline at end of file
diff --git a/src/dotnet/commands/dotnet-add/dotnet-add-proj/xlf/LocalizableStrings.es.xlf b/src/dotnet/commands/dotnet-add/dotnet-add-proj/xlf/LocalizableStrings.es.xlf
deleted file mode 100644
index f9d1dab81..000000000
--- a/src/dotnet/commands/dotnet-add/dotnet-add-proj/xlf/LocalizableStrings.es.xlf
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
-
-
- .NET Add Project to Solution Command
- Comando de .NET Agregar proyecto a solución
-
-
-
- Command to add project to solution
- Comando para agregar un proyecto a una solución
-
-
-
- Projects to add to solution
- Proyectos que se agregarán a la solución
-
-
-
-
-
\ No newline at end of file
diff --git a/src/dotnet/commands/dotnet-add/dotnet-add-proj/xlf/LocalizableStrings.fr.xlf b/src/dotnet/commands/dotnet-add/dotnet-add-proj/xlf/LocalizableStrings.fr.xlf
deleted file mode 100644
index 2323b4ba9..000000000
--- a/src/dotnet/commands/dotnet-add/dotnet-add-proj/xlf/LocalizableStrings.fr.xlf
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
-
-
- .NET Add Project to Solution Command
- Commande .NET d'ajout de projet à une solution
-
-
-
- Command to add project to solution
- Commande d'ajout de projet à une solution
-
-
-
- Projects to add to solution
- Projets à ajouter à la solution
-
-
-
-
-
\ No newline at end of file
diff --git a/src/dotnet/commands/dotnet-add/dotnet-add-proj/xlf/LocalizableStrings.it.xlf b/src/dotnet/commands/dotnet-add/dotnet-add-proj/xlf/LocalizableStrings.it.xlf
deleted file mode 100644
index 9f5b6b257..000000000
--- a/src/dotnet/commands/dotnet-add/dotnet-add-proj/xlf/LocalizableStrings.it.xlf
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
-
-
- .NET Add Project to Solution Command
- Comando Aggiungi progetto a soluzione .NET
-
-
-
- Command to add project to solution
- Comando per aggiungere il progetto alla soluzione
-
-
-
- Projects to add to solution
- Progetti da aggiungere alla soluzione
-
-
-
-
-
\ No newline at end of file
diff --git a/src/dotnet/commands/dotnet-add/dotnet-add-proj/xlf/LocalizableStrings.ja.xlf b/src/dotnet/commands/dotnet-add/dotnet-add-proj/xlf/LocalizableStrings.ja.xlf
deleted file mode 100644
index 7db8904d8..000000000
--- a/src/dotnet/commands/dotnet-add/dotnet-add-proj/xlf/LocalizableStrings.ja.xlf
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
-
-
- .NET Add Project to Solution Command
- .NET Add Project to Solution コマンド
-
-
-
- Command to add project to solution
- ソリューションにプロジェクトを追加するコマンド
-
-
-
- Projects to add to solution
- ソリューションに追加するプロジェクト
-
-
-
-
-
\ No newline at end of file
diff --git a/src/dotnet/commands/dotnet-add/dotnet-add-proj/xlf/LocalizableStrings.ko.xlf b/src/dotnet/commands/dotnet-add/dotnet-add-proj/xlf/LocalizableStrings.ko.xlf
deleted file mode 100644
index 5b6e02c56..000000000
--- a/src/dotnet/commands/dotnet-add/dotnet-add-proj/xlf/LocalizableStrings.ko.xlf
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
-
-
- .NET Add Project to Solution Command
- .NET 솔루션에 프로젝트 추가 명령
-
-
-
- Command to add project to solution
- 솔루션에 프로젝트를 추가하기 위한 명령입니다.
-
-
-
- Projects to add to solution
- 솔루션에 추가할 프로젝트
-
-
-
-
-
\ No newline at end of file
diff --git a/src/dotnet/commands/dotnet-add/dotnet-add-proj/xlf/LocalizableStrings.pl.xlf b/src/dotnet/commands/dotnet-add/dotnet-add-proj/xlf/LocalizableStrings.pl.xlf
deleted file mode 100644
index 7c8e0049f..000000000
--- a/src/dotnet/commands/dotnet-add/dotnet-add-proj/xlf/LocalizableStrings.pl.xlf
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
-
-
- .NET Add Project to Solution Command
- Polecenie dodawania projektu do rozwiązania dla platformy .NET
-
-
-
- Command to add project to solution
- Polecenie umożliwiające dodanie projektu do rozwiązania
-
-
-
- Projects to add to solution
- Projekty, które mają zostać dodane do rozwiązania
-
-
-
-
-
\ No newline at end of file
diff --git a/src/dotnet/commands/dotnet-add/dotnet-add-proj/xlf/LocalizableStrings.pt-BR.xlf b/src/dotnet/commands/dotnet-add/dotnet-add-proj/xlf/LocalizableStrings.pt-BR.xlf
deleted file mode 100644
index 1b3694bb4..000000000
--- a/src/dotnet/commands/dotnet-add/dotnet-add-proj/xlf/LocalizableStrings.pt-BR.xlf
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
-
-
- .NET Add Project to Solution Command
- Comando Adicionar Projeto à Solução do .NET
-
-
-
- Command to add project to solution
- Comando para adicionar o projeto à solução
-
-
-
- Projects to add to solution
- Projetos a serem adicionados à solução
-
-
-
-
-
\ No newline at end of file
diff --git a/src/dotnet/commands/dotnet-add/dotnet-add-proj/xlf/LocalizableStrings.ru.xlf b/src/dotnet/commands/dotnet-add/dotnet-add-proj/xlf/LocalizableStrings.ru.xlf
deleted file mode 100644
index e609e17f9..000000000
--- a/src/dotnet/commands/dotnet-add/dotnet-add-proj/xlf/LocalizableStrings.ru.xlf
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
-
-
- .NET Add Project to Solution Command
- Команда .NET "Добавить проект в решение"
-
-
-
- Command to add project to solution
- Команда для добавления проекта в решение
-
-
-
- Projects to add to solution
- Проекты, добавляемые в решение
-
-
-
-
-
\ No newline at end of file
diff --git a/src/dotnet/commands/dotnet-add/dotnet-add-proj/xlf/LocalizableStrings.tr.xlf b/src/dotnet/commands/dotnet-add/dotnet-add-proj/xlf/LocalizableStrings.tr.xlf
deleted file mode 100644
index ab0b0c18b..000000000
--- a/src/dotnet/commands/dotnet-add/dotnet-add-proj/xlf/LocalizableStrings.tr.xlf
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
-
-
- .NET Add Project to Solution Command
- .NET Çözüme Proje Ekleme Komutu
-
-
-
- Command to add project to solution
- Çözüme proje ekleme komutu
-
-
-
- Projects to add to solution
- Çözüme eklenecek projeler
-
-
-
-
-
\ No newline at end of file
diff --git a/src/dotnet/commands/dotnet-add/dotnet-add-proj/xlf/LocalizableStrings.xlf b/src/dotnet/commands/dotnet-add/dotnet-add-proj/xlf/LocalizableStrings.xlf
deleted file mode 100644
index 34201b21a..000000000
--- a/src/dotnet/commands/dotnet-add/dotnet-add-proj/xlf/LocalizableStrings.xlf
+++ /dev/null
@@ -1,20 +0,0 @@
-
-
-
-
-
-
- .NET Add Project to Solution Command
-
-
-
- Command to add project to solution
-
-
-
- Projects to add to solution
-
-
-
-
-
\ No newline at end of file
diff --git a/src/dotnet/commands/dotnet-add/dotnet-add-proj/xlf/LocalizableStrings.zh-Hans.xlf b/src/dotnet/commands/dotnet-add/dotnet-add-proj/xlf/LocalizableStrings.zh-Hans.xlf
deleted file mode 100644
index e49d0c2b1..000000000
--- a/src/dotnet/commands/dotnet-add/dotnet-add-proj/xlf/LocalizableStrings.zh-Hans.xlf
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
-
-
- .NET Add Project to Solution Command
- .NET 将项目添加到解决方案命令
-
-
-
- Command to add project to solution
- 将项目添加到解决方案的命令
-
-
-
- Projects to add to solution
- 要添加到解决方案的项目
-
-
-
-
-
\ No newline at end of file
diff --git a/src/dotnet/commands/dotnet-add/dotnet-add-proj/xlf/LocalizableStrings.zh-Hant.xlf b/src/dotnet/commands/dotnet-add/dotnet-add-proj/xlf/LocalizableStrings.zh-Hant.xlf
deleted file mode 100644
index b24ad1c7f..000000000
--- a/src/dotnet/commands/dotnet-add/dotnet-add-proj/xlf/LocalizableStrings.zh-Hant.xlf
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
-
-
- .NET Add Project to Solution Command
- .NET 將專案新增至解決方案命令
-
-
-
- Command to add project to solution
- 命令,將專案新增至解決方案
-
-
-
- Projects to add to solution
- 要新增至解決方案的專案
-
-
-
-
-
\ No newline at end of file
diff --git a/src/dotnet/commands/dotnet-help/LocalizableStrings.resx b/src/dotnet/commands/dotnet-help/LocalizableStrings.resx
index 8b0c84730..5c4f125dc 100644
--- a/src/dotnet/commands/dotnet-help/LocalizableStrings.resx
+++ b/src/dotnet/commands/dotnet-help/LocalizableStrings.resx
@@ -193,7 +193,7 @@
Remove reference from the project.
- List reference in the project.
+ List project references or installed tools.
Advanced Commands
@@ -271,6 +271,6 @@
Installs an item into the development environment.
- Uninstalls a tool from the development environment.
+ Uninstalls an item from the development environment.
diff --git a/src/dotnet/commands/dotnet-help/xlf/LocalizableStrings.cs.xlf b/src/dotnet/commands/dotnet-help/xlf/LocalizableStrings.cs.xlf
index b348a5041..2075f923e 100644
--- a/src/dotnet/commands/dotnet-help/xlf/LocalizableStrings.cs.xlf
+++ b/src/dotnet/commands/dotnet-help/xlf/LocalizableStrings.cs.xlf
@@ -153,8 +153,8 @@
- List reference in the project.
- Vypíše odkaz v projektu.
+ List project references or installed tools.
+ Vypíše odkaz v projektu.
@@ -258,8 +258,8 @@
- Uninstalls a tool from the development environment.
- Uninstalls a tool from the development environment.
+ Uninstalls an item from the development environment.
+ Uninstalls an item from the development environment.