Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Check schema when performing a sln build. #2593

Merged
merged 2 commits into from
Jan 4, 2018
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
55 changes: 52 additions & 3 deletions src/Build.UnitTests/Construction/SolutionFile_Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,9 @@
using System.IO;

using Microsoft.Build.Construction;
using Microsoft.Build.Engine.UnitTests;
using Microsoft.Build.Shared;



using Shouldly;
using InvalidProjectFileException = Microsoft.Build.Exceptions.InvalidProjectFileException;
using Xunit;

Expand Down Expand Up @@ -259,6 +258,56 @@ public void CanBeMSBuildFile()
}
}

/// <summary>
/// Test CanBeMSBuildFile
/// </summary>
[Fact]
public void CanBeMSBuildFileRejectsMSBuildLikeFiles()
{
using (var env = TestEnvironment.Create())
{
string rptprojProjContent = @"<?xml version=""1.0"" encoding=""utf-8""?>
<Project xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" ToolsVersion=""2.0"">
<DataSources />
<Reports />
</Project>";
string dwprojProjContent = @"<?xml version=""1.0"" encoding=""utf-8""?>
<Project xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:ddl2=""http://schemas.microsoft.com/analysisservices/2003/engine/2"" xmlns:ddl2_2=""http://schemas.microsoft.com/analysisservices/2003/engine/2/2"" xmlns:ddl100_100=""http://schemas.microsoft.com/analysisservices/2008/engine/100/100"" xmlns:ddl200=""http://schemas.microsoft.com/analysisservices/2010/engine/200"" xmlns:ddl200_200=""http://schemas.microsoft.com/analysisservices/2010/engine/200/200"" xmlns:dwd=""http://schemas.microsoft.com/DataWarehouse/Designer/1.0"">
<ProductVersion />
<SchemaVersion />
<State />
<Database />
<Cubes />
</Project>";

string rptprojPath = env.CreateFile(".rptproj").Path;
File.WriteAllText(rptprojPath, rptprojProjContent);
string dqprojPath = env.CreateFile(".dwproj").Path;
File.WriteAllText(dqprojPath, dwprojProjContent);

// Create the SolutionFile object
string solutionFileContents =
@"
Microsoft Visual Studio Solution File, Format Version 8.00
Project('{F14B399A-7131-4C87-9E4B-1186C45EF12D}') = 'PrtProj', '" + Path.GetFileName(rptprojPath) + @"', '{CCCCCCCC-9925-4D57-9DAF-E0A9D936ABDB}'
ProjectSection(ProjectDependencies) = postProject
EndProjectSection
EndProject
Project('{D2ABAB84-BF74-430A-B69E-9DC6D40DDA17}') = 'DwProj', '" + Path.GetFileName(dqprojPath) + @"', '{DEA89696-F42B-4B58-B7EE-017FF40817D1}'
ProjectSection(ProjectDependencies) = postProject
EndProjectSection
EndProject";

string error = null;
SolutionFile solution = ParseSolutionHelper(solutionFileContents);
ProjectInSolution project1 = solution.ProjectsByGuid["{CCCCCCCC-9925-4D57-9DAF-E0A9D936ABDB}"];
ProjectInSolution project2 = solution.ProjectsByGuid["{DEA89696-F42B-4B58-B7EE-017FF40817D1}"];

project1.CanBeMSBuildProjectFile(out error).ShouldBe(false);
project2.CanBeMSBuildProjectFile(out error).ShouldBe(false);
}
}

/// <summary>
/// Test ParseEtpProject function.
/// </summary>
Expand Down
46 changes: 44 additions & 2 deletions src/Build/Construction/Solution/ProjectInSolution.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
using BuildEventFileInfo = Microsoft.Build.Shared.BuildEventFileInfo;
using ErrorUtilities = Microsoft.Build.Shared.ErrorUtilities;
using System.Collections.ObjectModel;
using System.Linq;

namespace Microsoft.Build.Construction
{
Expand Down Expand Up @@ -323,8 +324,30 @@ internal bool CanBeMSBuildProjectFile(out string errorMessage)

if (mainProjectElement != null && mainProjectElement.LocalName == "Project")
{
_canBeMSBuildProjectFile = true;
return _canBeMSBuildProjectFile;
// MSBuild supports project files with an empty (supported in Visual Studio 2017) or the default MSBuild
// namespace.
bool emptyNamespace = string.IsNullOrEmpty(mainProjectElement.NamespaceURI);
bool defaultNamespace = String.Compare(mainProjectElement.NamespaceURI,
XMakeAttributes.defaultXmlNamespace,
StringComparison.OrdinalIgnoreCase) == 0;
bool projectElementInvalid = ElementContainsInvalidNamespaceDefitions(mainProjectElement);

// If the MSBuild namespace is declared, it is very likely an MSBuild project that should be built.
if (defaultNamespace)
{
_canBeMSBuildProjectFile = true;
return _canBeMSBuildProjectFile;
}

// This is a bit of a special case, but an rptproj file will contain a Project with no schema that is
// not an MSBuild file. It will however have ToolsVersion="2.0" which is not supported with an empty
// schema. This is not a great solution, but it should cover the customer reported issue. See:
// https://github.com/Microsoft/msbuild/issues/2064
if (emptyNamespace && !projectElementInvalid && mainProjectElement.GetAttribute("ToolsVersion") != "2.0")
{
_canBeMSBuildProjectFile = true;
return _canBeMSBuildProjectFile;
}
}
}
// catch all sorts of exceptions - if we encounter any problems here, we just assume the project file is not
Expand Down Expand Up @@ -463,6 +486,25 @@ static internal string DisambiguateProjectTargetName(string uniqueProjectName)
return uniqueProjectName;
}

/// <summary>
/// Check a Project element for known invalid namespace definitions.
/// </summary>
/// <param name="mainProjectElement">Project XML Element</param>
/// <returns>True if the element contains known invalid namespace definitions</returns>
private static bool ElementContainsInvalidNamespaceDefitions(XmlElement mainProjectElement)
{
if (mainProjectElement.HasAttributes)
{
// Data warehouse projects (.dwproj) will contain a Project element but are invalid MSBuild. Check attributes
// on Project for signs that this is a .dwproj file. If there are, it's not a valid MSBuild file.
return mainProjectElement.Attributes.OfType<XmlAttribute>().Any(a =>
a.Name.Equals("xmlns:dwd", StringComparison.OrdinalIgnoreCase) ||
a.Name.StartsWith("xmlns:dd", StringComparison.OrdinalIgnoreCase));
}

return false;
}

#endregion

#region Constants
Expand Down