This tool exports the Win2D samples such that they reference the nuget package and can be built in isolation.
This commit is contained in:
Damyan Pepper 2015-05-22 12:12:09 -07:00
Родитель 406b2ab0e3
Коммит 769230c5e4
15 изменённых файлов: 1167 добавлений и 7 удалений

Просмотреть файл

@ -171,6 +171,7 @@
<AnyCPUProject Include="tools\docs\DocDiff\DocDiff.csproj" />
<AnyCPUProject Include="tools\docs\ExtractAPISurface\ExtractAPISurface.csproj" />
<AnyCPUProject Include="tools\docs\MergeIntellisense\MergeIntellisense.csproj" />
<AnyCPUProject Include="tools\exportsample\exportsample.csproj" />
</ItemGroup>

Просмотреть файл

@ -1,6 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- [[NOT IN SAMPLE]] -->
<!--
This file contains build system properties that are common between C# and

Просмотреть файл

@ -3,6 +3,8 @@
<Import Project="Win2D.common.props" />
<!-- [[NOT IN SAMPLE]] -->
<!-- This lets individual projects turn off their building. This allows us to
prevent building in the cloud for unsupported SDKs (ie Phone unit tests)
-->
@ -10,6 +12,8 @@
<_InvalidConfigurationWarning>true</_InvalidConfigurationWarning>
</PropertyGroup>
<!-- [[IN SAMPLE]] -->
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|ARM" Condition="'$(ApplicationType)' != ''">
<Configuration>Debug</Configuration>
@ -41,12 +45,19 @@
<PlatformToolset Condition="'$(ApplicationType)' == 'Windows Store' And '$(ApplicationTypeRevision)' == '8.1'">v120</PlatformToolset>
<PlatformToolset Condition="'$(ApplicationType)' == 'Windows Store' And '$(ApplicationTypeRevision)' == '8.2'">v140</PlatformToolset>
<PlatformToolset Condition="'$(ApplicationType)' == 'Windows Phone'">v120_wp81</PlatformToolset>
</PropertyGroup>
<!-- [[NOT IN SAMPLE]] -->
<PropertyGroup Label="Configuration">
<UnmergedWinmdDirectory>$(IntermediateOutputPath)UnmergedWinMD</UnmergedWinmdDirectory>
<MergedWinmdDirectory>$(MSBuildThisFileDirectory)..\bin\$(FullPlatform)\$(Configuration)\MergedWinMD</MergedWinmdDirectory>
<IdlHeaderDirectory>$(MSBuildThisFileDirectory)..\bin\$(FullPlatform)\$(Configuration)\IdlHeader</IdlHeaderDirectory>
<PublishedHeaderDirectory>$(MSBuildThisFileDirectory)..\winrt\published</PublishedHeaderDirectory>
</PropertyGroup>
<!-- [[IN SAMPLE]] -->
<PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
<UseDebugLibraries>true</UseDebugLibraries>
</PropertyGroup>
@ -55,6 +66,8 @@
<WholeProgramOptimization>true</WholeProgramOptimization>
</PropertyGroup>
<!-- [[NOT IN SAMPLE]] -->
<PropertyGroup>
<GenerateManifest>false</GenerateManifest>
<OutDir>$(__OutputPath)\</OutDir>
@ -62,6 +75,14 @@
<GenerateProjectSpecificOutputFolder>false</GenerateProjectSpecificOutputFolder>
</PropertyGroup>
<ItemDefinitionGroup>
<ClCompile>
<AdditionalIncludeDirectories>$(IdlHeaderDirectory);$(PublishedHeaderDirectory);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
</ItemDefinitionGroup>
<!-- [[IN SAMPLE]] -->
<ItemDefinitionGroup>
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
@ -69,7 +90,6 @@
<SDLCheck>true</SDLCheck>
<RuntimeTypeInfo>false</RuntimeTypeInfo>
<AdditionalUsingDirectories>$(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories)</AdditionalUsingDirectories>
<AdditionalIncludeDirectories>$(IdlHeaderDirectory);$(PublishedHeaderDirectory);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalOptions>/bigobj /Zm450 /wd4503 /D_CRT_STDIO_LEGACY_WIDE_SPECIFIERS=1 %(AdditionalOptions)</AdditionalOptions>
<!--
/Zm999 - this value needs to be bumped occasionally when as our PCH grows

