From 07ddddfa884fee7fc219c073ba1109b06afdc7a6 Mon Sep 17 00:00:00 2001 From: Justin Goshi Date: Thu, 15 Dec 2016 13:40:46 -0800 Subject: [PATCH] Implement dotnet remove proj --- .../dotnet-remove/IRemoveSubCommand.cs | 12 +++ src/dotnet/commands/dotnet-remove/Program.cs | 2 + .../dotnet-remove/RemoveSubCommandBase.cs | 64 +++++++++++ .../dotnet-remove-p2p/LocalizableStrings.cs | 2 - .../dotnet-remove-p2p/Program.cs | 101 ++++++++---------- .../dotnet-remove-proj/LocalizableStrings.cs | 14 +++ .../dotnet-remove-proj/Program.cs | 101 ++++++++++++++++++ 7 files changed, 240 insertions(+), 56 deletions(-) create mode 100644 src/dotnet/commands/dotnet-remove/IRemoveSubCommand.cs create mode 100644 src/dotnet/commands/dotnet-remove/RemoveSubCommandBase.cs create mode 100644 src/dotnet/commands/dotnet-remove/dotnet-remove-proj/LocalizableStrings.cs create mode 100644 src/dotnet/commands/dotnet-remove/dotnet-remove-proj/Program.cs diff --git a/src/dotnet/commands/dotnet-remove/IRemoveSubCommand.cs b/src/dotnet/commands/dotnet-remove/IRemoveSubCommand.cs new file mode 100644 index 000000000..b3626aa66 --- /dev/null +++ b/src/dotnet/commands/dotnet-remove/IRemoveSubCommand.cs @@ -0,0 +1,12 @@ +// 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.Collections.Generic; + +namespace Microsoft.DotNet.Tools.Remove +{ + public interface IRemoveSubCommand + { + void Remove(IList items); + } +} diff --git a/src/dotnet/commands/dotnet-remove/Program.cs b/src/dotnet/commands/dotnet-remove/Program.cs index 58e58791c..9b5d22819 100644 --- a/src/dotnet/commands/dotnet-remove/Program.cs +++ b/src/dotnet/commands/dotnet-remove/Program.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using Microsoft.DotNet.Cli; using Microsoft.DotNet.Cli.CommandLine; +using Microsoft.DotNet.Tools.Remove.ProjectFromSolution; using Microsoft.DotNet.Tools.Remove.ProjectToProjectReference; namespace Microsoft.DotNet.Tools.Remove @@ -16,6 +17,7 @@ namespace Microsoft.DotNet.Tools.Remove internal override List> SubCommands => new List> { + RemoveProjectFromSolutionCommand.CreateApplication, RemoveProjectToProjectReferenceCommand.CreateApplication, }; diff --git a/src/dotnet/commands/dotnet-remove/RemoveSubCommandBase.cs b/src/dotnet/commands/dotnet-remove/RemoveSubCommandBase.cs new file mode 100644 index 000000000..63d6e24c7 --- /dev/null +++ b/src/dotnet/commands/dotnet-remove/RemoveSubCommandBase.cs @@ -0,0 +1,64 @@ +// 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 Microsoft.DotNet.Cli.CommandLine; +using Microsoft.DotNet.Cli.Utils; +using Microsoft.DotNet.Tools.Common; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +namespace Microsoft.DotNet.Tools.Remove +{ + public abstract class RemoveSubCommandBase + { + protected abstract string CommandName { get; } + protected abstract string LocalizedDisplayName { get; } + protected abstract string LocalizedDescription { get; } + protected abstract string LocalizedHelpText { get; } + internal abstract void AddCustomOptions(CommandLineApplication app); + protected abstract IRemoveSubCommand CreateIRemoveSubCommand(string fileOrDirectory); + + internal CommandLineApplication Create(CommandLineApplication parentApp) + { + CommandLineApplication app = parentApp.Command(CommandName, throwOnUnexpectedArg: false); + app.FullName = LocalizedDisplayName; + app.Description = LocalizedDescription; + app.HandleRemainingArguments = true; + app.ArgumentSeparatorHelpText = LocalizedHelpText; + + app.HelpOption("-h|--help"); + + AddCustomOptions(app); + + app.OnExecute(() => { + try + { + if (!parentApp.Arguments.Any()) + { + throw new GracefulException(CommonLocalizableStrings.RequiredArgumentNotPassed, Constants.ProjectOrSolutionArgumentName); + } + + var projectOrDirectory = parentApp.Arguments.First().Value; + if (string.IsNullOrEmpty(projectOrDirectory)) + { + projectOrDirectory = PathUtility.EnsureTrailingSlash(Directory.GetCurrentDirectory()); + } + + var removeSubCommand = CreateIRemoveSubCommand(projectOrDirectory); + removeSubCommand.Remove(app.RemainingArguments); + + return 0; + } + catch (GracefulException e) + { + Reporter.Error.WriteLine(e.Message.Red()); + app.ShowHelp(); + return 1; + } + }); + + return app; + } + } +} diff --git a/src/dotnet/commands/dotnet-remove/dotnet-remove-p2p/LocalizableStrings.cs b/src/dotnet/commands/dotnet-remove/dotnet-remove-p2p/LocalizableStrings.cs index 3cedc8539..9185548e4 100644 --- a/src/dotnet/commands/dotnet-remove/dotnet-remove-p2p/LocalizableStrings.cs +++ b/src/dotnet/commands/dotnet-remove/dotnet-remove-p2p/LocalizableStrings.cs @@ -9,7 +9,5 @@ namespace Microsoft.DotNet.Tools.Remove.ProjectToProjectReference public const string AppHelpText = "Project to project references to remove"; public const string CmdFrameworkDescription = "Remove reference only when targetting a specific framework"; - - public const string SpecifyAtLeastOneReferenceToRemove = "You must specify at least one reference to delete. Please run dotnet delete --help for more information."; } } diff --git a/src/dotnet/commands/dotnet-remove/dotnet-remove-p2p/Program.cs b/src/dotnet/commands/dotnet-remove/dotnet-remove-p2p/Program.cs index 9f9607240..e73d1d4e6 100644 --- a/src/dotnet/commands/dotnet-remove/dotnet-remove-p2p/Program.cs +++ b/src/dotnet/commands/dotnet-remove/dotnet-remove-p2p/Program.cs @@ -4,73 +4,66 @@ using Microsoft.Build.Evaluation; using Microsoft.DotNet.Cli.CommandLine; using Microsoft.DotNet.Cli.Utils; -using Microsoft.DotNet.Tools.Common; using System.Collections.Generic; -using System.IO; -using System.Linq; +using Microsoft.DotNet.Tools.Remove; namespace Microsoft.DotNet.Tools.Remove.ProjectToProjectReference { - public class RemoveProjectToProjectReferenceCommand + public class RemoveProjectToProjectReference : IRemoveSubCommand { - internal static CommandLineApplication CreateApplication(CommandLineApplication parentApp) + private CommandOption _frameworkOption; + private MsbuildProject _msbuildProj; + + internal RemoveProjectToProjectReference(string fileOrDirectory, CommandOption frameworkOption) { - CommandLineApplication app = parentApp.Command("p2p", throwOnUnexpectedArg: false); - app.FullName = LocalizableStrings.AppFullName; - app.Description = LocalizableStrings.AppDescription; - app.HandleRemainingArguments = true; - app.ArgumentSeparatorHelpText = LocalizableStrings.AppHelpText; + _msbuildProj = MsbuildProject.FromFileOrDirectory(new ProjectCollection(), fileOrDirectory); + _frameworkOption = frameworkOption; + } - app.HelpOption("-h|--help"); + public void Remove(IList references) + { + if (references.Count == 0) + { + throw new GracefulException(CommonLocalizableStrings.SpecifyAtLeastOneReferenceToRemove); + } - CommandOption frameworkOption = app.Option( + int numberOfRemovedReferences = _msbuildProj.RemoveProjectToProjectReferences( + _frameworkOption.Value(), + references); + + if (numberOfRemovedReferences != 0) + { + _msbuildProj.ProjectRootElement.Save(); + } + } + } + + public class RemoveProjectToProjectReferenceCommand : RemoveSubCommandBase + { + private CommandOption _frameworkOption; + + protected override string CommandName => "p2p"; + protected override string LocalizedDisplayName => LocalizableStrings.AppFullName; + protected override string LocalizedDescription => LocalizableStrings.AppDescription; + protected override string LocalizedHelpText => LocalizableStrings.AppHelpText; + + internal override void AddCustomOptions(CommandLineApplication app) + { + _frameworkOption = app.Option( $"-f|--framework <{CommonLocalizableStrings.CmdFramework}>", LocalizableStrings.CmdFrameworkDescription, CommandOptionType.SingleValue); + } - app.OnExecute(() => { - try - { - if (!parentApp.Arguments.Any()) - { - throw new GracefulException(CommonLocalizableStrings.RequiredArgumentNotPassed, Constants.ProjectOrSolutionArgumentName); - } + protected override IRemoveSubCommand CreateIRemoveSubCommand(string fileOrDirectory) + { + return new RemoveProjectToProjectReference(fileOrDirectory, _frameworkOption); + } - var projectOrDirectory = parentApp.Arguments.First().Value; - if (string.IsNullOrEmpty(projectOrDirectory)) - { - projectOrDirectory = PathUtility.EnsureTrailingSlash(Directory.GetCurrentDirectory()); - } - - var msbuildProj = MsbuildProject.FromFileOrDirectory(new ProjectCollection(), projectOrDirectory); - - if (app.RemainingArguments.Count == 0) - { - throw new GracefulException(LocalizableStrings.SpecifyAtLeastOneReferenceToRemove); - } - - List references = app.RemainingArguments; - - int numberOfRemovedReferences = msbuildProj.RemoveProjectToProjectReferences( - frameworkOption.Value(), - references); - - if (numberOfRemovedReferences != 0) - { - msbuildProj.ProjectRootElement.Save(); - } - - return 0; - } - catch (GracefulException e) - { - Reporter.Error.WriteLine(e.Message.Red()); - app.ShowHelp(); - return 1; - } - }); - - return app; + internal static CommandLineApplication CreateApplication(CommandLineApplication parentApp) + { + var removeSubCommand = new RemoveProjectToProjectReferenceCommand(); + return removeSubCommand.Create(parentApp); } } } diff --git a/src/dotnet/commands/dotnet-remove/dotnet-remove-proj/LocalizableStrings.cs b/src/dotnet/commands/dotnet-remove/dotnet-remove-proj/LocalizableStrings.cs new file mode 100644 index 000000000..50d12b8c0 --- /dev/null +++ b/src/dotnet/commands/dotnet-remove/dotnet-remove-proj/LocalizableStrings.cs @@ -0,0 +1,14 @@ +// 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. + +namespace Microsoft.DotNet.Tools.Remove.ProjectFromSolution +{ + internal class LocalizableStrings + { + public const string AppFullName = ".NET Remove Project from Solution Command"; + + public const string AppDescription = "Command to remove projects from a solution"; + + public const string AppHelpText = "Projects to remove from a solution"; + } +} diff --git a/src/dotnet/commands/dotnet-remove/dotnet-remove-proj/Program.cs b/src/dotnet/commands/dotnet-remove/dotnet-remove-proj/Program.cs new file mode 100644 index 000000000..e3930caa7 --- /dev/null +++ b/src/dotnet/commands/dotnet-remove/dotnet-remove-proj/Program.cs @@ -0,0 +1,101 @@ +// 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 Microsoft.DotNet.Cli.CommandLine; +using Microsoft.DotNet.Cli.Sln.Internal; +using Microsoft.DotNet.Cli.Utils; +using Microsoft.DotNet.Tools.Common; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using Microsoft.DotNet.Tools.Remove; + +namespace Microsoft.DotNet.Tools.Remove.ProjectFromSolution +{ + public class RemoveProjectFromSolution : IRemoveSubCommand + { + private SlnFile _slnFile; + + public RemoveProjectFromSolution(string fileOrDirectory) + { + _slnFile = SlnFileFactory.CreateFromFileOrDirectory(fileOrDirectory); + } + + public void Remove(IList projectPaths) + { + if (projectPaths.Count == 0) + { + throw new GracefulException(CommonLocalizableStrings.SpecifyAtLeastOneProjectToRemove); + } + + var relativeProjectPaths = projectPaths.Select((p) => + PathUtility.GetRelativePath( + PathUtility.EnsureTrailingSlash(_slnFile.BaseDirectory), + Path.GetFullPath(p))).ToList(); + + bool slnChanged = false; + foreach (var path in relativeProjectPaths) + { + slnChanged |= RemoveProject(_slnFile, path); + } + + if (slnChanged) + { + _slnFile.Write(); + } + } + + private static bool RemoveProject(SlnFile slnFile, string projectPath) + { + var projectPathNormalized = PathUtility.GetPathWithBackSlashes(projectPath); + + var projectsToRemove = slnFile.Projects.Where((p) => + string.Equals(p.FilePath, projectPathNormalized, StringComparison.OrdinalIgnoreCase)).ToList(); + + bool projectRemoved = false; + if (projectsToRemove.Count == 0) + { + Reporter.Output.WriteLine(string.Format( + CommonLocalizableStrings.ProjectReferenceCouldNotBeFound, + projectPath)); + } + else + { + foreach (var slnProject in projectsToRemove) + { + slnFile.Projects.Remove(slnProject); + Reporter.Output.WriteLine( + string.Format(CommonLocalizableStrings.ProjectReferenceRemoved, slnProject.FilePath)); + } + + projectRemoved = true; + } + + return projectRemoved; + } + } + + public class RemoveProjectFromSolutionCommand : RemoveSubCommandBase + { + protected override string CommandName => "project"; + protected override string LocalizedDisplayName => LocalizableStrings.AppFullName; + protected override string LocalizedDescription => LocalizableStrings.AppDescription; + protected override string LocalizedHelpText => LocalizableStrings.AppHelpText; + + internal override void AddCustomOptions(CommandLineApplication app) + { + } + + protected override IRemoveSubCommand CreateIRemoveSubCommand(string fileOrDirectory) + { + return new RemoveProjectFromSolution(fileOrDirectory); + } + + internal static CommandLineApplication CreateApplication(CommandLineApplication parentApp) + { + var removeSubCommand = new RemoveProjectFromSolutionCommand(); + return removeSubCommand.Create(parentApp); + } + } +}