diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/AbpCliCoreModule.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/AbpCliCoreModule.cs index c1894b2e6b..eb22185b73 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/AbpCliCoreModule.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/AbpCliCoreModule.cs @@ -22,6 +22,7 @@ namespace Volo.Abp.Cli { options.Commands["help"] = typeof(HelpCommand); options.Commands["new"] = typeof(NewCommand); + options.Commands["update"] = typeof(UpdateCommand); options.Commands["add-package"] = typeof(AddPackageCommand); options.Commands["add-module"] = typeof(AddModuleCommand); options.Commands["login"] = typeof(LoginCommand); diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/UpdateCommand.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/UpdateCommand.cs new file mode 100644 index 0000000000..b046c908e3 --- /dev/null +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/UpdateCommand.cs @@ -0,0 +1,93 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net.Http; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; +using Newtonsoft.Json; +using Volo.Abp.Cli.Args; +using Volo.Abp.Cli.ProjectBuilding.Github; +using Volo.Abp.Cli.ProjectModification; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.Cli.Commands +{ + public class UpdateCommand : IConsoleCommand, ITransientDependency + { + public ILogger Logger { get; set; } + + private readonly VoloPackagesVersionUpdater _packagesVersionUpdater; + + public UpdateCommand(VoloPackagesVersionUpdater packagesVersionUpdater) + { + _packagesVersionUpdater = packagesVersionUpdater; + + Logger = NullLogger.Instance; + } + + public async Task ExecuteAsync(CommandLineArgs commandLineArgs) + { + var includePreviews = commandLineArgs.Options.GetOrNull(Options.IncludePreviews.Short, Options.IncludePreviews.Long) != null; + + var solution = Directory.GetFiles(Directory.GetCurrentDirectory(), "*.sln").FirstOrDefault(); + + if (solution != null) + { + var version = await GetLatestAbpVersion(includePreviews); + var solutionName = Path.GetFileName(solution).RemovePostFix(".sln"); + + _packagesVersionUpdater.UpdateSolution(solution, version); + + Logger.LogInformation($"Volo packages are updated to {version} in {solutionName} solution."); + return; + } + + var project = Directory.GetFiles(Directory.GetCurrentDirectory(), "*.csproj").FirstOrDefault(); + + if (project != null) + { + var version = await GetLatestAbpVersion(includePreviews); + var projectName = Path.GetFileName(project).RemovePostFix(".csproj"); + + _packagesVersionUpdater.UpdateProject(project, version); + + Logger.LogInformation($"Volo packages are updated to {version} in {projectName} project."); + return; + } + + Logger.LogError("No solution or project found in this directory."); + } + + protected virtual async Task GetLatestAbpVersion(bool includePreviews) + { + var url = "https://api.github.com/repos/abpframework/abp/releases"; + + using (var client = new HttpClient()) + { + client.Timeout = TimeSpan.FromMinutes(30); + client.DefaultRequestHeaders.UserAgent.ParseAdd("MyAgent/1.0"); + var result = await client.GetStringAsync(url); + + var releases = JsonConvert.DeserializeObject>(result); + + if (!includePreviews) + { + releases.RemoveAll(v => v.IsPrerelease); + } + + return releases.First().Name.RemovePreFix("v"); + } + } + + public static class Options + { + public static class IncludePreviews + { + public const string Short = "p"; + public const string Long = "include-previews"; + } + } + } +} diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/VoloPackagesVersionUpdater.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/VoloPackagesVersionUpdater.cs new file mode 100644 index 0000000000..e97a901879 --- /dev/null +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/VoloPackagesVersionUpdater.cs @@ -0,0 +1,76 @@ +using System; +using System.IO; +using System.Text; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.Cli.ProjectModification +{ + public class VoloPackagesVersionUpdater : ITransientDependency + { + public void UpdateSolution(string solutionPath, string newVersion) + { + var projectPaths = ProjectFinder.GetProjectFiles(solutionPath); + + foreach (var filePath in projectPaths) + { + UpdateInternal(filePath, newVersion); + } + } + + public void UpdateProject(string projectPath, string newVersion) + { + UpdateInternal(projectPath, newVersion); + } + + protected virtual void UpdateInternal(string projectPath, string newVersion) + { + var fileContent = File.ReadAllText(projectPath); + + var content = new StringBuilder(); + var index = 0; + + while (index >= 0) + { + fileContent = fileContent.Substring(index); + content.Append(ReplaceAPackage(fileContent, newVersion, out index)); + } + + File.WriteAllText(projectPath, content.ToString()); + } + + private string ReplaceAPackage(string content, string version, out int index) + { + var packageReferenceStartText = "nclude=\"Volo."; + var returningText = new StringBuilder(); + + var indexOfPackageReference = content.IndexOf(packageReferenceStartText, StringComparison.Ordinal); + + if (indexOfPackageReference < 0) + { + index = -1; + return content; + } + + returningText.Append(content.Substring(0, indexOfPackageReference + packageReferenceStartText.Length)); + content = content.Substring(indexOfPackageReference + packageReferenceStartText.Length); + + var indexAfterQuote = content.IndexOf("\"", StringComparison.Ordinal) + 1; + + returningText.Append(content.Substring(0, indexAfterQuote)); + content = content.Substring(indexAfterQuote); + + var indexAfterSecondQuote = content.IndexOf("\"", StringComparison.Ordinal) + 1; + + returningText.Append(content.Substring(0, indexAfterSecondQuote)); + content = content.Substring(indexAfterSecondQuote); + + var indexOfThirdQuote = content.IndexOf("\"", StringComparison.Ordinal); + + returningText.Append(version); + + index = indexOfPackageReference + packageReferenceStartText.Length + indexAfterQuote + indexAfterSecondQuote + indexOfThirdQuote; + + return returningText.ToString(); + } + } +}