Просмотреть файл

@ -1,6 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- [[NOT IN SAMPLE]] -->
<!-- We'd like to just set WarningLevel once in Win2D.cpp.props, but
Microsoft.Cpp.AppContainerApplication.props unconditionally overwrites it.
So instead, we make sure each C++ project has individually set the right thing. -->

Просмотреть файл

@ -2,6 +2,8 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="Win2D.common.props"/>
<!-- [[NOT IN SAMPLE]] -->
<!-- This lets individual projects turn off their building. This allows us to
prevent building in the cloud for unsupported SDKs (ie Phone unit tests)
-->
@ -13,6 +15,11 @@
<OutputPath>$(__OutputPath)</OutputPath>
<OutDir>$(__OutputPath)\</OutDir>
<GenerateProjectSpecificOutputFolder>false</GenerateProjectSpecificOutputFolder>
</PropertyGroup>
<!-- [[IN SAMPLE]] -->
<PropertyGroup>
<WarningLevel>4</WarningLevel>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>

Просмотреть файл

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
</configuration>

Просмотреть файл

@ -0,0 +1,167 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use these files except in compliance with the License. You may obtain
// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
using System;
using System.Collections.Generic;
using System.IO;
using System.Xml.Linq;
namespace exportsample
{
public class Configuration
{
public CommandLineOptions Options;
public Dictionary<string, string> Properties = new Dictionary<string, string>();
public List<SampleDirectory> Samples = new List<SampleDirectory>();
public List<InlineImport> InlineImports = new List<InlineImport>();
public Dictionary<string, string> DuplicateDirectories = new Dictionary<string, string>();
public List<string> FileReferenceProperties = new List<string>();
public List<string> Win2DProjects = new List<string>();
public List<string> FilesToCopy = new List<string>();
public Configuration(CommandLineOptions options)
{
this.Options = options;
var doc = XDocument.Load(options.Config);
foreach (var element in doc.Element("ExportSamples").Elements())
{
switch (element.Name.ToString())
{
case "Property":
Properties.Add(
element.Attribute("Name").Value,
Path.GetFullPath(Path.Combine(options.Root, element.Attribute("Value").Value)));
break;
case "Sample":
Samples.Add(new SampleDirectory(element, options.Root, options.Dest));
break;
case "InlineImport":
InlineImports.Add(new InlineImport(element));
break;
case "DuplicateIntoSample":
DuplicateDirectories.Add(
Path.GetFullPath(Path.Combine(options.Root, element.Attribute("Source").Value)),
element.Attribute("Destination").Value);
break;
case "MSBuildPropertyIsFileReference":
FileReferenceProperties.Add(element.Attribute("Name").Value);
break;
case "Win2DProject":
Win2DProjects.Add(element.Attribute("Name").Value);
break;
case "File":
FilesToCopy.Add(element.Attribute("Source").Value);
break;
}
}
}
public InlineImport FindInlineImportFor(string importPath)
{
foreach (var inlineImport in InlineImports)
{
if (importPath.EndsWith(inlineImport.Name))
return inlineImport;
}
return null;
}
public string GetDestination(string source)
{
string destination;
if (TryGetDestination(source, out destination))
{
return destination;
}
throw new Exception(string.Format("Could not find destination for '{0}'", source));
}
public bool ShouldExport(string file)
{
string dummyDestination;
return TryGetDestination(file, out dummyDestination);
}
public bool TryGetDestination(string source, out string destination)
{
foreach (var directory in Samples)
{
if (source.StartsWith(directory.Source))
{
destination = source.Replace(directory.Source, directory.Destination);
return true;
}
}
destination = null;
return false;
}
public bool IsWin2DProject(string project)
{
foreach (var win2dProject in Win2DProjects)
{
if (project.EndsWith(win2dProject))
return true;
}
return false;
}
}
public class SampleDirectory
{
public string Destination;
public string Source;
public SampleDirectory(XElement element, string enlistmentRoot, string destinationRoot)
{
Destination = element.Attribute("Destination").Value;
Source = element.Attribute("Source").Value;
// Preprocess the directories to have absolute paths. The dirs in the config file are relative to the config file.
Destination = Path.GetFullPath(Path.Combine(destinationRoot, Destination));
Source = Path.GetFullPath(Path.Combine(enlistmentRoot, Source));
}
}
public class InlineImport
{
public string Name;
public List<XElement> Elements;
public InlineImport(XElement element)
{
Name = element.Attribute("Name").Value;
Elements = new List<XElement>(element.Elements());
// Rename all the elements so that they're in msbuild's namespace
foreach (var e in Elements)
{
foreach (var d in e.DescendantsAndSelf())
{
d.Name = ProjectProcessor.NS + d.Name.LocalName;
}
}
}
}
}

