Skip to content

Commit

Permalink
Merge pull request #398 from nguerrera/resx
Browse files Browse the repository at this point in the history
Make all SDK errors localizable
  • Loading branch information
nguerrera committed Nov 17, 2016
2 parents 23c6ba1 + 6ee174c commit aca5d15
Show file tree
Hide file tree
Showing 25 changed files with 584 additions and 85 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public bool Process(string originalAssetPath, string relativeOutputPath, out str
string value;
if (!_preprocessorValues.TryGetValue(token, out value))
{
throw new Exception($"The token '${token}$' is unrecognized");
throw new InvalidDataException($"The token '${token}$' is unrecognized");
}
return value;
});
Expand Down
32 changes: 32 additions & 0 deletions src/Tasks/Microsoft.NET.Build.Tasks/BuildErrorException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// 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.Globalization;

namespace Microsoft.NET.Build.Tasks
{
/// <summary>
/// Represents an error that is neither avoidable in all cases nor indicative of a bug in this library.
/// It will be logged as a plain build error without the exception type or stack.
/// </summary>
internal class BuildErrorException : Exception
{
public BuildErrorException()
{
}

public BuildErrorException(string message) : base(message)
{
}

public BuildErrorException(string message, Exception innerException) : base(message, innerException)
{
}

public BuildErrorException(string format, params string[] args)
: this(string.Format(CultureInfo.CurrentCulture, format, args))
{
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -421,7 +421,7 @@ private static void EnsureProjectInfo(SingleProjectInfo referenceProjectInfo, st
{
if (referenceProjectInfo == null)
{
throw new Exception($"Could not find valid a SingleProjectInfo for LockFileTargetLibrary '{libraryName}'");
throw new BuildErrorException(Strings.CannotFindProjectInfo, libraryName);
}
}

Expand All @@ -430,7 +430,7 @@ private SingleProjectInfo GetProjectInfo(LockFileLibrary library)
string projectPath = library.MSBuildProject;
if (string.IsNullOrEmpty(projectPath))
{
throw new Exception($"Could not find valid 'MSBuildProject' for project LockFileTargetLibrary '{library.Name}'");
throw new BuildErrorException(Strings.CannotFindProjectInfo, library.Name);
}

string mainProjectDirectory = Path.GetDirectoryName(_mainProjectInfo.ProjectPath);
Expand All @@ -440,7 +440,7 @@ private SingleProjectInfo GetProjectInfo(LockFileLibrary library)
if (_referenceProjectInfos?.TryGetValue(fullProjectPath, out referenceProjectInfo) != true ||
referenceProjectInfo == null)
{
throw new Exception($"Could not find valid a SingleProjectInfo for project '{fullProjectPath}'");
throw new BuildErrorException(Strings.CannotFindProjectInfo, fullProjectPath);
}

return referenceProjectInfo;
Expand Down
2 changes: 1 addition & 1 deletion src/Tasks/Microsoft.NET.Build.Tasks/FileGroup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ public static string GetTypeMetadata(this FileGroup fileGroup)
return package.FrameworkAssemblies.Select(c => Tuple.Create(c, _emptyProperties));

default:
throw new Exception($"Unexpected file group in project.lock.json target library {package.Name}");
throw new ArgumentOutOfRangeException(nameof(fileGroup));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ protected override void ExecuteCore()

if (!result.Success)
{
Log.LogError($"Errors ocurred when emitting satellite assembly - {satelliteAssembly}");
Log.LogError(Strings.ErrorsOccurredWhenEmittingSatelliteAssembly, satelliteAssembly);
foreach (var diagnostic in result.Diagnostics)
{
Log.LogError(diagnostic.ToString());
Expand Down
13 changes: 6 additions & 7 deletions src/Tasks/Microsoft.NET.Build.Tasks/GetAssemblyVersion.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,14 @@ public class GetAssemblyVersion : TaskBase

protected override void ExecuteCore()
{
// Using try/catch instead of TryParse so that we don't need to maintain our own error message here.
try
NuGetVersion nugetVersion;
if (!NuGet.Versioning.NuGetVersion.TryParse(NuGetVersion, out nugetVersion))
{
AssemblyVersion = NuGet.Versioning.NuGetVersion.Parse(NuGetVersion).Version.ToString();
}
catch (ArgumentException ex)
{
Log.LogError(ex.Message);
Log.LogError(Strings.InvalidNuGetVersionString, NuGetVersion);
return;
}

AssemblyVersion = nugetVersion.Version.ToString();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,7 @@ protected override void ExecuteCore()
{
if (PossibleTargetFrameworks.Length < 1)
{
// TODO: localize: https://github.com/dotnet/sdk/issues/33
Log.LogError("At least one possible target framework must be specified.");
Log.LogError(Strings.AtLeastOneTargetFrameworkMustBeSpecified);
return;
}

Expand All @@ -59,8 +58,7 @@ protected override void ExecuteCore()
var nearestNuGetFramework = new FrameworkReducer().GetNearest(referringNuGetFramework, possibleNuGetFrameworks);
if (nearestNuGetFramework == null)
{
// TODO: localize: https://github.com/dotnet/sdk/issues/33
Log.LogError($"Project '{ProjectFilePath}' has no target framework compatible with '{ReferringTargetFramework}'.");
Log.LogError(Strings.NoCompatibleTargetFramework, ProjectFilePath, ReferringTargetFramework);
return;
}

Expand All @@ -81,8 +79,7 @@ private NuGetFramework ParseFramework(string name)

if (framework == null)
{
// TODO: localize: https://github.com/dotnet/sdk/issues/33
Log.LogError($"Invalid framework name: '{framework}'.");
Log.LogError(Strings.InvalidFrameworkName, framework);
}

return framework;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ public interface IContentAssetPreprocessor
/// result to specified output path
/// </summary>
/// <returns>true if an asset is written, false otherwise</returns>
/// <exception cref="InvalidOperationException"><see cref="ConfigurePreprocessor"/> was not called.</exception>
bool Process(string originalAssetPath, string relativeOutputPath, out string pathToFinalAsset);
}
}
6 changes: 2 additions & 4 deletions src/Tasks/Microsoft.NET.Build.Tasks/LockFileCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,7 @@ public LockFile GetLockFile(string path)
{
if (!Path.IsPathRooted(path))
{
throw new ArgumentException(
$"The path '{path}' specified to LockFileCache.GetLockFile is not rooted. Only full paths are supported.",
nameof(path));
throw new BuildErrorException(Strings.AssetsFilePathNotRooted, path);
}

string lockFileKey = GetTaskObjectKey(path);
Expand Down Expand Up @@ -54,7 +52,7 @@ private LockFile LoadLockFile(string path)
{
if (!File.Exists(path))
{
throw new ReportUserErrorException($"Assets file '{path}' couldn't be found. Run a NuGet package restore to generate this file.");
throw new BuildErrorException(Strings.AssetsFileNotFound, path);
}

// TODO - https://github.com/dotnet/sdk/issues/18 adapt task logger to Nuget Logger
Expand Down
4 changes: 1 addition & 3 deletions src/Tasks/Microsoft.NET.Build.Tasks/LockFileExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,7 @@ public static class LockFileExtensions
frameworkString :
$"{frameworkString}/{runtime}";

throw new ReportUserErrorException($"Assets file '{lockFile.Path}' doesn't have a target for '{targetMoniker}'." +
$" Ensure you have restored this project for TargetFramework='{framework.GetShortFolderName()}'" +
$" and RuntimeIdentifier='{runtime}'.");
throw new BuildErrorException(Strings.AssetsFileMissingTarget, lockFile.Path, targetMoniker, framework.GetShortFolderName(), runtime);
}

return new ProjectContext(lockFile, lockFileTarget, platformLibraryName);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,16 @@
</PackageReference>
</ItemGroup>
<ItemGroup>
<Compile Include="NETSdkError.cs" />
<Compile Include="LockFileLookup.cs" />
<Compile Include="FrameworkReferenceResolver.cs" />
<Compile Include="ReportUserErrorException.cs" />
<Compile Include="BuildErrorException.cs" />
<Compile Include="ReferenceInfo.cs" />
<Compile Include="Resources\Strings.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Strings.resx</DependentUpon>
</Compile>
<Compile Include="TaskBase.cs" />
<Compile Include="PackageReferenceConverter.cs" />
<Compile Include="NugetContentAssetPreprocessor.cs" />
Expand Down Expand Up @@ -131,6 +137,13 @@
<Compile Include="ResolvePackageDependencies.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Resources\Strings.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Strings.Designer.cs</LastGenOutput>
<CustomToolNamespace>Microsoft.NET.Build.Tasks</CustomToolNamespace>
</EmbeddedResource>
</ItemGroup>
<Import Project="..\..\..\build\Targets\Signing.Imports.targets" />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
36 changes: 36 additions & 0 deletions src/Tasks/Microsoft.NET.Build.Tasks/NETSdkError.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// 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.Build.Framework;
using Newtonsoft.Json;
using System;
using System.Globalization;

namespace Microsoft.NET.Build.Tasks
{
/// <summary>
/// Provides a localizable mechanism for logging an error from the SDK targets.
/// </summary>
public class NETSdkError : TaskBase
{
/// <summary>
/// The name of the resource in Strings.resx that contains the desired error message.
/// </summary>
[Required]
public string ResourceName { get; set; }

/// <summary>
/// The arguments provided to <see cref="string.Format"/> along with the retrieved resource as the format.
/// </summary>
public string[] FormatArguments { get; set; }

protected override void ExecuteCore()
{
string format = Strings.ResourceManager.GetString(ResourceName, Strings.Culture);
string[] arguments = FormatArguments ?? Array.Empty<string>();
string message = string.Format(CultureInfo.CurrentCulture, format, arguments);

Log.LogError(message);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@
using NuGet.Common;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;

namespace Microsoft.NET.Build.Tasks
{
public class NugetContentAssetPreprocessor : IContentAssetPreprocessor
internal class NugetContentAssetPreprocessor : IContentAssetPreprocessor
{
private Dictionary<string, string> _preprocessorValues = new Dictionary<string, string>();
private string _preprocessedOutputDirectory = null;
Expand All @@ -26,7 +27,7 @@ public bool Process(string originalAssetPath, string relativeOutputPath, out str
{
if (_preprocessedOutputDirectory == null)
{
throw new Exception($"{nameof(NugetContentAssetPreprocessor)} should be configured before any assets are processed");
throw new InvalidOperationException(Strings.AssetPreprocessorMustBeConfigured);
}

bool fileWritten = false;
Expand All @@ -43,7 +44,7 @@ public bool Process(string originalAssetPath, string relativeOutputPath, out str
string value;
if (!_preprocessorValues.TryGetValue(token, out value))
{
throw new Exception($"The token '${token}$' is unrecognized");
throw new BuildErrorException(Strings.UnrecognizedPreprocessorToken, $"${token}$", originalAssetPath);
}
return value;
});
Expand Down
14 changes: 5 additions & 9 deletions src/Tasks/Microsoft.NET.Build.Tasks/ProduceContentAssets.cs
Original file line number Diff line number Diff line change
Expand Up @@ -154,9 +154,7 @@ private void ProcessContentFileInputs()

foreach (var duplicatedPreprocessorKey in duplicatedPreprocessorKeys)
{
Log.LogWarning(
$"The preprocessor token '{duplicatedPreprocessorKey}' has been given more than one value." +
$" Choosing '{preprocessorValues[duplicatedPreprocessorKey]}' as the value.");
Log.LogWarning(Strings.DuplicatePreprocessorToken, duplicatedPreprocessorKey, preprocessorValues[duplicatedPreprocessorKey]);
}

AssetPreprocessor.ConfigurePreprocessor(ContentPreprocessorOutputDirectory, preprocessorValues);
Expand Down Expand Up @@ -209,7 +207,7 @@ private void ProduceContentAsset(ITaskItem contentFile)
string resolvedPath;
if (!_resolvedPaths.TryGetValue(contentFile.ItemSpec, out resolvedPath))
{
Log.LogWarning($"Unable to find resolved path for {contentFile.ItemSpec}");
Log.LogWarning(Strings.UnableToFindResolvedPath, contentFile.ItemSpec);
return;
}

Expand All @@ -221,13 +219,12 @@ private void ProduceContentAsset(ITaskItem contentFile)
{
if (string.IsNullOrEmpty(ContentPreprocessorOutputDirectory))
{
throw new Exception($"The {nameof(ContentPreprocessorOutputDirectory)} property must be set in order to consume preprocessed content");
throw new BuildErrorException(Strings.ContentPreproccessorParameterRequired, nameof(ProduceContentAssets), nameof(ContentPreprocessorOutputDirectory));
}

string [] parts = parentPackage?.Split('/');
if (parts == null)
{
throw new Exception($"Content File {contentFile.ItemSpec} does not contain expected parent package information");
throw new BuildErrorException(Strings.ContentFileDoesNotContainExpectedParentPackageInformation, contentFile.ItemSpec);
}

// We need the preprocessed output, so let's run the preprocessor here
Expand All @@ -252,8 +249,7 @@ private void ProduceContentAsset(ITaskItem contentFile)
}
else
{
Log.LogWarning($"Content Item for {pathToFinalAsset} sets 'copyToOutput' " +
"but does not provide an 'outputPath' or 'ppOutputPath'");
Log.LogWarning(Strings.ContentItemDoesNotProvideOutputPath, pathToFinalAsset, "copyToOutput", "outputPath", "ppOutputPath");
}
}

Expand Down
22 changes: 0 additions & 22 deletions src/Tasks/Microsoft.NET.Build.Tasks/ReportUserErrorException.cs

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,7 @@ private void GetPackageAndFileDependencies(LockFileTarget target)
string version;
if (!resolvedPackageVersions.TryGetValue(deps.Id, out version))
{
Log.LogError($"Unexpected Dependency {deps.Id} with no version number");
Log.LogError(Strings.UnexpectedDependencyWithNoVersionNumber, deps.Id);
continue;
}

Expand Down Expand Up @@ -387,7 +387,7 @@ private void SaveFileKeyType(string fileKey, FileGroup fileGroup)
}
else if (currentFileType != fileType)
{
throw new Exception($"Unexpected file type for {fileKey}. Type is both {fileType} and {currentFileType}");
throw new BuildErrorException(Strings.UnexpectedFileType, fileKey, fileType, currentFileType);
}
}
}
Expand All @@ -401,7 +401,7 @@ private string ResolvePackagePath(LockFileLibrary package)

if (string.IsNullOrEmpty(relativeMSBuildProjectPath))
{
ReportException($"Your project is consuming assets from the project but no MSBuild project is found in '{ProjectAssetsFile}'");
throw new BuildErrorException(Strings.ProjectAssetsConsumedWithoutMSBuildProjectPath, package.Name, ProjectAssetsFile);
}

return GetAbsolutePathFromProjectRelativePath(relativeMSBuildProjectPath);
Expand Down Expand Up @@ -430,10 +430,5 @@ private string GetAbsolutePathFromProjectRelativePath(string path)
{
return Path.GetFullPath(Path.Combine(Path.GetDirectoryName(Path.GetFullPath(ProjectAssetsFile)), path));
}

private void ReportException(string message)
{
throw new ReportUserErrorException(message);
}
}
}

0 comments on commit aca5d15

Please sign in to comment.