Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -480,11 +480,35 @@ public string DefaultCommandPrefix
/// </summary>
/// <param name="name">The string to quote</param>
/// <returns>The quoted string</returns>
private string QuoteName(object name)
private string QuoteName(string name)
{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The method comments should be updated to reflect string or URI.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will fix

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The method comments should be updated to reflect string or URI. Better would be to have two explicit overloads and remove the 'object' overload since I don't think anything other than uri and string are expected.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I looked through the calls to QuoteName() and I believe you are right that it's only a string or Uri. I'll separate it.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually Version is another type that needs to be supported

if (name == null)
return "''";
return "'" + name.ToString().Replace("'", "''") + "'";
return ("'" + name.ToString().Replace("'", "''") + "'");
}

/// <summary>
/// Return a single-quoted string using the AbsoluteUri member to ensure it is escaped correctly
/// </summary>
/// <param name="name">The Uri to quote</param>
/// <returns>The quoted AbsoluteUri</returns>
private string QuoteName(Uri name)
{
if (name == null)
return "''";
return QuoteName(name.AbsoluteUri);
}

/// <summary>
/// Return a single-quoted string from a Version object
/// </summary>
/// <param name="name">The Version object to quote</param>
/// <returns>The quoted Version string</returns>
private string QuoteName(Version name)
{
if (name == null)
return "''";
return QuoteName(name.ToString());
}

/// <summary>
Expand Down Expand Up @@ -877,6 +901,10 @@ protected override void EndProcessing()
ValidateUriParameterValue(ProjectUri, "ProjectUri");
ValidateUriParameterValue(LicenseUri, "LicenseUri");
ValidateUriParameterValue(IconUri, "IconUri");
if (_helpInfoUri != null)
{
ValidateUriParameterValue(new Uri(_helpInfoUri), "HelpInfoUri");
}

if (CompatiblePSEditions != null && (CompatiblePSEditions.Distinct(StringComparer.OrdinalIgnoreCase).Count() != CompatiblePSEditions.Count()))
{
Expand Down Expand Up @@ -949,7 +977,7 @@ protected override void EndProcessing()

BuildModuleManifest(result, "RootModule", Modules.RootModule, !string.IsNullOrEmpty(_rootModule), () => QuoteName(_rootModule), streamWriter);

BuildModuleManifest(result, "ModuleVersion", Modules.ModuleVersion, _moduleVersion != null && !string.IsNullOrEmpty(_moduleVersion.ToString()), () => QuoteName(_moduleVersion.ToString()), streamWriter);
BuildModuleManifest(result, "ModuleVersion", Modules.ModuleVersion, _moduleVersion != null && !string.IsNullOrEmpty(_moduleVersion.ToString()), () => QuoteName(_moduleVersion), streamWriter);

BuildModuleManifest(result, "CompatiblePSEditions", Modules.CompatiblePSEditions, _compatiblePSEditions != null && _compatiblePSEditions.Length > 0, () => QuoteNames(_compatiblePSEditions, streamWriter), streamWriter);

Expand All @@ -973,7 +1001,7 @@ protected override void EndProcessing()

BuildModuleManifest(result, "CLRVersion", StringUtil.Format(Modules.CLRVersion, Modules.PrerequisiteForDesktopEditionOnly), _ClrVersion != null && !string.IsNullOrEmpty(_ClrVersion.ToString()), () => QuoteName(_ClrVersion), streamWriter);

BuildModuleManifest(result, "ProcessorArchitecture", Modules.ProcessorArchitecture, _processorArchitecture.HasValue, () => QuoteName(_processorArchitecture), streamWriter);
BuildModuleManifest(result, "ProcessorArchitecture", Modules.ProcessorArchitecture, _processorArchitecture.HasValue, () => QuoteName(_processorArchitecture.ToString()), streamWriter);

BuildModuleManifest(result, "RequiredModules", Modules.RequiredModules, _requiredModules != null && _requiredModules.Length > 0, () => QuoteModules(_requiredModules, streamWriter), streamWriter);

Expand Down Expand Up @@ -1003,7 +1031,7 @@ protected override void EndProcessing()

BuildPrivateDataInModuleManifest(result, streamWriter);

BuildModuleManifest(result, "HelpInfoURI", Modules.HelpInfoURI, !string.IsNullOrEmpty(_helpInfoUri), () => QuoteName(_helpInfoUri), streamWriter);
BuildModuleManifest(result, "HelpInfoURI", Modules.HelpInfoURI, !string.IsNullOrEmpty(_helpInfoUri), () => QuoteName((_helpInfoUri != null) ? new Uri(_helpInfoUri) : null), streamWriter);

BuildModuleManifest(result, "DefaultCommandPrefix", Modules.DefaultCommandPrefix, !string.IsNullOrEmpty(_defaultCommandPrefix), () => QuoteName(_defaultCommandPrefix), streamWriter);

Expand Down Expand Up @@ -1128,7 +1156,7 @@ private void ValidateUriParameterValue(Uri uri, string parameterName)
{
Dbg.Assert(!String.IsNullOrWhiteSpace(parameterName), "parameterName should not be null or whitespace");

if (uri != null && !Uri.IsWellFormedUriString(uri.ToString(), UriKind.Absolute))
if (uri != null && !Uri.IsWellFormedUriString(uri.AbsoluteUri, UriKind.Absolute))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're using inconsistent comparison to null ordering. (i.e., value != null versus null != value). Suggest picking one.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer null on the left, but most of the code in this file has it on the right, I'll change my usage to make it consistent

{
var message = StringUtil.Format(Modules.InvalidParameterValue, uri);
var ioe = new InvalidOperationException(message);
Expand Down
30 changes: 30 additions & 0 deletions test/powershell/engine/Module/NewModuleManifest.Tests.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
Import-Module $PSScriptRoot\..\..\Common\Test.Helpers.psm1

Describe "New-ModuleManifest tests" -tags "CI" {
BeforeEach {
New-Item -ItemType Directory -Path testdrive:/module
$testModulePath = "testdrive:/module/test.psd1"
}

AfterEach {
Remove-Item -Recurse -Force -ErrorAction SilentlyContinue testdrive:/module
}

It "Uris with spaces are allowed and escaped correctly" {
$testUri = [Uri]"http://foo.com/hello world"
$absoluteUri = $testUri.AbsoluteUri

New-ModuleManifest -Path $testModulePath -ProjectUri $testUri -LicenseUri $testUri -IconUri $testUri -HelpInfoUri $testUri
$module = Test-ModuleManifest -Path $testModulePath
$module.HelpInfoUri | Should BeExactly $absoluteUri
$module.PrivateData.PSData.IconUri | Should BeExactly $absoluteUri
$module.PrivateData.PSData.LicenseUri | Should BeExactly $absoluteUri
$module.PrivateData.PSData.ProjectUri | Should BeExactly $absoluteUri
}

It "Relative URIs are not allowed" {
$testUri = [Uri]"../foo"

{ New-ModuleManifest -Path $testModulePath -ProjectUri $testUri -LicenseUri $testUri -IconUri $testUri } | ShouldBeErrorId "System.InvalidOperationException,Microsoft.PowerShell.Commands.NewModuleManifestCommand"
}
}