Просмотреть файл

@ -0,0 +1,56 @@
<?xml version="1.0"?>
<!--
Copyright (c) Microsoft Corporation. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License"); you may
not use these files except in compliance with the License. You may obtain
a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
License for the specific language governing permissions and limitations
under the License.
-->
<ExportSamples>
<File Source="LICENSE.txt" />
<File Source="README.md" />
<Sample Source="samples\CoreWindowExample" Destination="CoreWindowExample" />
<Sample Source="samples\ExampleGallery" Destination="ExampleGallery" />
<Sample Source="samples\SimpleSample" Destination="SimpleSample" />
<Property Name="AssetDir" Value="build\assets\" />
<DuplicateIntoSample Source="build\assets" Destination="Shared" />
<InlineImport Name="Win2D.cs.props">
<PropertyGroup>
<OutputPath>bin\$(Platform)\$(Configuration)\</OutputPath>
</PropertyGroup>
</InlineImport>
<InlineImport Name="Win2D.common.props" />
<InlineImport Name="Win2D.cpp.props" />
<InlineImport Name="Win2D.cpp.targets" />
<!--
Most file references can be found by looking for "Include" attributes.
However, sometimes the value of an MSBuild property should be interpreted
as a file reference.
-->
<MSBuildPropertyIsFileReference Name="PackageCertificateKeyFile" />
<!--
Any references to these projects indicate that a project should actually
reference the Win2D nuget package. These references themselves will be
removed.
-->
<Win2DProject Name="winrt.dll.Windows.vcxproj" />
<Win2DProject Name="winrt.dll.WindowsPhone.vcxproj" />
<Win2DProject Name="winrt.dll.uap.vcxproj" />
<Win2DProject Name="DotNetNumerics.Windows.csproj" />
<Win2DProject Name="DotNetNumerics.WindowsPhone.csproj" />
</ExportSamples>

Просмотреть файл

@ -0,0 +1,113 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use these files except in compliance with the License. You may obtain
// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
using Shared;
using System;
using System.IO;
namespace exportsample
{
class Program
{
static int Main(string[] args)
{
// Read command line
var options = new CommandLineOptions();
var parser = new CommandLineParser(options);
if (!parser.ParseCommandLine(args))
{
return 1;
}
var config = LoadConfig(options);
// Export Samples
foreach (var sample in config.Samples)
{
SampleExporter.Export(config, sample);
}
// Copy individual files
foreach (var file in config.FilesToCopy)
{
File.Copy(Path.Combine(config.Options.Root, file), Path.Combine(config.Options.Dest, file), true);
}
return 0;
}
static private Configuration LoadConfig(CommandLineOptions options)
{
if (options.Config == null)
{
options.Config = FindConfigFile();
}
if (options.Root == null)
{
options.Root = FindEnlistmentRoot(options);
}
if (options.Win2DVersion == null)
{
options.Win2DVersion = File.ReadAllText(Path.Combine(options.Root, "build", "nuget", "VERSION")).Trim();
}
return new Configuration(options);
}
static string FindConfigFile()
{
string[] candidates = new string[] {
".",
"../../../../tools/exportsample",
};
foreach (var candidate in candidates)
{
var normalizedCandidate = Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, candidate, "ExportSampleConfig.xml"));
if (File.Exists(normalizedCandidate))
return normalizedCandidate;
}
throw new FileNotFoundException("Couldn't find ExportSampleConfig.xml");
}
static string FindEnlistmentRoot(CommandLineOptions options)
{
string dir = Path.GetFullPath(options.Config);
do
{
dir = Path.GetDirectoryName(dir);
if (File.Exists(Path.Combine(dir, "Win2D.proj")))
return dir;
} while (dir.Length > 3);
throw new FileNotFoundException("Couldn't find enlistment root");
}
}
public class CommandLineOptions
{
[CommandLineParser.Required]
public string Dest = null;
public string Config = null;
public string Root = null;
public string Win2DVersion = null;
}
}

