Skip to content

Commit

Permalink
Cosmos project upgrader improvements.
Browse files Browse the repository at this point in the history
  • Loading branch information
jp2masa committed Jan 8, 2018
1 parent 0142e03 commit 443577f
Show file tree
Hide file tree
Showing 3 changed files with 133 additions and 67 deletions.
4 changes: 0 additions & 4 deletions source/Cosmos.VS.ProjectSystem/Cosmos.VS.ProjectSystem.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,6 @@
<ExtensionInstallationFolder>Cosmos\ProjectSystem\</ExtensionInstallationFolder>
</PropertyGroup>

<ItemGroup>
<EmbeddedResource Include="ProjectTemplate.xml" />
</ItemGroup>

<ItemGroup>
<Compile Remove="ProjectTemplates\**" />
<Content Include="ProjectTemplates\**">
Expand Down
186 changes: 133 additions & 53 deletions source/Cosmos.VS.ProjectSystem/MigrateCosmosProjectFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Xml;
using System.Xml.Linq;
using Microsoft.VisualStudio;
Expand All @@ -13,9 +12,16 @@ namespace Cosmos.VS.ProjectSystem
{
internal class MigrateCosmosProjectFactory : IVsProjectFactory, IVsProjectUpgradeViaFactory, IVsProjectUpgradeViaFactory4
{
private const string CSharpProjectTypeGuid = "9A19103F-16F7-4668-BE54-9A1E7A4F7556";
private const string FSharpProjectTypeGuid = "6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705";
private const string VisualBasicProjectTypeGuid = "778DAE3C-4631-46EA-AA77-85C1314464D9";
private const string PropertyGroup = nameof(PropertyGroup);
private const string ProjectGuid = nameof(ProjectGuid);
private const string TargetFramework = nameof(TargetFramework);

private const string ItemGroup = nameof(ItemGroup);
private const string Include = nameof(Include);
private const string Remove = nameof(Remove);
private const string None = nameof(None);
private const string PackageReference = nameof(PackageReference);
private const string ProjectReference = nameof(ProjectReference);

private static readonly List<string> CommonProjectProperties = new List<string>()
{
Expand Down Expand Up @@ -81,8 +87,8 @@ public int UpgradeProject(string bstrFileName, uint fUpgradeFlag, string bstrCop
using (var projectStream = File.OpenRead(bstrFileName))
{
var document = XDocument.Load(projectStream);
var itemGroups = document.Root.Descendants().Where(e => e.Name == "ItemGroup");
var projectReferences = itemGroups.Descendants().Where(e => e.Name == "ProjectReference");
var itemGroups = document.Root.Descendants().Where(e => XNameEqualsString(e.Name, ItemGroup));
var projectReferences = itemGroups.Descendants().Where(e => XNameEqualsString(e.Name, ProjectReference));

if (!projectReferences.Any())
{
Expand All @@ -93,7 +99,8 @@ public int UpgradeProject(string bstrFileName, uint fUpgradeFlag, string bstrCop
}
else if (projectReferences.Count() == 1)
{
var codeProject = projectReferences.Single().Attributes().Where(a => a.Name == "Include").Single().Value;
var codeProject = projectReferences.Single().Attributes().Where(
a => XNameEqualsString(a.Name, Include)).Single().Value;
codeProjectPath = Path.IsPathRooted(codeProject) ? codeProject
: Path.GetFullPath(Path.Combine(projectDir.FullName, codeProject));
}
Expand All @@ -103,7 +110,7 @@ public int UpgradeProject(string bstrFileName, uint fUpgradeFlag, string bstrCop
p => !PlugsProjects.Contains(
Path.GetFileNameWithoutExtension(
p.Attributes().Where(
a => a.Name == "Include").Single().Value), StringComparer.OrdinalIgnoreCase));
a => XNameEqualsString(a.Name, Include)).Single().Value), StringComparer.OrdinalIgnoreCase));

if (projectReferencesWithoutPlugsProjects.Count() > 1)
{
Expand All @@ -114,9 +121,10 @@ public int UpgradeProject(string bstrFileName, uint fUpgradeFlag, string bstrCop
var codeProjectPathWithoutExtension = Path.Combine(projectDir.FullName, codeProjectName);

var possibleCodeProjects = projectReferences.Where(
p => Path.GetFileNameWithoutExtension(
p.Attributes().Where(
a => a.Name == "Include").Single().Value) == codeProjectName);
p => StringEquals(
Path.GetFileNameWithoutExtension(
p.Attributes().Where(
a => XNameEqualsString(a.Name, Include)).Single().Value), codeProjectName));

if (possibleCodeProjects.Count() != 1)
{
Expand All @@ -128,14 +136,14 @@ public int UpgradeProject(string bstrFileName, uint fUpgradeFlag, string bstrCop
}

var codeProject =
possibleCodeProjects.Single().Attributes().Where(a => a.Name == "Include").Single().Value;
possibleCodeProjects.Single().Attributes().Where(a => XNameEqualsString(a.Name, Include)).Single().Value;
codeProjectPath = Path.IsPathRooted(codeProject) ? codeProject
: Path.GetFullPath(Path.Combine(projectDir.FullName, codeProject));
}
else
{
var codeProject = projectReferencesWithoutPlugsProjects
.Single().Attributes().Where(a => a.Name == "Include").Single().Value;
.Single().Attributes().Where(a => XNameEqualsString(a.Name, Include)).Single().Value;
codeProjectPath = Path.IsPathRooted(codeProject) ? codeProject
: Path.GetFullPath(Path.Combine(projectDir.FullName, codeProject));
}
Expand Down Expand Up @@ -196,77 +204,149 @@ public void UpgradeProject_CheckOnly(string pszFileName, IVsUpgradeLogger pLogge
private void MigrateProject(string cosmosProject, string codeProject)
{
var cosmosProjectProperties = XDocument.Parse(File.ReadAllText(cosmosProject)).Root.Descendants()
.Where(d => d.Name == "PropertyGroup").Select(p => p.Descendants()
.Where(d => XNameEqualsString(d.Name, PropertyGroup)).Select(p => p.Descendants()
.Where(e => !CommonProjectProperties.Contains(e.Name.LocalName, StringComparer.OrdinalIgnoreCase)));

var codeProjectStream = File.OpenRead(codeProject);
XDocument document;

using (var codeProjectStream = File.OpenRead(codeProject))
{
document = XDocument.Load(codeProjectStream);
}

var root = document.Root;

var document = XDocument.Load(codeProjectStream);
var itemGroups = document.Root.Descendants().Where(e => e.Name == "ItemGroup");
var references = itemGroups.Descendants().Where(e => e.Name == "Reference");
var projectReferences = itemGroups.Descendants().Where(e => e.Name == "ProjectReference");
var packageReferences = itemGroups.Descendants().Where(e => e.Name == "PackageReference");
root.Descendants().Where(
e => XNameEqualsString(e.Name, PropertyGroup)).Last().AddAfterSelf(
new XElement(PropertyGroup, cosmosProjectProperties));

if (packageReferences.Any(p => p.Attributes().Any(a => a.Name == "Include" && a.Value == "Cosmos.Build")))
var packageReferencesItemGroups = root.Descendants().Where(
e => XNameEqualsString(e.Name, ItemGroup) && e.Descendants().Where(
i => XNameEqualsString(i.Name, PackageReference)).Any());

if (packageReferencesItemGroups.Descendants().Any(
i => XNameEqualsString(i.Name, PackageReference) && i.Attributes().Any(
a => XNameEqualsString(a.Name, Include) && XNameEqualsString(a.Value, "Cosmos.Build"))))
{
return;
}

var cosmosBuildPackageReference = new XElement("PackageReference");
cosmosBuildPackageReference.Add(new XAttribute("Include", "Cosmos.Build"));
cosmosBuildPackageReference.Add(new XAttribute("Version", "*"));
var properties = root.Descendants().Where(
e => XNameEqualsString(e.Name, PropertyGroup)).Descendants();

packageReferences.Append(cosmosBuildPackageReference);
packageReferences = packageReferences.OrderBy(p => p.Attributes().Where(a => a.Name == "Include").First().Value);
foreach(var targetFrameworkProperty in properties.Where(
p => XNameEqualsString(p.Name, TargetFramework)))
{
targetFrameworkProperty.Value = "netstandard2.0";
}

codeProjectStream.Dispose();
properties.Where(p => XNameEqualsString(p.Name, ProjectGuid)).Remove();

File.WriteAllText(codeProject, GetProjectTemplate());
var itemGroups = root.Descendants().Where(
e => XNameEqualsString(e.Name, ItemGroup));

var codeProjectDocument = XDocument.Parse(File.ReadAllText(codeProject));
itemGroups.Where(e =>
{
var items = e.Descendants();

if (items.Count() != 1)
{
return false;
}

codeProjectDocument.Root.Descendants().Where(d => d.Name == "PropertyGroup").LastOrDefault()
.Add(cosmosProjectProperties);
var singleItem = items.Single();

if (references.Count() > 0)
if (!XNameEqualsString(singleItem.Name, None))
{
return false;
}

var removeAttribute = singleItem.Attributes().Where(a => XNameEqualsString(a.Name, Remove)).FirstOrDefault();

if (removeAttribute == null)
{
return false;
}

if (removeAttribute.Value.IndexOf(Path.GetFileName(cosmosProject), StringComparison.OrdinalIgnoreCase) != -1)
{
return true;
}

return false;
}).Remove();

var count = packageReferencesItemGroups.Count();
XElement itemGroup;

if (count == 0)
{
codeProjectDocument.Root.Add(new XElement("ItemGroup", references));
itemGroup = new XElement(ItemGroup);
root.Add(itemGroup);
}

if (projectReferences.Count() > 0)
else if (count == 1)
{
codeProjectDocument.Root.Add(new XElement("ItemGroup", projectReferences));
itemGroup = packageReferencesItemGroups.Single();
}

if (packageReferences.Count() > 0)
else
{
codeProjectDocument.Root.Add(new XElement("ItemGroup", packageReferences));
var packageReferencesOnlyItemGroups = packageReferencesItemGroups.Where(
e => e.Descendants().All(i => XNameEqualsString(i.Name, PackageReference)));

count = packageReferencesOnlyItemGroups.Count();

if (count == 1)
{
itemGroup = packageReferencesOnlyItemGroups.Single();
}
else
{
if (count == 0)
{
itemGroup = packageReferencesItemGroups.First();
}
else
{
var cosmosPackageReferencesItemGroups = packageReferencesOnlyItemGroups.Where(
e => e.Descendants().Any(
p => p.Attributes().First(
a => XNameEqualsString(a.Name, Include)).Value.Contains("Cosmos")));

if (cosmosPackageReferencesItemGroups.Any())
{
itemGroup = cosmosPackageReferencesItemGroups.First();
}
else
{
itemGroup = packageReferencesItemGroups.First();
}
}
}
}

using (var xmlWriter = XmlWriter.Create(codeProject,
var cosmosBuildPackageReference = new XElement("PackageReference");
cosmosBuildPackageReference.Add(new XAttribute(Include, "Cosmos.Build"));
cosmosBuildPackageReference.Add(new XAttribute("Version", "*"));
cosmosBuildPackageReference.Add(new XAttribute("NoWarn", "NU1604"));

itemGroup.AddFirst(cosmosBuildPackageReference);

using (var xmlWriter = XmlWriter.Create(
codeProject,
new XmlWriterSettings()
{
Indent = true,
IndentChars = " ",
OmitXmlDeclaration = true
}))
{
codeProjectDocument.Save(xmlWriter);
document.Save(xmlWriter);
}

File.Delete(cosmosProject);
}

private string GetProjectTemplate()
{
using (var projectTemplateStream = Assembly.GetExecutingAssembly()
.GetManifestResourceStream("Cosmos.VS.ProjectSystem.ProjectTemplate.xml"))
{
using (var projectTemplateReader = new StreamReader(projectTemplateStream))
{
return projectTemplateReader.ReadToEnd();
}
}
}
private static bool XNameEqualsString(XName xName, string name) => StringEquals(xName.LocalName, name);

private static bool StringEquals(string a, string b) => String.Equals(a, b, StringComparison.OrdinalIgnoreCase);
}
}
10 changes: 0 additions & 10 deletions source/Cosmos.VS.ProjectSystem/ProjectTemplate.xml

This file was deleted.

0 comments on commit 443577f

Please sign in to comment.