From 4d4dfedd59fb8ca58587eaa735a0fdecab07fc0f Mon Sep 17 00:00:00 2001 From: moozzyk Date: Thu, 14 Jan 2016 10:23:00 -0800 Subject: [PATCH] dotnet-publish-iis refactoring - moving command logic to a dedicated class - adding logic for reading webroot value from a parameter, hosting.json file and folder structure - reading application name from project.json instead of a parameter --- src/dotnet-publish-iis/Program.cs | 34 +--- src/dotnet-publish-iis/PublishIISCommand.cs | 96 +++++++++++ src/dotnet-publish-iis/WebConfigTransform.cs | 3 +- src/dotnet-publish-iis/project.json | 11 +- .../PublishIISCommandFacts.cs | 149 ++++++++++++++++++ .../WebConfigTransformFacts.cs | 7 +- .../dotnet-publish-iis.Tests.xproj | 4 +- test/dotnet-publish-iis.Tests/project.json | 3 +- 8 files changed, 266 insertions(+), 41 deletions(-) create mode 100644 src/dotnet-publish-iis/PublishIISCommand.cs create mode 100644 test/dotnet-publish-iis.Tests/PublishIISCommandFacts.cs diff --git a/src/dotnet-publish-iis/Program.cs b/src/dotnet-publish-iis/Program.cs index c8af80c90c..e053b87227 100644 --- a/src/dotnet-publish-iis/Program.cs +++ b/src/dotnet-publish-iis/Program.cs @@ -2,9 +2,6 @@ // 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.Xml; -using System.Xml.Linq; using Microsoft.Extensions.CommandLineUtils; namespace Microsoft.AspNet.Tools.PublishIIS @@ -15,46 +12,27 @@ namespace Microsoft.AspNet.Tools.PublishIIS { var app = new CommandLineApplication { - // TODO: This needs to be updated once we know how this is going to be called - Name = "dotnet(????) publish-iis", + Name = "dotnet publish-iis", FullName = "Asp.Net IIS Publisher", Description = "IIS Publisher for the Asp.Net web applications", }; app.HelpOption("-h|--help"); - var publishFolderOption = app.Option("--publish-folder", "The path to the publish output folder", CommandOptionType.SingleValue); - var appNameOption = app.Option("--application-name", "The name of the application", CommandOptionType.SingleValue); + var publishFolderOption = app.Option("--publish-folder|-p", "The path to the publish output folder", CommandOptionType.SingleValue); + var webRootOption = app.Option("--webroot|-w", "The name of webroot folder", CommandOptionType.SingleValue); + var projectPath = app.Argument("", "The path to the project (project folder or project.json) being published. If empty the current directory is used."); app.OnExecute(() => { var publishFolder = publishFolderOption.Value(); - var appName = appNameOption.Value(); - if (publishFolder == null || appName == null) + if (publishFolder == null) { app.ShowHelp(); return 2; } - XDocument webConfigXml = null; - var webConfigPath = Path.Combine(publishFolder, "wwwroot", "web.config"); - if (File.Exists(webConfigPath)) - { - try - { - webConfigXml = XDocument.Load(webConfigPath); - } - catch (XmlException) { } - } - - var transformedConfig = WebConfigTransform.Transform(webConfigXml, appName); - - using (var f = new FileStream(webConfigPath, FileMode.Create)) - { - transformedConfig.Save(f); - } - - return 0; + return new PublishIISCommand(publishFolder, projectPath.Value, webRootOption.Value()).Run(); }); try diff --git a/src/dotnet-publish-iis/PublishIISCommand.cs b/src/dotnet-publish-iis/PublishIISCommand.cs new file mode 100644 index 0000000000..7d5720c8d3 --- /dev/null +++ b/src/dotnet-publish-iis/PublishIISCommand.cs @@ -0,0 +1,96 @@ +// 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.IO; +using System.Xml; +using System.Xml.Linq; +using Microsoft.Extensions.Configuration; +using Microsoft.DotNet.ProjectModel; + +namespace Microsoft.AspNet.Tools.PublishIIS +{ + public class PublishIISCommand + { + private readonly string _publishFolder; + private readonly string _projectPath; + private readonly string _webRoot; + + public PublishIISCommand(string publishFolder, string projectPath, string webRoot) + { + _publishFolder = publishFolder; + _projectPath = projectPath; + _webRoot = webRoot; + } + + public int Run() + { + var applicationBasePath = GetApplicationBasePath(); + var webRoot = GetWebRoot(applicationBasePath); + + XDocument webConfigXml = null; + var webConfigPath = Path.Combine(_publishFolder, webRoot, "web.config"); + if (File.Exists(webConfigPath)) + { + try + { + webConfigXml = XDocument.Load(webConfigPath); + } + catch (XmlException) { } + } + + var applicationName = Path.ChangeExtension(GetApplicationName(applicationBasePath), "exe"); + var transformedConfig = WebConfigTransform.Transform(webConfigXml, applicationName); + + using (var f = new FileStream(webConfigPath, FileMode.Create)) + { + transformedConfig.Save(f); + } + + return 0; + } + + private string GetApplicationBasePath() + { + if (!string.IsNullOrEmpty(_projectPath)) + { + var fullProjectPath = Path.GetFullPath(_projectPath); + + return Path.GetFileName(fullProjectPath) == "project.json" + ? Path.GetDirectoryName(fullProjectPath) + : fullProjectPath; + } + + return Directory.GetCurrentDirectory(); + } + + private string GetApplicationName(string applicationBasePath) + { + return ProjectReader.GetProject(Path.Combine(applicationBasePath, "project.json")).Name; + } + + private string GetWebRoot(string applicationBasePath) + { + if (!string.IsNullOrEmpty(_webRoot)) + { + return _webRoot; + } + + var builder = new ConfigurationBuilder() + .AddJsonFile(Path.Combine(applicationBasePath, "hosting.json"), optional: true); + + var webroot = builder.Build()["webroot"]; + + if (!string.IsNullOrEmpty(webroot)) + { + return webroot; + } + + if (Directory.Exists(Path.Combine(applicationBasePath, "wwwroot"))) + { + return "wwwroot"; + } + + return string.Empty; + } + } +} diff --git a/src/dotnet-publish-iis/WebConfigTransform.cs b/src/dotnet-publish-iis/WebConfigTransform.cs index 02bcc647f9..4e6ec51cc9 100644 --- a/src/dotnet-publish-iis/WebConfigTransform.cs +++ b/src/dotnet-publish-iis/WebConfigTransform.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.IO; using System.Linq; using System.Xml.Linq; @@ -56,7 +57,7 @@ namespace Microsoft.AspNet.Tools.PublishIIS private static void TransformHttpPlatform(XElement httpPlatformElement, string appName) { - httpPlatformElement.SetAttributeValue("processPath", $@"..\wwwroot\{appName}"); + httpPlatformElement.SetAttributeValue("processPath", Path.Combine("..", appName)); SetAttributeValueIfEmpty(httpPlatformElement, "stdoutLogEnabled", "false"); SetAttributeValueIfEmpty(httpPlatformElement, "startupTimeLimit", "3600"); } diff --git a/src/dotnet-publish-iis/project.json b/src/dotnet-publish-iis/project.json index ff5be4addd..eefde53ba1 100644 --- a/src/dotnet-publish-iis/project.json +++ b/src/dotnet-publish-iis/project.json @@ -6,14 +6,15 @@ }, "dependencies": { - "NETStandard.Library": "1.0.0-*", "System.Xml.XDocument": "4.0.11-*", - "Microsoft.Extensions.CommandLineUtils": "1.0.0-*" + "Microsoft.Extensions.CommandLineUtils": "1.0.0-*", + "Microsoft.Extensions.Configuration.Json": "1.0.0-*", + "Microsoft.DotNet.ProjectModel": "1.0.0-*" }, "frameworks": { - "dnxcore50": { - "Microsoft.NETCore.Platforms": "1.0.0-*" - } + "dnxcore50": { + "Microsoft.NETCore.Platforms": "1.0.0-*" + } } } diff --git a/test/dotnet-publish-iis.Tests/PublishIISCommandFacts.cs b/test/dotnet-publish-iis.Tests/PublishIISCommandFacts.cs new file mode 100644 index 0000000000..152b6e3473 --- /dev/null +++ b/test/dotnet-publish-iis.Tests/PublishIISCommandFacts.cs @@ -0,0 +1,149 @@ +using Xunit; +using System.IO; +using System.Linq; +using System.Xml.Linq; +using System; + +namespace Microsoft.AspNet.Tools.PublishIIS.Tests +{ + public class PublishIISCommandFacts + { + private class Folders + { + public string TestRoot; + public string PublishOutput; + public string ProjectPath; + } + + [Fact] + public void PublishIIS_uses_default_values_if_options_not_specified() + { + var webRoot = "wwwroot"; + var folders = CreateTestDir("{}", webRoot); + + new PublishIISCommand(folders.PublishOutput, folders.ProjectPath, null).Run(); + + var processPath = (string)GetPublishedWebConfig(folders.PublishOutput, webRoot) + .Descendants("httpPlatform").Attributes("processPath").Single(); + + Assert.Equal($@"..\projectDir.exe", processPath); + + Directory.Delete(folders.TestRoot, recursive: true); + } + + [Fact] + public void PublishIIS_reads_application_name_from_project_json_if_exists() + { + var webRoot = "wwwroot"; + var folders = CreateTestDir(@"{ ""name"": ""awesomeApp""}", webRoot); + + new PublishIISCommand(folders.PublishOutput, folders.ProjectPath, null).Run(); + + var processPath = (string)GetPublishedWebConfig(folders.PublishOutput, webRoot) + .Descendants("httpPlatform").Attributes("processPath").Single(); + + Assert.Equal($@"..\awesomeApp.exe", processPath); + + Directory.Delete(folders.TestRoot, recursive: true); + } + + [Fact] + public void PublishIIS_uses_webroot_from_hosting_json() + { + var webRoot = "mywebroot"; + var folders = CreateTestDir("{}", webRoot); + File.WriteAllText(Path.Combine(folders.ProjectPath, "hosting.json"), $"{{ \"webroot\": \"{webRoot}\"}}"); + + new PublishIISCommand(folders.PublishOutput, folders.ProjectPath, null).Run(); + + var processPath = (string)GetPublishedWebConfig(folders.PublishOutput, webRoot) + .Descendants("httpPlatform").Attributes("processPath").Single(); + + Assert.Equal($@"..\projectDir.exe", processPath); + + Directory.Delete(folders.TestRoot, recursive: true); + } + + [Fact] + public void PublishIIS_webroot_switch_takes_precedence_over_hosting_json() + { + var webRoot = "mywebroot"; + var folders = CreateTestDir("{}", webRoot); + File.WriteAllText(Path.Combine(folders.ProjectPath, "hosting.json"), $"{{ \"webroot\": \"wwwroot\"}}"); + + new PublishIISCommand(folders.PublishOutput, folders.ProjectPath, webRoot).Run(); + + var processPath = (string)GetPublishedWebConfig(folders.PublishOutput, webRoot) + .Descendants("httpPlatform").Attributes("processPath").Single(); + + Assert.Equal($@"..\projectDir.exe", processPath); + + Directory.Delete(folders.TestRoot, recursive: true); + } + + [Fact] + public void PublishIIS_accepts_path_to_project_json_as_project_path() + { + var webRoot = "wwwroot"; + var folders = CreateTestDir("{}", webRoot); + + new PublishIISCommand(folders.PublishOutput, Path.Combine(folders.ProjectPath, "project.json"), null).Run(); + + var processPath = (string)GetPublishedWebConfig(folders.PublishOutput, webRoot) + .Descendants("httpPlatform").Attributes("processPath").Single(); + + Assert.Equal($@"..\projectDir.exe", processPath); + + Directory.Delete(folders.TestRoot, recursive: true); + } + + [Fact] + public void PublishIIS_modifies_existing_web_config() + { + var webRoot = "wwwroot"; + var folders = CreateTestDir("{}", webRoot); + + File.WriteAllText(Path.Combine(folders.PublishOutput, webRoot, "web.config"), +@" + + + + + + +"); + + new PublishIISCommand(folders.PublishOutput, Path.Combine(folders.ProjectPath, "project.json"), null).Run(); + + var httpPlatformElement = GetPublishedWebConfig(folders.PublishOutput, webRoot) + .Descendants("httpPlatform").Single(); + + Assert.Equal($@"..\projectDir.exe", (string)httpPlatformElement.Attribute("processPath")); + Assert.Equal($@"1234", (string)httpPlatformElement.Attribute("startupTimeLimit")); + + Directory.Delete(folders.TestRoot, recursive: true); + } + + private XDocument GetPublishedWebConfig(string publishOut, string webRoot) + { + return XDocument.Load(Path.Combine(publishOut, webRoot, "web.config")); + } + + private Folders CreateTestDir(string projectJson, string webRoot) + { + var testRoot = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); + Directory.CreateDirectory(testRoot); + + var projectPath = Path.Combine(testRoot, "projectDir"); + Directory.CreateDirectory(projectPath); + Directory.CreateDirectory(Path.Combine(projectPath, webRoot)); + File.WriteAllText(Path.Combine(projectPath, "project.json"), projectJson); + + var publishOut = Path.Combine(testRoot, "publishOut"); + Directory.CreateDirectory(publishOut); + Directory.CreateDirectory(Path.Combine(publishOut, webRoot)); + + return new Folders { TestRoot = testRoot, ProjectPath = projectPath, PublishOutput = publishOut }; + } + } +} diff --git a/test/dotnet-publish-iis.Tests/WebConfigTransformFacts.cs b/test/dotnet-publish-iis.Tests/WebConfigTransformFacts.cs index 74dc5e518d..44775a2eb8 100644 --- a/test/dotnet-publish-iis.Tests/WebConfigTransformFacts.cs +++ b/test/dotnet-publish-iis.Tests/WebConfigTransformFacts.cs @@ -1,7 +1,6 @@ using Xunit; using System.Linq; using System.Xml.Linq; -using Microsoft.AspNet.Tools.PublishIIS; namespace Microsoft.AspNet.Tools.PublishIIS.Tests { @@ -13,7 +12,7 @@ namespace Microsoft.AspNet.Tools.PublishIIS.Tests - + "); @@ -71,7 +70,7 @@ namespace Microsoft.AspNet.Tools.PublishIIS.Tests (string)WebConfigTransform.Transform(WebConfigTemplate, "app.exe") .Descendants("httpPlatform").Single().Attribute("processPath"); - Assert.Equal(@"..\wwwroot\app.exe", newProcessPath); + Assert.Equal(@"..\app.exe", newProcessPath); } [Fact] @@ -94,7 +93,7 @@ namespace Microsoft.AspNet.Tools.PublishIIS.Tests input.Descendants("httpPlatform").Single().Add(envVarsElement); Assert.True(XNode.DeepEquals(envVarsElement, - WebConfigTransform.Transform(input, "app.exe").Descendants("httpPlatform").Single().Elements().Single())); + WebConfigTransform.Transform(input, "app.exe").Descendants("httpPlatform").Elements().Single())); } private bool VerifyMissingElementCreated(params string[] elementNames) diff --git a/test/dotnet-publish-iis.Tests/dotnet-publish-iis.Tests.xproj b/test/dotnet-publish-iis.Tests/dotnet-publish-iis.Tests.xproj index fb8bd03ebf..2d98be76ad 100644 --- a/test/dotnet-publish-iis.Tests/dotnet-publish-iis.Tests.xproj +++ b/test/dotnet-publish-iis.Tests/dotnet-publish-iis.Tests.xproj @@ -11,9 +11,11 @@ ..\..\artifacts\obj\$(MSBuildProjectName) ..\..\artifacts\bin\$(MSBuildProjectName)\ - 2.0 + + + \ No newline at end of file diff --git a/test/dotnet-publish-iis.Tests/project.json b/test/dotnet-publish-iis.Tests/project.json index 17e4931a2d..dcf7c6c57a 100644 --- a/test/dotnet-publish-iis.Tests/project.json +++ b/test/dotnet-publish-iis.Tests/project.json @@ -7,8 +7,7 @@ "frameworks": { "dnxcore50": { "dependencies": { - "Microsoft.NETCore.Platforms": "1.0.0-*", - "xunit.runner.aspnet": "2.0.0-aspnet-*" + "xunit.runner.aspnet": "2.0.0-aspnet-*" } } },