Просмотреть файл

@ -0,0 +1,526 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use these files except in compliance with the License. You may obtain
// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Xml.Linq;
namespace exportsample
{
class ProjectProcessor
{
public static XNamespace NS = "http://schemas.microsoft.com/developer/msbuild/2003";
public Dictionary<string, string> FilesToCopy = new Dictionary<string, string>();
public bool ReferencesWin2DNuGetPackage { get; private set; }
string fileName;
public string SourceDirectory { get; private set; }
public string DestinationDirectory { get; private set; }
string relativePackagesDirectory;
Configuration config;
SampleDirectory sample;
XDocument doc;
public static ProjectProcessor Export(string projectFileName, Configuration config, SampleDirectory sample, string destination)
{
var project = new ProjectProcessor(projectFileName, config, sample);
project.Process();
project.Save(destination);
return project;
}
ProjectProcessor(string projectFileName, Configuration config, SampleDirectory sample)
{
this.fileName = projectFileName;
this.SourceDirectory = Path.GetDirectoryName(fileName);
this.DestinationDirectory = config.GetDestination(SourceDirectory);
this.config = config;
this.sample = sample;
var relativeSolutionDirectory = GetRelativePath(sample.Destination + "\\", DestinationDirectory);
this.relativePackagesDirectory = Path.Combine(relativeSolutionDirectory, "packages\\");
doc = XDocument.Load(projectFileName);
}
public void Save(string dest)
{
Directory.CreateDirectory(Path.GetDirectoryName(dest));
doc.Save(dest);
}
// Pull out a list of names of projects that are imported by this project
public List<string> FindImportedProjectsThatNeedExporting()
{
var imports = doc.Descendants(NS + "Import");
List<string> importPaths = new List<string>();
foreach (var import in imports)
{
var importPath = import.Attribute("Project").Value;
importPath = Expand(importPath);
// After we've expanded variables we know about, anything that still starts with a $ we leave unmodified
if (!importPath.StartsWith("$"))
{
// Everything else we convert into a full path
importPath = Path.GetFullPath(Path.Combine(SourceDirectory, importPath));
}
if (config.ShouldExport(importPath))
importPaths.Add(importPath);
}
return importPaths;
}
public static bool IsValidPathName(string includeFile)
{
return !Path.GetInvalidPathChars().Any(includeFile.Contains);
}
// Expand variables we know about
string Expand(string path)
{
path = path.Replace("$(MSBuildThisFileDir)", SourceDirectory + "\\");
foreach (var property in config.Properties)
{
string prop = string.Format("$({0})", property.Key);
path = path.Replace(prop, property.Value);
}
return path;
}
void Process()
{
ProcessInlineImports();
ProcessFileReferences();
RelocateNuGetReferences();
ConvertWin2DProjectReferences();
}
#region Inline Imports
void ProcessInlineImports()
{
while (ProcessNextInlinedImport())
;
}
bool ProcessNextInlinedImport()
{
var imports = doc.Descendants(NS + "Import");
foreach (var import in imports)
{
var importPath = import.Attribute("Project").Value;
var inlineImport = config.FindInlineImportFor(importPath);
if (inlineImport != null)
{
DoInlineImport(import, inlineImport);
return true;
}
}
return false;
}
void DoInlineImport(XElement import, InlineImport inlineImport)
{
var importPath = ExpandPath(SourceDirectory, import.Attribute("Project").Value);
var inlinedDoc = XDocument.Load(importPath);
RelocateImports(Path.GetDirectoryName(importPath), inlinedDoc);
var project = inlinedDoc.Root;
List<XNode> filteredNodes = new List<XNode>();
bool inSample = true;
foreach (var node in project.Nodes())
{
if (node is XComment)
{
var comment = (XComment)node;
if (comment.Value.Contains("[[NOT IN SAMPLE]]"))
{
inSample = false;
continue;
}
else if (comment.Value.Contains("[[IN SAMPLE]]"))
{
inSample = true;
continue;
}
}
if (inSample)
filteredNodes.Add(node);
}
import.AddBeforeSelf(filteredNodes);
if (inlineImport.Elements.Count > 0)
{
import.AddBeforeSelf(inlineImport.Elements);
}
import.Remove();
}
void RelocateImports(string directory, XDocument doc)
{
foreach (var import in doc.Descendants(NS + "Import"))
{
import.SetAttributeValue("Project", ExpandPath(directory, import.Attribute("Project").Value));
}
}
#endregion
#region File References
const string MSBuildThisFileDirectory = "$(MSBuildThisFileDirectory)";
void ProcessFileReferences()
{
foreach (var element in doc.Descendants())
{
var includeAttribute = element.Attribute("Include");
if (includeAttribute == null)
continue;
includeAttribute.Value = ProcessFileReference(includeAttribute.Value);
}
foreach (var propertyThatIsFileReference in config.FileReferenceProperties)
{
foreach (var element in doc.Descendants(NS + propertyThatIsFileReference))
{
element.Value = ProcessFileReference(element.Value);
}
}
}
string ProcessFileReference(string originalValue)
{
string includedFile = originalValue;
// If this is a reference in a Shared project then it'll start with $(MSBuildThisFileDirectory).
// Strip this off while we're looking at this.
if (includedFile.StartsWith(MSBuildThisFileDirectory))
{
includedFile = includedFile.Substring(MSBuildThisFileDirectory.Length);
}
// Expand properties (eg $(AssetDir))
includedFile = Expand(includedFile);
// Ignore anything that isn't a valid path name
if (!IsValidPathName(includedFile))
return originalValue;
// Ignore anything that doesn't exist
var fullPath = Path.GetFullPath(Path.Combine(SourceDirectory, includedFile));
if (!File.Exists(fullPath))
return originalValue;
// If the file is part of this sample then we can reference it unmodified
if (fullPath.StartsWith(sample.Source))
{
var dest = config.GetDestination(fullPath);
FilesToCopy.Add(fullPath, dest);
return originalValue;
}
// Otherwise we'll need to copy it somewhere to reference it, and update our element to point to the new location
foreach (var entry in config.DuplicateDirectories)
{
if (fullPath.StartsWith(entry.Key))
{
var dest = fullPath.Replace(entry.Key, Path.Combine(sample.Destination, entry.Value));
FilesToCopy[fullPath] = dest;
return GetRelativePath(dest, DestinationDirectory);
}
}
return originalValue;
}
#endregion
#region Relocate NuGet References
void RelocateNuGetReferences()
{
// When projects have existing nuget references these need to be updated to be relative to
// the packages directory that'll be in the sample's directory.
//
// We can identify these by things that reference "\packages\". NuGet adds Import, Error
// and HintPath elements that might reference these.
RelocateNuGetReferences(doc.Descendants(NS + "Import"));
RelocateNuGetReferences(doc.Descendants(NS + "Error"));
RelocateNuGetReferences(doc.Descendants(NS + "HintPath"));
}
static Regex packagesRegex = new Regex(@"[.\\]*\\packages\\");
void RelocateNuGetReferences(IEnumerable<XElement> elements)
{
foreach (var element in elements)
{
if (element.Value.Length > 0)
element.Value = RelocateNuGetReference(relativePackagesDirectory, element.Value);
foreach (var attribute in element.Attributes())
{
attribute.Value = RelocateNuGetReference(relativePackagesDirectory, attribute.Value);
}
}
}
private static string RelocateNuGetReference(string relativePackagesDirectory, string reference)
{
var match = packagesRegex.Match(reference);
if (match.Success)
{
return packagesRegex.Replace(reference, relativePackagesDirectory);
}
else
{
return reference;
}
}
#endregion
#region Convert Win2D project references to NuGet package references
void ConvertWin2DProjectReferences()
{
ReferencesWin2DNuGetPackage = FindAndRemoveWin2DProjectReferences();
if (ReferencesWin2DNuGetPackage)
AddWin2DNuGetPackage();
}
bool FindAndRemoveWin2DProjectReferences()
{
bool foundAReference = false;
var toRemove = new List<XElement>();
foreach (var reference in doc.Descendants(NS + "ProjectReference"))
{
if (config.IsWin2DProject(reference.Attribute("Include").Value))
{
toRemove.Add(reference);
foundAReference = true;
}
}
toRemove.ForEach(RemoveElementAndParentIfEmpty);
if (RemoveExistingReferencesToWin2DNuGet())
foundAReference = true;
return foundAReference;
}
bool RemoveExistingReferencesToWin2DNuGet()
{
var elementsToRemove = new List<XElement>();
elementsToRemove.AddRange(from element in doc.Descendants(NS + "Import")
where element.Attribute("Project").Value.Contains("packages\\Win2D")
select element);
elementsToRemove.AddRange(from element in doc.Descendants(NS + "Reference")
where element.Attribute("Include").Value.Contains("Microsoft.Graphics.Canvas")
select element);
elementsToRemove.AddRange(from element in doc.Descendants(NS + "Error")
where element.Attribute("Condition").Value.Contains("packages\\Win2D")
select element);
if (elementsToRemove.Count == 0)
return false;
elementsToRemove.ForEach(RemoveElementAndParentIfEmpty);
return true;
}
void AddWin2DNuGetPackage()
{
var framework = GetFramework();
string importsDir = Path.Combine(Win2DPackagePath, "build", framework);
var propsImport = Path.Combine(importsDir, "Win2D.props");
var targetsImport = Path.Combine(importsDir, "Win2D.targets");
doc.Root.AddFirst(MakeImportElement(propsImport));
// Targets is added after last element (rather than the last node) so that it appears before
// any comments at the end of the project.
doc.Root.Elements().Last().AddAfterSelf(MakeImportElement(targetsImport));
var importsTarget = GetEnsureNuGetPackageBuildImportsTarget();
importsTarget.Add(MakeCheckImport(propsImport));
importsTarget.Add(MakeCheckImport(targetsImport));
}
public string GetFramework()
{
// C++ projects are always native
if (fileName.EndsWith("vcxproj"))
return "native";
// Otherwise we need to look at TargetPlatformIdentifier
var targetPlatformIdentifier = doc.Descendants(NS + "TargetPlatformIdentifier").FirstOrDefault();
// No platform == windows
if (targetPlatformIdentifier == null)
return "win";
switch (targetPlatformIdentifier.Value)
{
case "Windows":
return "win";
case "WindowsPhoneApp":
return "wpa";
case "UAP":
// Since NuGet currently doesn't know about UAP as a framwork moniker,
// the nuget package uses 'win'.
//
// When NuGet learns about UAP, and the Win2D package has been updated accordingly,
// this will need to be changed.
return "win";
}
throw new Exception("Unabled to determine NuGet framework for " + fileName);
}
XElement MakeImportElement(string filename)
{
var importElement = new XElement(NS + "Import");
importElement.SetAttributeValue("Project", filename);
importElement.SetAttributeValue("Condition", "Exists('" + filename + "')");
return importElement;
}
string Win2DPackagePath
{
get
{
return Path.Combine(relativePackagesDirectory, "Win2D." + config.Options.Win2DVersion);
}
}
Regex nugetTargetsFile = new Regex(@"packages\\.*\.targets$");
XElement GetEnsureNuGetPackageBuildImportsTarget()
{
// Look for an existing one...
var targets = from element in doc.Descendants(NS + "Target")
where element.Attribute("Name").Value == "EnsureNuGetPackageBuildImports"
select element;
var target = targets.FirstOrDefault();
if (target != null)
return target;
// There isn't an existing one, so we create one...
var ensureImports = new XElement(NS + "Target");
ensureImports.SetAttributeValue("Name", "EnsureNuGetPackageBuildImports");
ensureImports.SetAttributeValue("BeforeTargets", "PrepareForBuild");
var propertyGroup = new XElement(NS + "PropertyGroup");
var errorText = new XElement(NS + "ErrorText");
errorText.Value = "This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.";
propertyGroup.Add(errorText);
ensureImports.Add(propertyGroup);
var targetsImports = from element in doc.Descendants(NS + "Import")
where nugetTargetsFile.IsMatch(element.Attribute("Project").Value)
select element;
var firstImportTarget = targetsImports.First(); // if there isn't an import target then something strange is going on!
firstImportTarget.AddBeforeSelf(ensureImports);
return ensureImports;
}
XElement MakeCheckImport(string filename)
{
var element = new XElement(NS + "Error");
element.SetAttributeValue("Condition", string.Format("!Exists('{0}')", filename));
element.SetAttributeValue("Text", string.Format("$([System.String]::Format('$(ErrorText)', '{0}'))", filename));
return element;
}
#endregion
#region Utils
string ExpandPath(string root, string path)
{
string expandedPath = Expand(path);
if (!IsValidPathName(expandedPath))
throw new Exception(string.Format("Couldn't expand path {0}", path));
return Path.GetFullPath(Path.Combine(root, expandedPath));
}
// From http://stackoverflow.com/a/703292/157728
static string GetRelativePath(string filespec, string folder)
{
Uri pathUri = new Uri(filespec);
// Folders must end in a slash
if (!folder.EndsWith(Path.DirectorySeparatorChar.ToString()))
{
folder += Path.DirectorySeparatorChar;
}
Uri folderUri = new Uri(folder);
return Uri.UnescapeDataString(folderUri.MakeRelativeUri(pathUri).ToString().Replace('/', Path.DirectorySeparatorChar));
}
static void RemoveElementAndParentIfEmpty(XElement element)
{
var parent = element.Parent;
element.Remove();
if (parent.IsEmpty)
parent.Remove();
}
#endregion
}
}

Просмотреть файл

@ -0,0 +1,21 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use these files except in compliance with the License. You may obtain
// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
using System.Reflection;
using System.Runtime.InteropServices;
[assembly: AssemblyTitle("ExportSample")]
[assembly: AssemblyProduct("Win2D")]
[assembly: AssemblyCompany("Microsoft Corporation")]
[assembly: AssemblyCopyright("Copyright (c) Microsoft Corporation")]
[assembly: ComVisible(false)]

Просмотреть файл

@ -0,0 +1,175 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use these files except in compliance with the License. You may obtain
// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml.Linq;
namespace exportsample
{
class SampleExporter
{
public static void Export(Configuration config, SampleDirectory sample)
{
new SampleExporter(config, sample).Go();
}
Configuration config;
SampleDirectory sample;
HashSet<string> remainingProjects;
HashSet<string> copiedFiles;
SampleExporter(Configuration config, SampleDirectory sample)
{
this.config = config;
this.sample = sample;
}
void Go()
{
// Delete all the directories under the sample (leaving any files in the root). This is to allow
// us to catch (re)moved files.
foreach (var dir in Directory.EnumerateDirectories(sample.Destination))
{
Directory.Delete(dir, true);
}
// Process all the projects. Any files referenced by a project will be exported.
var projects = FindProjects();
remainingProjects = new HashSet<string>(from project in projects select project.FullName);
copiedFiles = new HashSet<string>();
while (remainingProjects.Count > 0)
{
var project = remainingProjects.First();
var destination = config.GetDestination(project);
if (!copiedFiles.Contains(destination) && File.Exists(project))
{
ExportProject(project, destination);
copiedFiles.Add(destination);
}
remainingProjects.Remove(project);
}
}
FileInfo[] FindProjects()
{
var sourceDir = Path.GetFullPath(Path.Combine(config.Options.Root, sample.Source));
return new DirectoryInfo(sourceDir).GetFiles("*proj", SearchOption.AllDirectories);
}
void ExportProject(string source, string destination)
{
ProcessAndCopyProject(source, destination);
CopyProjectFilters(source);
}
void ProcessAndCopyProject(string source, string destination)
{
var project = ProjectProcessor.Export(source, config, sample, destination);
remainingProjects.UnionWith(project.FindImportedProjectsThatNeedExporting());
if (project.ReferencesWin2DNuGetPackage)
{
CopyPackagesConfigWithAddedWin2DReference(project);
}
// Any referenced files should be copied
CopyReferencedFiles(project);
}
void CopyPackagesConfigWithAddedWin2DReference(ProjectProcessor project)
{
var source = Path.Combine(project.SourceDirectory, "packages.config");
XDocument packagesConfig;
if (File.Exists(source))
{
packagesConfig = XDocument.Load(source);
}
else
{
packagesConfig = new XDocument();
packagesConfig.Add(new XElement("packages"));
}
RemoveExistingWin2DReferences(packagesConfig);
var package = new XElement("package");
package.SetAttributeValue("id", "Win2D");
package.SetAttributeValue("version", config.Options.Win2DVersion);
// The framework name in packages.config does not exactly match then name on disk
string framework = project.GetFramework();
switch (framework)
{
case "win": framework = "win81"; break;
case "wpa": framework = "wpa81"; break;
case "native": framework = "Native"; break;
default: throw new Exception("Unexpected framework type");
}
package.SetAttributeValue("targetFramework", framework);
packagesConfig.Root.Add(package);
var destination = Path.Combine(project.DestinationDirectory, "packages.config");
packagesConfig.Save(destination);
copiedFiles.Add(destination);
}
private static void RemoveExistingWin2DReferences(XDocument packagesConfig)
{
var existingReferences = from package in packagesConfig.Descendants("package")
where package.Attribute("id").Value == "Win2D"
select package;
existingReferences.ToList().ForEach(e => e.Remove());
}
void CopyReferencedFiles(ProjectProcessor project)
{
foreach (var srcDst in project.FilesToCopy)
{
var source = srcDst.Key;
var destination = srcDst.Value;
if (!copiedFiles.Contains(destination))
{
CopyFile(source, destination);
copiedFiles.Add(destination);
}
}
}
void CopyProjectFilters(string projectFileName)
{
string filters = projectFileName + ".filters";
if (File.Exists(filters))
{
var dest = config.GetDestination(filters);
CopyFile(filters, dest);
}
}
void CopyFile(string fileName, string dest)
{
Directory.CreateDirectory(Path.GetDirectoryName(dest));
File.Copy(fileName, dest, true);
}
}
}

Просмотреть файл

@ -0,0 +1,59 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{7465574A-8830-4F80-8687-E1EA17BE5918}</ProjectGuid>
<OutputType>Exe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>exportsample</RootNamespace>
<AssemblyName>exportsample</AssemblyName>
<TargetPlatformIdentifier>Windows</TargetPlatformIdentifier>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<Import Project="$(MSBuildThisFileDirectory)..\..\build\Win2D.cs.props" />
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\shared\CommandLineParser.cs">
<Link>CommandLineParser.cs</Link>
</Compile>
<Compile Include="ConfigFile.cs" />
<Compile Include="Program.cs" />
<Compile Include="ProjectProcessor.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="SampleExporter.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<ItemGroup>
<Content Include="ExportSampleConfig.xml" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="$(MSBuildThisFileDirectory)..\..\build\Win2D.cs.targets" />
</Project>

Просмотреть файл

@ -11,13 +11,13 @@
// under the License.
using System;
using System.IO;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
namespace Shared
{

Просмотреть файл

@ -1,7 +1,6 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2013
VisualStudioVersion = 12.0.30303.0
VisualStudioVersion = 12.0.31101.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "codegen.exe", "codegen\exe\codegen.exe.csproj", "{984ABFAE-12D5-4929-AF2B-A733341BCCCF}"
EndProject
@ -25,6 +24,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "mock", "mock", "{A1494431-9
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "mock.test", "mock\test\mock.test.csproj", "{6FDE4A4E-DF4F-4823-B4C6-DCBD8D762D50}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "exportsample", "exportsample\exportsample.csproj", "{7465574A-8830-4F80-8687-E1EA17BE5918}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -63,6 +64,10 @@ Global
{6FDE4A4E-DF4F-4823-B4C6-DCBD8D762D50}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6FDE4A4E-DF4F-4823-B4C6-DCBD8D762D50}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6FDE4A4E-DF4F-4823-B4C6-DCBD8D762D50}.Release|Any CPU.Build.0 = Release|Any CPU
{7465574A-8830-4F80-8687-E1EA17BE5918}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7465574A-8830-4F80-8687-E1EA17BE5918}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7465574A-8830-4F80-8687-E1EA17BE5918}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7465574A-8830-4F80-8687-E1EA17BE5918}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE