From 8ed3f85c07795403fb1d466e560f7cb695ebce1b Mon Sep 17 00:00:00 2001 From: Manuel de la Pena Date: Tue, 5 Dec 2017 14:13:59 +0100 Subject: [PATCH] [Debugger] Allow to step into Xamarin code. (#1663) * [Debugger] Allow to step into Xamarin code. The tool now detects the different sources and mangles the path to ensure that the correct paths are installed in the following location: /Library/Frameworks/Xamarin.iOS/Versions/Current/src /Library/Frameworks/Xamarin.Mac/Versions/Current/src The tool will detect if the path map command was used in the mdb and pub files, will point to the correct source code and will copy it to the installation dir. Tests have been added that will be ran both by wrench and jenkins ensuring that changes in the manglers do not change it behaviour. --- Make.config | 15 +- builds/Makefile | 4 + src/Makefile | 2 + tests/Makefile | 7 + tests/xharness/Jenkins.cs | 20 ++ tools/install-source/IPathMangler.cs | 24 ++ .../InstallSourcesTests.csproj | 52 ++++ .../MonoPathManglerTest.cs | 48 ++++ .../InstallSourcesTests/OpenTKManglerTest.cs | 46 +++ .../PathManclerFactoryTests.cs | 107 +++++++ .../XamarinSourcesPathManglerTest.cs | 136 +++++++++ .../InstallSourcesTests/packages.config | 4 + tools/install-source/Makefile | 50 +++- tools/install-source/MonoPathMangler.cs | 52 ++++ tools/install-source/OpenTKSourceMangler.cs | 56 ++++ tools/install-source/PathManglerFactory.cs | 131 +++++++++ tools/install-source/Program.cs | 272 ++++++++++++++---- .../XamarinSourcesPathMangler.cs | 231 +++++++++++++++ tools/install-source/install-source.csproj | 24 +- tools/install-source/install-source.sln | 23 ++ 20 files changed, 1234 insertions(+), 70 deletions(-) create mode 100644 tools/install-source/IPathMangler.cs create mode 100644 tools/install-source/InstallSourcesTests/InstallSourcesTests.csproj create mode 100644 tools/install-source/InstallSourcesTests/MonoPathManglerTest.cs create mode 100644 tools/install-source/InstallSourcesTests/OpenTKManglerTest.cs create mode 100644 tools/install-source/InstallSourcesTests/PathManclerFactoryTests.cs create mode 100644 tools/install-source/InstallSourcesTests/XamarinSourcesPathManglerTest.cs create mode 100644 tools/install-source/InstallSourcesTests/packages.config create mode 100644 tools/install-source/MonoPathMangler.cs create mode 100644 tools/install-source/OpenTKSourceMangler.cs create mode 100644 tools/install-source/PathManglerFactory.cs create mode 100644 tools/install-source/XamarinSourcesPathMangler.cs create mode 100644 tools/install-source/install-source.sln diff --git a/Make.config b/Make.config index 65e586b361..942e32760d 100644 --- a/Make.config +++ b/Make.config @@ -291,10 +291,21 @@ include $(TOP)/mk/quiet.mk MDTOOL?="/Applications/Visual Studio.app/Contents/MacOS/vstool" $(MDTOOL_VERBOSITY) +IOS_SOURCE=$(TOP)/src +IOS_BUILD_SOURCE=$(IOS_SOURCE)/build/ios/native +IOS_COMMON_BUILD_SOURCE=$(IOS_SOURCE)/build/common +MAC_SOURCE=$(TOP)/src +MAC_FULL_BUILD_SOURCE=$(MAC_SOURCE)/build/mac/full +MAC_MODERN_BUILD_SOURCE=$(MAC_SOURCE)/build/mac/mobile +MAC_COMMON_BUILD_SOURCE=$(MAC_SOURCE)/build/common + ifneq ($(BUILD_REVISION),) # wrench build only -IOS_MCS_FLAGS=-pathmap:$(abspath $(MONO_PATH))/=$(IOS_FRAMEWORK_DIR)/Versions/$(IOS_PACKAGE_VERSION)/src/mono/ -MAC_MCS_FLAGS=-pathmap:$(abspath $(MONO_PATH))/=$(MAC_FRAMEWORK_DIR)/Versions/$(MAC_PACKAGE_VERSION)/src/mono/ +IOS_MCS_FLAGS="-pathmap:$(abspath $(MONO_PATH))/=$(IOS_FRAMEWORK_DIR)/Versions/$(IOS_PACKAGE_VERSION)/src/Xamarin.iOS/" +IOS_MCS_FLAGS_XI="-pathmap:$(abspath $(IOS_COMMON_BUILD_SOURCE))/=$(IOS_FRAMEWORK_DIR)/Versions/$(IOS_PACKAGE_VERSION)/src/Xamarin.iOS/ -pathmap:$(abspath $(IOS_BUILD_SOURCE))/=$(IOS_FRAMEWORK_DIR)/Versions/$(IOS_PACKAGE_VERSION)/src/Xamarin.iOS/ -pathmap:$(abspath $(IOS_SOURCE))/=$(IOS_FRAMEWORK_DIR)/Versions/$(IOS_PACKAGE_VERSION)/src/Xamarin.iOS/" + +MAC_MCS_FLAGS="-pathmap:$(abspath $(MONO_PATH))/=$(MAC_FRAMEWORK_DIR)/Versions/$(MAC_PACKAGE_VERSION)/src/Xamarin.Mac/" +MAC_MCS_FLAGS_XM="-pathmap:$(abspath $(MAC_COMMON_BUILD_SOURCE))/=$(MAC_FRAMEWORK_DIR)/Versions/$(MAC_PACKAGE_VERSION)/src/Xamarin.Mac/ -pathmap:$(abspath $(MAC_FULL_BUILD_SOURCE))/=$(MAC_FRAMEWORK_DIR)/Versions/$(MAC_PACKAGE_VERSION)/src/Xamarin.Mac/ -pathmap:$(abspath $(MAC_MODERN_BUILD_SOURCE))/=$(MAC_FRAMEWORK_DIR)/Versions/$(MAC_PACKAGE_VERSION)/src/Xamarin.Mac/ -pathmap:$(abspath $(MAC_SOURCE))/=$(MAC_FRAMEWORK_DIR)/Versions/$(MAC_PACKAGE_VERSION)/src/Xamarin.Mac/" endif ifdef ENABLE_XAMARIN diff --git a/builds/Makefile b/builds/Makefile index c892afaed7..ed9b69e74b 100644 --- a/builds/Makefile +++ b/builds/Makefile @@ -264,6 +264,10 @@ MAC_DIRECTORIES += \ $$(MAC_DESTDIR)$$(MAC_FRAMEWORK_CURRENT_DIR)/lib/mono/$(1)/%: $$(BUILD_DESTDIR)/bcl/$(2)/% | $$(MAC_DESTDIR)$$(MAC_FRAMEWORK_CURRENT_DIR)/lib/mono/$(1)/Facades $$(Q) install -m 0755 $$< $$@ + + +$$(MAC_DESTDIR)$$(MAC_FRAMEWORK_CURRENT_DIR)/lib/mono/$(1)/%.pdb: $$(BUILD_DESTDIR)/mac/$(2)/bcl/%.pdb | $$(MAC_DESTDIR)$$(MAC_FRAMEWORK_CURRENT_DIR)/lib/mono/$(1)/Facades + $$(Q) install -m 0644 $$< $$@ endef $(eval $(call MacInstallBclTemplate,Xamarin.Mac,xammac)) diff --git a/src/Makefile b/src/Makefile index 1d042e91be..0f295b271a 100644 --- a/src/Makefile +++ b/src/Makefile @@ -167,6 +167,7 @@ $(IOS_BUILD_DIR)/$(1)/$(3): $$(IOS_SOURCES) $(IOS_BUILD_DIR)/$(4)/generated_sour -r:$(IOS_LIBDIR)/Mono.Security.dll \ -keyfile:$(PRODUCT_KEY_PATH) $$(IOS_DEFINES) \ -nowarn:219,618,114,414,1635,3021,$$(IOS_WARNINGS_THAT_YOU_SHOULD_FIX) \ + $(IOS_MCS_FLAGS_XI) \ $$(IOS_SOURCES) @$(IOS_BUILD_DIR)/$(4)/generated_sources $(IOS_BUILD_DIR)/$(1)/$(3).mdb: $(IOS_BUILD_DIR)/$(1)/$(3) @@ -558,6 +559,7 @@ $(MAC_BUILD_DIR)/$(1)/$(2): $(MAC_BUILD_DIR)/$(3)/generated-sources $(MAC_SOURCE -r:Mono.Security.dll \ -keyfile:$(SN_KEY) \ -nowarn:3021,1635,612,618,0219,0414,$(MAC_WARNINGS_TO_FIX) \ + $(MAC_MCS_FLAGS_XM) \ $(4) \ @$$< $$(MAC_SOURCES) endef diff --git a/tests/Makefile b/tests/Makefile index f997e930e8..e95e5c0bdd 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -206,6 +206,13 @@ test-ios-tasks: @[[ -z "$$BUILD_REPOSITORY" ]] || ( xsltproc $(TOP)/tests/HtmlTransform.xslt $(NUNIT_MSBUILD_DIR)/TestResults_Xamarin.iOS.Tasks.Tests.xml > $(TOP)/tests/index.html && echo "@MonkeyWrench: AddFile: $$PWD/index.html" ) @if test -e $(NUNIT_MSBUILD_DIR)/.failed-stamp; then rm $(NUNIT_MSBUILD_DIR)/.failed-stamp; exit 1; fi +test-install-sources: + $(SYSTEM_XBUILD) $(TOP)/tools/install-source/InstallSourcesTests/InstallSourcesTests.csproj + cd $(NUNIT_MSBUILD_DIR) && $(SYSTEM_MONO) ../nunit-console.exe ../../../../tools/install-source/InstallSourcesTests/bin/Release/InstallSourcesTests.dll -xml=TestResults_InstallSourcesTests.xml -labels $(TEST_FIXTURE) || touch .failed-stamp + @[[ -z "$$BUILD_REPOSITORY" ]] || ( xsltproc $(TOP)/tests/HtmlTransform.xslt $(NUNIT_MSBUILD_DIR)/TestResults_InstallSourcesTests.xml > $(TOP)/tests/index.html && echo "@MonkeyWrench: AddFile: $$PWD/index.html" ) + @if test -e $(NUNIT_MSBUILD_DIR)/.failed-stamp; then rm $(NUNIT_MSBUILD_DIR)/.failed-stamp; exit 1; fi + + ifdef ENABLE_XAMARIN ifdef INCLUDE_IOS qa-test-dependencies.zip: diff --git a/tests/xharness/Jenkins.cs b/tests/xharness/Jenkins.cs index cd512be918..66fe57b0ec 100644 --- a/tests/xharness/Jenkins.cs +++ b/tests/xharness/Jenkins.cs @@ -518,6 +518,26 @@ namespace xharness }; Tasks.Add (nunitExecutioniOSMSBuild); + var buildInstallSources = new XBuildTask () + { + Jenkins = this, + TestProject = new TestProject (Path.GetFullPath (Path.Combine (Harness.RootDirectory, "..", "tools", "install-source", "InstallSourcesTests", "InstallSourcesTests.csproj"))), + SpecifyPlatform = false, + SpecifyConfiguration = false, + Platform = TestPlatform.iOS, + }; + var nunitExecutionInstallSource = new NUnitExecuteTask (buildInstallSources) + { + TestLibrary = Path.Combine (Harness.RootDirectory, "..", "tools", "install-source", "InstallSourcesTests", "bin", "Release", "InstallSourcesTests.dll"), + TestExecutable = Path.Combine (Harness.RootDirectory, "..", "packages", "NUnit.Runners.2.6.4", "tools", "nunit-console.exe"), + WorkingDirectory = Path.Combine (Harness.RootDirectory, "..", "packages", "NUnit.Runners.2.6.4", "tools", "lib"), + Platform = TestPlatform.iOS, + TestName = "Install Sources tests", + Mode = "iOS", + Timeout = TimeSpan.FromMinutes (60), + }; + Tasks.Add (nunitExecutionInstallSource); + foreach (var project in Harness.MacTestProjects) { bool ignored = !IncludeMac; if (!IncludeMmpTest && project.Path.Contains ("mmptest")) diff --git a/tools/install-source/IPathMangler.cs b/tools/install-source/IPathMangler.cs new file mode 100644 index 0000000000..fb46c50d30 --- /dev/null +++ b/tools/install-source/IPathMangler.cs @@ -0,0 +1,24 @@ +using System; + +namespace InstallSources +{ + /// + /// Represents a class that knows how to change paths to ensure that the correct source path is used. + /// + public interface IPathMangler + { + /// + /// Returns the real source path for the given path found in an mdb. + /// + /// The source path related to the mdb path. + /// The path found in the mdb file. + string GetSourcePath (string path); + + /// + /// Returns the target were a source path should be installed. + /// + /// The target path for the installation. + /// The source path to install./ + string GetTargetPath (string path); + } +} diff --git a/tools/install-source/InstallSourcesTests/InstallSourcesTests.csproj b/tools/install-source/InstallSourcesTests/InstallSourcesTests.csproj new file mode 100644 index 0000000000..ebc2c50660 --- /dev/null +++ b/tools/install-source/InstallSourcesTests/InstallSourcesTests.csproj @@ -0,0 +1,52 @@ + + + + Release + AnyCPU + {795E0F7E-5C48-4C90-8F66-518359874022} + Library + InstallSourcesTests + InstallSourcesTests + + + true + bin\Release + prompt + 4 + + + + + + ..\..\..\packages\NUnit.2.6.4\lib\nunit.framework.dll + + + Mono.Cecil.dll + + + + + + + + + + + IPathMangler.cs + + + MonoPathMangler.cs + + + OpenTKSourceMangler.cs + + + PathManglerFactory.cs + + + XamarinSourcesPathMangler.cs + + + + + \ No newline at end of file diff --git a/tools/install-source/InstallSourcesTests/MonoPathManglerTest.cs b/tools/install-source/InstallSourcesTests/MonoPathManglerTest.cs new file mode 100644 index 0000000000..8a178222ef --- /dev/null +++ b/tools/install-source/InstallSourcesTests/MonoPathManglerTest.cs @@ -0,0 +1,48 @@ +using System; +using NUnit.Framework; + +using InstallSources; + +namespace InstallSourcesTests +{ + [TestFixture] + public class MonoPathManglerTest + { + MonoPathMangler mangler; + string monoPath; + string installDir; + string destinationDir; + + [SetUp] + public void SetUp () + { + monoPath = "/Users/test/xamarin-macios/external/mono/"; + installDir = "/Users/test/xamarin-macios/_ios-build//Library/Frameworks/Xamarin.iOS.framework/Versions/git"; + destinationDir = "/Users/test/xamarin-macios/_ios-build/Library/Frameworks/Xamarin.iOS.framework/Versions/git"; + mangler = new MonoPathMangler { + InstallDir = installDir, + MonoSourcePath = monoPath, + DestinationDir = destinationDir, + }; + } + + [TestCase ("/Users/test/xamarin-macios/external/mono/mcs/class/Mono.Data.Tds/Mono.Data.Tds.Protocol/TdsAsyncState.cs")] + [TestCase ("/Users/test/xamarin-macios/external/mono/mcs/class/Mono.Security/Mono.Security.X509/X509StoreManager.cs")] + [TestCase ("/Users/test/xamarin-macios/external/mono/mcs/class/dlr/Runtime/Microsoft.Scripting.Core/Actions/UpdateDelegates.Generated.cs")] + public void TestGetSourcePath (string path) + { + Assert.AreEqual (path, mangler.GetSourcePath (path), "Failed getting path for '{0}'", path); + } + + [TestCase ("/Users/test/xamarin-macios/external/mono/mcs/class/Mono.Data.Tds/Mono.Data.Tds.Protocol/TdsAsyncState.cs")] + [TestCase ("/Users/test/xamarin-macios/external/mono/mcs/class/Mono.Security/Mono.Security.X509/X509StoreManager.cs")] + [TestCase ("/Users/test/xamarin-macios/external/mono/mcs/class/dlr/Runtime/Microsoft.Scripting.Core/Actions/UpdateDelegates.Generated.cs")] + public void TestGetTargetPath (string path) + { + var targetPath = mangler.GetTargetPath (path); + Assert.IsFalse (targetPath.StartsWith (monoPath, StringComparison.InvariantCulture), "Path starts with the mono path."); + Assert.IsTrue (targetPath.StartsWith (destinationDir, StringComparison.InvariantCulture), "Path does not start with the install dir"); + Assert.IsTrue (!targetPath.Contains ("mono"), "Path does contain 'mono'"); + } + } +} diff --git a/tools/install-source/InstallSourcesTests/OpenTKManglerTest.cs b/tools/install-source/InstallSourcesTests/OpenTKManglerTest.cs new file mode 100644 index 0000000000..948badfaf6 --- /dev/null +++ b/tools/install-source/InstallSourcesTests/OpenTKManglerTest.cs @@ -0,0 +1,46 @@ +using System; +using NUnit.Framework; + +using InstallSources; + +namespace InstallSourcesTests +{ + [TestFixture] + public class OpenTKManglerTest + { + OpenTKSourceMangler mangler; + string openTKPath; + string installDir; + string destinationDir; + + [SetUp] + public void SetUp () + { + openTKPath = "/Users/test/xamarin-macios/external/opentk/Source/"; + installDir = "/Users/test/xamarin-macios/_ios-build//Library/Frameworks/Xamarin.iOS.framework/Versions/git"; + destinationDir = "/Users/test/xamarin-macios/_ios-build/Library/Frameworks/Xamarin.iOS.framework/Versions/git"; + mangler = new OpenTKSourceMangler { + InstallDir = installDir, + OpenTKSourcePath = openTKPath, + DestinationDir = destinationDir, + }; + } + + [TestCase ("/Users/test/xamarin-macios/external/opentk/Source/OpenTK/Math/BezierCurve.cs")] + [TestCase ("/Users/test/xamarin-macios/external/opentk/Source/OpenTK/Math/BezierCurveCubic.cs")] + public void TestGetSourcePath (string path) + { + Assert.AreEqual (path, mangler.GetSourcePath (path), "Failed getting path for '{0}'", path); + } + + [TestCase ("/Users/test/xamarin-macios/external/opentk/Source/OpenTK/Math/BezierCurve.cs")] + [TestCase ("/Users/test/xamarin-macios/external/opentk/Source/OpenTK/Math/BezierCurveCubic.cs")] + public void TestGetTargetPath (string path) + { + var targetPath = mangler.GetTargetPath (path); + Assert.IsFalse (targetPath.StartsWith (openTKPath, StringComparison.InvariantCulture), "Path starts with the opentk path."); + Assert.IsTrue (targetPath.StartsWith (destinationDir, StringComparison.InvariantCulture), "Path does not start with the install dir"); + Assert.IsTrue (targetPath.Contains ("/src/Xamarin.iOS/"), "Path does not contain 'src'"); + } + } +} diff --git a/tools/install-source/InstallSourcesTests/PathManclerFactoryTests.cs b/tools/install-source/InstallSourcesTests/PathManclerFactoryTests.cs new file mode 100644 index 0000000000..852f1302f6 --- /dev/null +++ b/tools/install-source/InstallSourcesTests/PathManclerFactoryTests.cs @@ -0,0 +1,107 @@ +using System.IO; +using NUnit.Framework; + +using InstallSources; + +namespace InstallSourcesTests +{ + [TestFixture] + public class PathManclerFactoryTests + { + string tmpRoot; + string installDir; + string fakeMonoPath; + string fakeOpenTKPath; + string fakeXamarinPath; + + PathManglerFactory factory; + + void CreateFakeFile (string path) + { + string[] lines = { "Test", "Fake", "file" }; + using (StreamWriter outputFile = new StreamWriter (path)) { + foreach (string line in lines) + outputFile.WriteLine(line); + } + } + + [SetUp] + public void SetUp () + { + installDir = Path.GetTempFileName (); + if (File.Exists (installDir)) + File.Delete (installDir); + installDir = Path.Combine (installDir, "Xamarin.iOS"); + Directory.CreateDirectory (installDir); + // create temp dirs that will be used to place some files + // to test their presence and decide that the correct + // mangler is used + tmpRoot = Path.GetTempFileName (); + if (File.Exists (tmpRoot)) + File.Delete (tmpRoot); + Directory.CreateDirectory (tmpRoot); + + // create a path for the mono paths + var monoPath = Path.Combine (tmpRoot, "external", "mono"); + Directory.CreateDirectory (monoPath); + fakeMonoPath = Path.Combine (monoPath, "FakeStirng.cs"); + CreateFakeFile (fakeMonoPath); + + // create a path for the xamarin paths + var xamarinPath = Path.Combine (tmpRoot, "src"); + Directory.CreateDirectory (xamarinPath); + fakeXamarinPath = Path.Combine (xamarinPath, "FakeObjc.cs"); + CreateFakeFile (fakeXamarinPath); + + var openTKPath = Path.Combine (tmpRoot, "external", "OpenTK"); + Directory.CreateDirectory (Path.Combine (openTKPath)); + fakeOpenTKPath = Path.Combine (openTKPath, "FakeMaths.cs"); + CreateFakeFile (fakeOpenTKPath); + + factory = new PathManglerFactory() + { + InstallDir = installDir, + MonoSourcePath = monoPath, + XamarinSourcePath = xamarinPath, + OpenTKSourcePath = openTKPath + }; + } + + [TearDown] + public void TearDown () + { + if (Directory.Exists (tmpRoot)) + Directory.Delete (tmpRoot, true); + if (Directory.Exists (installDir)) + Directory.Delete (installDir); + } + + [Test] + public void TestIsMonoPath () + { + var monoPathMap = fakeMonoPath.Replace (factory.MonoSourcePath, Path.Combine (installDir, "src", "Xamarin.iOS")); + var xamarinPathMap = fakeXamarinPath.Replace(factory.XamarinSourcePath, Path.Combine (installDir, "src", "Xamarin.iOS")); + Assert.IsTrue (factory.IsMonoPath (monoPathMap), "Present mono path"); + Assert.IsFalse (factory.IsMonoPath (xamarinPathMap), "Present xamarin path"); + + } + + [Test] + public void TestIsOpenTKPath () + { + var openTKPathMap = fakeMonoPath.Replace (factory.OpenTKSourcePath, Path.Combine (installDir, "src", "Xamarin.iOS")); + var xamarinPathMap = fakeXamarinPath.Replace(factory.XamarinSourcePath, Path.Combine (installDir, "src", "Xamarin.iOS")); + Assert.IsTrue (factory.IsMonoPath (openTKPathMap), "Present openTK path"); + Assert.IsFalse (factory.IsMonoPath (xamarinPathMap), "Present xamarin path"); + } + + [Test] + public void TestPathIsIgnored () + { + var pathToIgnore = Path.Combine (factory.MonoSourcePath, "mcs", "mcs", "Foo.cs"); + var pathNotToIgnore = Path.Combine (factory.MonoSourcePath, "mcs", "class", "Foo.cs"); + Assert.IsTrue (factory.IsIgnored (pathToIgnore), "Do ignore."); + Assert.IsFalse (factory.IsIgnored (pathNotToIgnore), "Do NOT ignore."); + } + } +} diff --git a/tools/install-source/InstallSourcesTests/XamarinSourcesPathManglerTest.cs b/tools/install-source/InstallSourcesTests/XamarinSourcesPathManglerTest.cs new file mode 100644 index 0000000000..33112ab7c3 --- /dev/null +++ b/tools/install-source/InstallSourcesTests/XamarinSourcesPathManglerTest.cs @@ -0,0 +1,136 @@ +using System; +using NUnit.Framework; + +using InstallSources; + +namespace InstallSourcesTests +{ + [TestFixture] + public class XamarinSourcesPathManglerTest + { + string frameworkPath; + string xamarinSourcePath; + string installDir; + string destinationDir; + XamarinSourcesPathMangler mangler; + + [SetUp] + public void SetUp () + { + frameworkPath = "Xamarin.iOS.framework"; + xamarinSourcePath = "/Users/test/xamarin-macios/src/"; + installDir = "/Library/Frameworks/Xamarin.iOS.framework/Versions/4.1.0.402"; + destinationDir = "/Users/test/xamarin-macios/_ios-build/Library/Frameworks/Xamarin.iOS.framework/Versions/git"; + + mangler = new XamarinSourcesPathMangler { + FrameworkPath = frameworkPath, + XamarinSourcePath = xamarinSourcePath, + InstallDir = installDir, + DestinationDir = destinationDir, + }; + } + + [TestCase ("/Library/Frameworks/Xamarin.iOS.framework/Versions/4.1.0.402/src/Xamarin.iOS/CoreData/NSEntityMapping.g.cs", + "/Users/test/xamarin-macios/src/build/ios/native/CoreData/NSEntityMapping.g.cs")] + [TestCase ("/Users/test/xamarin-macios/_ios-build/Library/Frameworks/Xamarin.iOS.framework/Versions/git/src/Xamarin.iOS/build/ios/native/AVFoundation/AVMutableTimedMetadataGroup.g.cs", + "/Users/test/xamarin-macios/src/build/ios/native/AVFoundation/AVMutableTimedMetadataGroup.g.cs")] + [TestCase ("/Users/test/xamarin-macios/_ios-build/Library/Frameworks/Xamarin.iOS.framework/Versions/git/src/Xamarin.iOS/build/ios/native/CloudKit/CKRecordZoneNotification.g.cs", + "/Users/test/xamarin-macios/src/build/ios/native/CloudKit/CKRecordZoneNotification.g.cs")] + public void TestGetSourcePathGeneratediOSCode (string path, string expectedPath) + { + var result = mangler.GetSourcePath (path); + Assert.IsTrue (result.Contains ("/build/"), "Path does not contain '/build/'"); + Assert.IsTrue (result.StartsWith(xamarinSourcePath, StringComparison.InvariantCulture), "Path does not start with the XamarinPath '{0}'", xamarinSourcePath); + Assert.AreEqual (result, expectedPath); + } + + [TestCase ("/Library/Frameworks/Xamarin.Mac.framework/Versions/4.1.0.402/src/Xamarin.iOS/CoreData/NSEntityMapping.g.cs", + "/Users/test/xamarin-macios/src/build/mac/full/CoreData/NSEntityMapping.g.cs")] + [TestCase ("/Users/test/xamarin-macios/_mac-build/Library/Frameworks/Xamarin.Mac.framework/Versions/git/src/Xamarin.Mac/build/mac/full/AVFoundation/AVMutableTimedMetadataGroup.g.cs", + "/Users/test/xamarin-macios/src/build/mac/full/AVFoundation/AVMutableTimedMetadataGroup.g.cs")] + [TestCase ("/Users/test/xamarin-macios/_mac-build/Library/Frameworks/Xamarin.Mac.framework/Versions/git/src/Xamarin.Mac/build/mac/full/CloudKit/CKRecordZoneNotification.g.cs", + "/Users/test/xamarin-macios/src/build/mac/full/CloudKit/CKRecordZoneNotification.g.cs")] + public void TestGetSourcePathGeneratedMacCode (string path, string expectedPath) + { + mangler.FrameworkPath = "Xamarin.Mac.framework"; // dealing with mac sources + mangler.InstallDir = "/Library/Frameworks/Xamarin.Mac.framework/Versions/4.1.0.402/"; + var result = mangler.GetSourcePath (path); + Assert.IsTrue (result.Contains ("/build/"), "Path does not contain '/build/'"); + Assert.IsTrue (result.StartsWith (xamarinSourcePath, StringComparison.InvariantCulture), "Path does not start with the XamarinPath '{0}'", xamarinSourcePath); + Assert.AreEqual (expectedPath, result); + } + + [TestCase ("/Users/test/xamarin-macios/runtime/Delegates.generated.cs", "/Users/test/xamarin-macios/runtime/Delegates.generated.cs")] + public void TestGetSourceRuntimeCode (string path, string expectedPath) + { + var result = mangler.GetSourcePath (path); + Assert.AreEqual (result, expectedPath); + } + + [TestCase ("/Library/Frameworks/Xamarin.iOS.framework/Versions/4.1.0.402/src/Xamarin.iOS/AVFoundation/AVCaptureDeviceInput.cs", + "/Users/test/xamarin-macios/src/AVFoundation/AVCaptureDeviceInput.cs")] + [TestCase ("/Users/test/xamarin-macios/_ios-build/Library/Frameworks/Xamarin.iOS.framework/Versions/git/src/Xamarin.iOS/CoreImage/CIImage.cs", + "/Users/test/xamarin-macios/src/CoreImage/CIImage.cs")] + [TestCase ("/Users/test/xamarin-macios/_ios-build/Library/Frameworks/Xamarin.iOS.framework/Versions/git/src/Xamarin.iOS/CoreData/NSAttributeDescription.cs", + "/Users/test/xamarin-macios/src/CoreData/NSAttributeDescription.cs")] + [TestCase ("/Users/test/xamarin-macios/src/CoreData/NSAttributeDescription.cs", + "/Users/test/xamarin-macios/src/CoreData/NSAttributeDescription.cs")] + public void TestGetSourcePathManualCode (string path, string expectedPath) + { + var result = mangler.GetSourcePath(path); + Assert.IsFalse (result.Contains ("/build/"), "Path contains '/build/' when it is a manual path."); + Assert.IsTrue (result.StartsWith (xamarinSourcePath, StringComparison.InvariantCulture), "Path does not start with the XamarinPath '{0}'", xamarinSourcePath); + Assert.AreEqual (result, expectedPath); + } + + [TestCase ("/Library/Frameworks/Xamarin.iOS.framework/Versions/4.1.0.402/src/Xamarin.iOS/NativeTypes/NMath.cs", + "/Users/test/xamarin-macios/src/NativeTypes/NMath.cs")] + [TestCase ("/Users/test/xamarin-macios/_ios-build/Library/Frameworks/Xamarin.iOS.framework/Versions/git/src/Xamarin.iOS/build/common/NativeTypes/Drawing.cs", + "/Users/test/xamarin-macios/src/build/common/NativeTypes/Drawing.cs")] + [TestCase ("/Users/test/xamarin-macios/_ios-build/Library/Frameworks/Xamarin.iOS.framework/Versions/git/src/Xamarin.iOS/build/common/NativeTypes/Primitives.cs", + "/Users/test/xamarin-macios/src/build/common/NativeTypes/Primitives.cs")] + public void TestGetSourcePathNativeTypes (string path, string expectedPath) + { + var result = mangler.GetSourcePath(path); + Assert.IsTrue(result.StartsWith(xamarinSourcePath, StringComparison.InvariantCulture), "Path does not start with the XamarinPath '{0}'", xamarinSourcePath); + Assert.AreEqual (result, expectedPath); + } + + [TestCase ("/Users/test/xamarin-macios/src/build/ios/native/AVFoundation/AVMutableMetadataItem.g.cs", "/Users/test/xamarin-macios/_ios-build/Library/Frameworks/Xamarin.iOS.framework/Versions/git/src/Xamarin.iOS/AVFoundation/AVMutableMetadataItem.g.cs")] + [TestCase ("/Users/test/xamarin-macios/src/AVFoundation/AVCaptureDeviceInput.cs", "/Users/test/xamarin-macios/_ios-build/Library/Frameworks/Xamarin.iOS.framework/Versions/git/src/Xamarin.iOS/AVFoundation/AVCaptureDeviceInput.cs")] + [TestCase ("/Users/test/xamarin-macios/src/NativeTypes/NMath.cs", "/Users/test/xamarin-macios/_ios-build/Library/Frameworks/Xamarin.iOS.framework/Versions/git/src/Xamarin.iOS/NativeTypes/NMath.cs")] + public void TestGetTargetPathiOS (string src, string expectedTarget) + { + var target = mangler.GetTargetPath (src); + + Assert.IsTrue (target.StartsWith (destinationDir, StringComparison.InvariantCulture), "Does not contain the install dir."); + Assert.AreEqual (expectedTarget, target, "Target is not the expected one."); + } + + [TestCase ("/Users/test/xamarin-macios/src/build/mac/full/AVFoundation/AVMutableMetadataItem.g.cs", "/Users/test/xamarin-macios/_mac-build/Library/Frameworks/Xamarin.Mac.framework/Versions/git/src/Xamarin.Mac/AVFoundation/AVMutableMetadataItem.g.cs")] + [TestCase ("/Users/test/xamarin-macios/src/AVFoundation/AVCaptureDeviceInput.cs", "/Users/test/xamarin-macios/_mac-build/Library/Frameworks/Xamarin.Mac.framework/Versions/git/src/Xamarin.Mac/AVFoundation/AVCaptureDeviceInput.cs")] + [TestCase ("/Users/test/xamarin-macios/src/NativeTypes/NMath.cs", "/Users/test/xamarin-macios/_mac-build/Library/Frameworks/Xamarin.Mac.framework/Versions/git/src/Xamarin.Mac/NativeTypes/NMath.cs")] + public void TestGetTargetPathMac (string src, string expectedTarget) + { + mangler.FrameworkPath = "Xamarin.Mac.framework"; // dealing with mac sources + mangler.InstallDir = "/Library/Frameworks/Xamarin.Mac.framework"; + mangler.DestinationDir = "/Users/test/xamarin-macios/_mac-build/Library/Frameworks/Xamarin.Mac.framework/Versions/git"; + + var target = mangler.GetTargetPath (src); + + Assert.IsTrue (target.StartsWith (mangler.DestinationDir, StringComparison.InvariantCulture), "Does not contain the install dir."); + Assert.AreEqual (expectedTarget, target, "Target is not the expected one."); + } + + [TestCase ("/Library/Frameworks/Xamarin.iOS.framework/Versions/4.1.0.402/src/Xamarin.iOS/Delegates.generated.cs", + "/Users/test/xamarin-macios/runtime/Delegates.generated.cs")] + [TestCase ("/Users/test/xamarin-macios/src/Xamarin.iOS/runtime/Delegates.generated.cs", + "/Users/test/xamarin-macios/src/Xamarin.iOS/runtime/Delegates.generated.cs")] + public void TestGetSourcePathRuntime (string path, string expectedPath) + { + var result = mangler.GetSourcePath (path); + Assert.AreEqual (expectedPath, result); + } + + } +} diff --git a/tools/install-source/InstallSourcesTests/packages.config b/tools/install-source/InstallSourcesTests/packages.config new file mode 100644 index 0000000000..c714ef3a23 --- /dev/null +++ b/tools/install-source/InstallSourcesTests/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/tools/install-source/Makefile b/tools/install-source/Makefile index 3a75a9d638..2fe2cd3c0e 100644 --- a/tools/install-source/Makefile +++ b/tools/install-source/Makefile @@ -1,4 +1,5 @@ TOP=../.. +SRC_PATH=$(TOP)/src include $(TOP)/Make.config ifdef INCLUDE_IOS @@ -8,23 +9,62 @@ ifdef INCLUDE_MAC install-local:: install-source-mac endif +CECIL_PATH=$(MONO_PATH)/external/cecil +CECIL_CONFIG=net_4_0_Release +MONO_CECIL_DLL=$(CECIL_PATH)/bin/$(CECIL_CONFIG)/Mono.Cecil.dll +MONO_CECIL_FILES=$(wildcard $(CECIL_PATH)/*.cs) $(wildcard $(CECIL_PATH)/*/*.cs) $(wildcard $(CECIL_PATH)/*/*/*.cs) $(wildcard $(CECIL_PATH)/*/*/*/*.cs) $(wildcard $(CECIL_PATH)/*/*/*/*/*.cs) +MONO_CECIL_PDB_FILES=$(wildcard $(CECIL_PATH)/symbols/pdb/*.cs) $(wildcard $(CECIL_PATH)/symbols/pdb/*/*.cs) $(wildcard $(CECIL_PATH)/symbols/pdb/*/*/*.cs) $(wildcard $(CECIL_PATH)/symbols/pdb/*/*/*/*.cs) $(wildcard $(CECIL_PATH)/symbols/pdb/*/*/*/*/*.cs) + +Mono.Cecil.Pdb.dll: $(MONO_CECIL_PDB_FILES) + $(Q_XBUILD) cd $(CECIL_PATH)/symbols/pdb/ && $(SYSTEM_XBUILD) /p:Configuration=$(CECIL_CONFIG) Mono.Cecil.Pdb.csproj $(XBUILD_VERBOSITY) + $(Q) cp $(CECIL_PATH)/bin/$(CECIL_CONFIG)/*.dll $(dir $@) + +$(MONO_CECIL_DLL): $(CECIL_PATH)/Mono.Cecil.csproj $(MONO_CECIL_FILES) + $(Q_XBUILD) cd $(CECIL_PATH) && $(SYSTEM_XBUILD) /p:Configuration=$(CECIL_CONFIG) Mono.Cecil.csproj $(XBUILD_VERBOSITY) + +Mono.Cecil.dll: $(MONO_CECIL_DLL) + $(Q) cp $<* $(dir $@) + IOS_ASSEMBLIES = \ - $(wildcard $(MONO_PATH)/mcs/class/lib/monotouch/*.mdb) + $(wildcard $(MONO_PATH)/mcs/class/lib/monotouch/*.pdb) \ + $(IOS_DESTDIR)$(MONOTOUCH_PREFIX)/lib/64bits/Xamarin.iOS.dll.mdb MAC_ASSEMBLIES = \ - $(wildcard $(MONO_PATH)/mcs/class/lib/xammac/*.mdb) + $(wildcard $(MONO_PATH)/mcs/class/lib/xammac/*.pdb) \ + $(MAC_DESTDIR)$(MAC_FRAMEWORK_CURRENT_DIR)/lib/mono/4.5/Xamarin.Mac.dll.mdb + +IOS_MDB_FILES = \ + $(IOS_DESTDIR)$(MONOTOUCH_PREFIX)/lib/64bits/Xamarin.iOS.dll \ + $(IOS_DESTDIR)$(MONOTOUCH_PREFIX)/lib/32bits/Xamarin.iOS.dll + +MAC_MDB_FILES = \ + $(MAC_DESTDIR)$(MAC_FRAMEWORK_CURRENT_DIR)/lib/x86_64/mobile/Xamarin.Mac.dll.mdb \ + $(MAC_DESTDIR)$(MAC_FRAMEWORK_CURRENT_DIR)/lib/i386/mobile/Xamarin.Mac.dll.mdb \ + $(MAC_DESTDIR)$(MAC_FRAMEWORK_CURRENT_DIR)/lib/reference/full/Xamarin.Mac.dll.mdb \ + $(MAC_DESTDIR)$(MAC_FRAMEWORK_CURRENT_DIR)/lib/x86_64/full/Xamarin.Mac.dll.mdb \ + $(MAC_DESTDIR)$(MAC_FRAMEWORK_CURRENT_DIR)/lib/i386/full/Xamarin.Mac.dll.mdb \ + $(MAC_DESTDIR)$(MAC_FRAMEWORK_CURRENT_DIR)/lib/mono/XamMac.CFNetwork.dll.mdb \ + $(MAC_DESTDIR)$(MAC_FRAMEWORK_CURRENT_DIR)/lib/mono/Xamarin.Mac/Xamarin.Mac.dll.mdb \ + $(MAC_DESTDIR)$(MAC_FRAMEWORK_CURRENT_DIR)/lib/mono/4.5/Xamarin.Mac.dll.mdb install-source-ios: install-source.exe @echo "Installing source files for Xamarin.iOS" - $(Q) $(SYSTEM_MONO) install-source.exe $(IOS_ASSEMBLIES) --link:$(USE_SOURCE_LINKS) --mono-path=$(abspath $(MONO_PATH)) --install-dir=$(abspath $(IOS_DESTDIR))/$(abspath $(MONOTOUCH_PREFIX)) + $(Q) $(SYSTEM_MONO) install-source.exe $(IOS_ASSEMBLIES) --link:$(USE_SOURCE_LINKS) -v --mono-path=$(abspath $(MONO_PATH)) --opentk-path=$(abspath $(OPENTK_PATH)/Source) --xamarin-path=$(abspath $(SRC_PATH)) --install-dir=$(IOS_FRAMEWORK_DIR)/Versions/$(IOS_PACKAGE_VERSION) --destination-dir=$(abspath $(IOS_DESTDIR))$(abspath $(MONOTOUCH_PREFIX)) install-source-mac: install-source.exe @echo "Installing source files for Xamarin.Mac" - $(Q) $(SYSTEM_MONO) install-source.exe $(MAC_ASSEMBLIES) --link:$(USE_SOURCE_LINKS) --mono-path=$(abspath $(MONO_PATH)) --install-dir=$(abspath $(MAC_DESTDIR)/$(MAC_FRAMEWORK_CURRENT_DIR)) + $(Q) $(SYSTEM_MONO) install-source.exe $(MAC_ASSEMBLIES) --link:$(USE_SOURCE_LINKS) -v --mono-path=$(abspath $(MONO_PATH)) --opentk-path=$(abspath $(OPENTK_PATH)/Source) --xamarin-path=$(abspath $(SRC_PATH)) --install-dir=$(MAC_FRAMEWORK_DIR)/Versions/$(MAC_PACKAGE_VERSION) --destination-dir=$(abspath $(MAC_DESTDIR)/$(MAC_FRAMEWORK_CURRENT_DIR)) + IOS_SOURCES = \ + IPathMangler.cs \ + MonoPathMangler.cs \ + OpenTKSourceMangler.cs \ + PathManglerFactory.cs \ Program.cs \ + XamarinSourcesPathMangler.cs \ $(MONO_PATH)/mcs/class/Mono.Options/Mono.Options/Options.cs -install-source.exe: $(IOS_SOURCES) Makefile install-source.csproj + +install-source.exe: Mono.Cecil.dll Mono.Cecil.Pdb.dll $(IOS_SOURCES) Makefile install-source.csproj $(MONO_CECIL_DLL) $(Q_XBUILD) $(SYSTEM_XBUILD) install-source.csproj $(XBUILD_VERBOSITY) diff --git a/tools/install-source/MonoPathMangler.cs b/tools/install-source/MonoPathMangler.cs new file mode 100644 index 0000000000..63430f61e6 --- /dev/null +++ b/tools/install-source/MonoPathMangler.cs @@ -0,0 +1,52 @@ +using System; +using System.IO; + +namespace InstallSources +{ + public class MonoPathMangler : IPathMangler + { + static readonly string iOSFramework = "Xamarin.iOS/"; + static readonly string MacFramework = "Xamarin.Mac/"; + /// + /// Gets and sets the location of the mono sources. + /// + /// The mono source path. + public string MonoSourcePath { get; set; } + + /// + /// Gets or sets the frame work dir. + /// + /// The frame work dir. + public string DestinationDir { get; set; } + + /// + /// Gets or sets the install dir. + /// + /// The install dir. + public string InstallDir { get; set; } + + public string GetSourcePath (string path) + { + bool iosFramework = true; + if (path.StartsWith(MonoSourcePath, StringComparison.Ordinal)) + return path; + // we are dealing with a package build + var index = path.IndexOf (iOSFramework, StringComparison.Ordinal); + if (index < 0) {// we are dealing with mac sources + iosFramework = false; + index = path.IndexOf(MacFramework, StringComparison.Ordinal); + } + path = path.Remove (0, index + ((iosFramework)?iOSFramework.Length : MacFramework.Length)); // + length framework + return Path.Combine (MonoSourcePath, path); + } + + public string GetTargetPath (string path) + { + var relativePath = path.Substring (MonoSourcePath.Length); + if (relativePath.StartsWith ("/", StringComparison.Ordinal)) + relativePath = relativePath.Remove (0, 1); + var target = Path.Combine (DestinationDir, "src", (InstallDir.Contains("Xamarin.iOS")?"Xamarin.iOS":"Xamarin.Mac"), relativePath); + return target; + } + } +} diff --git a/tools/install-source/OpenTKSourceMangler.cs b/tools/install-source/OpenTKSourceMangler.cs new file mode 100644 index 0000000000..3a95ef4a4a --- /dev/null +++ b/tools/install-source/OpenTKSourceMangler.cs @@ -0,0 +1,56 @@ +using System; +using System.IO; + +namespace InstallSources +{ + /// + /// Path manipulator that knows how to deal with OpenTK paths. + /// + public class OpenTKSourceMangler : IPathMangler + { + static readonly string iOSFramework = "Xamarin.iOS/"; + static readonly string MacFramework = "Xamarin.Mac/"; + + /// + /// Locations of the OpenTK source. + /// + /// The OpenTK source path. + public string OpenTKSourcePath { get; set; } + + /// + /// Gets or sets the install dir. + /// + /// The install dir. + public string InstallDir { get; set;} + + /// + /// Gets or sets the frame work dir. + /// + /// The frame work dir. + public string DestinationDir { get; set; } + + public string GetSourcePath (string path) + { + bool iosFramework = true; + if (path.StartsWith (OpenTKSourcePath, StringComparison.Ordinal)) + return path; + // we are dealing with a package build + var index = path.IndexOf (iOSFramework, StringComparison.Ordinal); + if (index < 0) {// we are dealing with mac sources + iosFramework = false; + index = path.IndexOf(MacFramework, StringComparison.Ordinal); + } + path = path.Remove (0, index + ((iosFramework)?iOSFramework.Length : MacFramework.Length)); // + length framework + return Path.Combine (OpenTKSourcePath, path); + } + + public string GetTargetPath (string path) + { + var relativePath = path.Substring (OpenTKSourcePath.Length); + if (relativePath.StartsWith ("/", StringComparison.Ordinal)) + relativePath = relativePath.Remove (0, 1); + var target = Path.Combine (DestinationDir, "src", (InstallDir.Contains ("Xamarin.iOS") ? "Xamarin.iOS" : "Xamarin.Mac"), relativePath); + return target; + } + } +} diff --git a/tools/install-source/PathManglerFactory.cs b/tools/install-source/PathManglerFactory.cs new file mode 100644 index 0000000000..461f36b529 --- /dev/null +++ b/tools/install-source/PathManglerFactory.cs @@ -0,0 +1,131 @@ +using System; +using System.IO; + +namespace InstallSources +{ + public class PathManglerFactory + { + public bool Verbose { get; set; } + public string InstallDir { get; set; } + public string DestinationDir { get; set; } + public string MonoSourcePath { get; set; } + public string XamarinSourcePath { get; set; } + public string FrameworkPath { get; set; } + public string OpenTKSourcePath { get; set; } + + MonoPathMangler monoMangler; + OpenTKSourceMangler openTKMangler; + XamarinSourcesPathMangler xamarinPathMangler; + + readonly string srcSubPath = "src"; + readonly string runtimeSubPath = "runtime"; + readonly string xamariniOSDir = "Xamarin.iOS"; + readonly string xamarinMacDir = "Xamarin.Mac"; + + MonoPathMangler MonoPathMangler { + get { + if (monoMangler == null) + monoMangler = new MonoPathMangler { + InstallDir = InstallDir, + DestinationDir = DestinationDir, + MonoSourcePath = MonoSourcePath + }; + return monoMangler; + } + } + + OpenTKSourceMangler OpenTKSourceMangler { + get { + if (openTKMangler == null) + openTKMangler = new OpenTKSourceMangler { + InstallDir = InstallDir, + DestinationDir = DestinationDir, + OpenTKSourcePath = OpenTKSourcePath + }; + return openTKMangler; + } + } + + XamarinSourcesPathMangler XamarinSourcesPathMangler { + get { + if (xamarinPathMangler == null) + xamarinPathMangler = new XamarinSourcesPathMangler { + InstallDir = InstallDir, + DestinationDir = DestinationDir, + XamarinSourcePath = XamarinSourcePath, + FrameworkPath = FrameworkPath + }; + return xamarinPathMangler; + } + } + + public bool IsMonoPath (string path) + { + // remove the intall dir and append the mono source path + if (path.StartsWith(InstallDir, StringComparison.Ordinal)) { + // dealing with the jenkins paths + if (Verbose) { + Console.WriteLine($"Install dir is {InstallDir}"); + Console.WriteLine($"Original path os {path}"); + } + + var srcDir = Path.Combine(InstallDir, srcSubPath, + (InstallDir.Contains(xamariniOSDir) ? xamariniOSDir : xamarinMacDir)); + if (Verbose) + Console.WriteLine($"Src path to remove {srcDir}"); + var relative = path.Remove(0, srcDir.Length); + if (Verbose) + Console.WriteLine($"Relative path is {relative}"); + if (relative.StartsWith("/", StringComparison.Ordinal)) + relative = relative.Remove(0, 1); + var monoPath = Path.Combine(MonoSourcePath, relative); + if (Verbose) + Console.WriteLine($"Mono path is {monoPath}"); + return File.Exists(monoPath); + } + if (path.StartsWith (XamarinSourcePath, StringComparison.Ordinal)) + return false; + var xamarinRuntimePath = XamarinSourcePath.Replace($"/{srcSubPath}/", $"/{runtimeSubPath}/"); + if (path.StartsWith (xamarinRuntimePath, StringComparison.Ordinal)) + return false; + return path.StartsWith (MonoSourcePath, StringComparison.Ordinal); + } + + public bool IsOpenTKPath (string path) + { + if (path.StartsWith(InstallDir, StringComparison.Ordinal)) { + // dealing with the jenkins paths + var srcDir = Path.Combine (InstallDir, srcSubPath, + (InstallDir.Contains(xamariniOSDir) ? xamariniOSDir : xamarinMacDir)); + var relative = path.Remove (0, srcDir.Length); + if (relative.StartsWith("/", StringComparison.Ordinal)) + relative = relative.Remove (0, 1); + var openTKPath = Path.Combine (OpenTKSourcePath, relative); + return File.Exists(openTKPath); + } else { + return path.Contains(OpenTKSourcePath); + } + } + + public bool IsIgnored (string path) + { + return path.Contains ("/mcs/mcs/"); + } + + public IPathMangler GetMangler (string path) + { + if (IsIgnored(path)) + return null; + + if (IsOpenTKPath (path)) { + return OpenTKSourceMangler; + } + + if (IsMonoPath(path)) { + return MonoPathMangler; + } + + return XamarinSourcesPathMangler; + } + } +} diff --git a/tools/install-source/Program.cs b/tools/install-source/Program.cs index 3bcb13eeda..27c5443d05 100644 --- a/tools/install-source/Program.cs +++ b/tools/install-source/Program.cs @@ -1,11 +1,19 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; using Mono.CompilerServices.SymbolWriter; using Mono.Options; using Mono.Unix; +using Mono.Cecil; +using Mono.Cecil.Cil; +using Mono.Cecil.Pdb; + + +using InstallSources; + public class ListSourceFiles { static bool ParseBool (string value) { @@ -25,87 +33,247 @@ public class ListSourceFiles { return bool.Parse (value); } } - public static void Main (string[] arguments) + + public static string FixPathEnding(string path) + { + if (!path.EndsWith (Path.DirectorySeparatorChar.ToString (), StringComparison.Ordinal)) + return path + Path.DirectorySeparatorChar; + return path; + } + + // returns a tuple with the pdb files as the first value and the mdb files as the second + public static Tuple , HashSet> GetSplittedPaths (List paths) + { + var splittedPaths = new Tuple, HashSet> (new HashSet (), new HashSet ()); + foreach (var p in paths) { + if (p.EndsWith (".pdb", StringComparison.Ordinal)) { + splittedPaths.Item1.Add (p); + continue; + } + if (p.EndsWith (".mdb", StringComparison.Ordinal)) { + splittedPaths.Item2.Add (p); + continue; + } + } + return splittedPaths; + } + + // returns the source paths used to create an assembly that has an mdb file + public static HashSet GetFilePathsFromMdb (string mdb_file) + { + var srcs = new HashSet (); + MonoSymbolFile symfile; + + try { + symfile = MonoSymbolFile.ReadSymbolFile(mdb_file); + srcs.UnionWith (from src in symfile.Sources select src.FileName); + + } catch (IOException ioe) { + Console.WriteLine("IO error while reading msb file '{0}': {1}", mdb_file, ioe.Message); + } + + return srcs; + } + + // returns the source paths used to create an assembly that has a pdb file + public static HashSet GetFilePathsFromPdb (string pdbFile) + { + var pdb = Path.ChangeExtension (pdbFile, ".dll"); + + var result = new HashSet (StringComparer.OrdinalIgnoreCase); + + if (!File.Exists (pdbFile)) + return result; + + var assemblyResolver = new DefaultAssemblyResolver (); + var assemblyLocation = Path.GetDirectoryName (pdb); + assemblyResolver.AddSearchDirectory (assemblyLocation); + + var readerParameters = new ReaderParameters { AssemblyResolver = assemblyResolver }; + var writerParameters = new WriterParameters (); + + var symbolReaderProvider = new PortablePdbReaderProvider (); + readerParameters.SymbolReaderProvider = symbolReaderProvider; + readerParameters.ReadSymbols = true; + + var assemblyDefinition = AssemblyDefinition.ReadAssembly (pdb, readerParameters); + var mainModule = assemblyDefinition.MainModule; + foreach (var type in mainModule.Types) { + foreach (var method in type.Methods) { + if (method.DebugInformation.SequencePoints.Any ()) { + var sequence_point = method.DebugInformation.SequencePoints[0]; + var document = sequence_point.Document; + result.Add (document.Url); + } + } + } + return result; + } + + public static int Main (string[] arguments) { bool link = false; string monopath = null; + string opentkpath = null; + string xamarinpath = null; string installDir = null; + string destinationDir = null; bool verbose = false; var os = new OptionSet () { { "link:", "If source files should be linked instead of copied. Makes the install process faster, and if you edit files when stopped in a debugger, you'll edit the right file (and not a copy).", v => link = ParseBool (v) }, { "mono-path=", "The path of the mono checkout.", v => monopath = v }, + { "opentk-path=", "The path of the opentk checkout.", v => opentkpath = v}, + { "xamarin-path=", "The path of the xamarin source.", v => xamarinpath = v }, { "install-dir=", "The directory to install into. The files will be put into a src subdirectory of this directory.", v => installDir = v }, + { "destination-dir=", "The path to the directory used for the -pathmap at build time.", v => destinationDir = v}, { "v|erbose", "Enable verbose output", v => verbose = true }, }; - var mdb_files = os.Parse (arguments); + var paths = os.Parse (arguments); + var files = GetSplittedPaths (paths); var srcs = new HashSet (StringComparer.OrdinalIgnoreCase); - if (!monopath.EndsWith (Path.DirectorySeparatorChar.ToString (), StringComparison.Ordinal)) - monopath += Path.DirectorySeparatorChar; + monopath = FixPathEnding (monopath); + xamarinpath = FixPathEnding (xamarinpath); + opentkpath = FixPathEnding (opentkpath); - foreach (string mdb_file in mdb_files) { - if (!File.Exists (mdb_file)) { - Console.WriteLine ("File does not exist: {0}", mdb_file); + var manglerFactory = new PathManglerFactory { + Verbose = verbose, + InstallDir = installDir, + DestinationDir = destinationDir, + MonoSourcePath = monopath, + XamarinSourcePath = xamarinpath, + FrameworkPath = (installDir.Contains ("Xamarin.iOS.framework")) ? "Xamarin.iOS.framework" : "Xamarin.Mac.framework", + OpenTKSourcePath = opentkpath, + }; + + // add the paths from the pdb files + foreach (string pdbFile in files.Item1) { + if (!File.Exists (pdbFile)) { + Console.WriteLine ("File does not exist: {0}", pdbFile); continue; } - if (mdb_file.EndsWith ("monotouch.dll.mdb", StringComparison.Ordinal)) { - // don't include monotouch.dll source - continue; - } else if (mdb_file.EndsWith ("Xamarin.iOS.dll.mdb", StringComparison.Ordinal)) { - // same for Xamarin.iOS.dll - continue; - } else if (mdb_file.EndsWith ("XamMac.dll.mdb", StringComparison.Ordinal)) { - continue; - } else if (mdb_file.EndsWith ("Xamarin.Mac.dll.mdb", StringComparison.Ordinal)) { - continue; - } - - MonoSymbolFile symfile; - - try { - symfile = MonoSymbolFile.ReadSymbolFile (mdb_file); - } catch (IOException ioe) { - Console.WriteLine ("IO error while reading msb file '{0}': {1}", mdb_file, ioe.Message); - continue; - } - - foreach (var source_file in symfile.Sources) { - var src = source_file.FileName; - - if (!src.StartsWith (monopath, StringComparison.Ordinal)) { - if (verbose) - Console.WriteLine ("{0}: not a mono source file", src); - continue; - } - - srcs.Add (src); + var assemblySrcs = GetFilePathsFromPdb(pdbFile); + if (verbose) { + Console.WriteLine("Pdb file sources are:"); + foreach (var p in srcs) + Console.WriteLine($"\t{p}"); } + srcs.UnionWith(assemblySrcs); } + // add the paths from the mdb files + foreach (string mdbFile in files.Item2) { + if (!File.Exists (mdbFile)) { + Console.WriteLine ("File does not exist: {0}", mdbFile); + continue; + } + var assemblySrcs = GetFilePathsFromMdb (mdbFile); + if (verbose) { + Console.WriteLine("Mdb file sources are:"); + foreach (var p in srcs) + Console.WriteLine($"\t{p}"); + } + srcs.UnionWith (assemblySrcs); + } + + if (verbose) { + Console.WriteLine ("Build paths are:"); + Console.WriteLine ($"\tMono path:{monopath}"); + Console.WriteLine ($"\tXamarin path:{xamarinpath}"); + Console.WriteLine ($"\tOpenTk path:{opentkpath}"); + Console.WriteLine ($"\tDestination path:{destinationDir}"); + } + var alreadyLinked = new List (); foreach (var src in srcs) { - var relativePath = src.Substring (monopath.Length); - var target = Path.Combine (installDir, "src", "mono", relativePath); + var mangler = manglerFactory.GetMangler (src); + if (mangler == null) { // we are ignoring this file + if (verbose) + Console.WriteLine ($"Ignoring path {src}"); + continue; + } + if (verbose) + Console.WriteLine ($"Original source is {src}"); + var fixedSource = mangler.GetSourcePath (src); + + if (String.IsNullOrEmpty (fixedSource)) { + Console.WriteLine ($"Skip path {src}"); + continue; + } + var target = mangler.GetTargetPath (fixedSource); + + if (verbose) { + Console.WriteLine ($"Fixed source {fixedSource}"); + Console.WriteLine ($"Target path {target}"); + } + var targetDir = Path.GetDirectoryName (target); - if (!Directory.Exists (targetDir)) { - Directory.CreateDirectory (targetDir); - } else if (File.Exists (target)) { - File.Delete (target); + if (String.IsNullOrEmpty (targetDir)) { + Console.WriteLine ($"Got empty dir for {target}"); + continue; } + + if (verbose) + Console.WriteLine ($"Target direcotry is {targetDir}"); + + if (!Directory.Exists (targetDir)) { + try { + if (verbose) + Console.WriteLine ($"Creating dir {targetDir}"); + Directory.CreateDirectory(targetDir); + } catch (PathTooLongException e) { + Console.WriteLine("Could not create directory {0} because the path is too long: {1}", targetDir, e); + return 1; + } + } else if (File.Exists (target)) { + try { + File.Delete(target); + } catch (PathTooLongException e) { + Console.WriteLine("Could not delete file {0} because the path is too long: {1}", target, e); + return 1; + } + } // else if (link) { if (verbose) - Console.WriteLine ("ln -s {0} {1}", src, target); - new UnixFileInfo (src).CreateSymbolicLink (target); + Console.WriteLine ("ln -s {0} {1}", fixedSource, target); + try { + if (!alreadyLinked.Contains (fixedSource)) { + new UnixFileInfo (fixedSource).CreateSymbolicLink (target); + alreadyLinked.Add(fixedSource); + } else { + Console.WriteLine ("Src {0} was already linked.", src); + } + } catch (PathTooLongException e) { + Console.WriteLine("Could not link {0} to {1} because the path is too long: {2}", fixedSource, target, e); + return 1; + } catch (UnixIOException e) { + Console.WriteLine("Could not link {0} to {1}: {2}", src, target, e); + return 1; + } // try/catch } else { - if (verbose) - Console.WriteLine ("cp {0} {1}", src, target); - File.Copy (src, target); - } - } + if (verbose) { + Console.WriteLine ("cp {0} {1}", fixedSource, target); + } + try { + File.Copy (fixedSource, target); + } catch (FileNotFoundException e) { + Console.WriteLine ("The file {0} could not be copied to {1} because the file does not exists: {2}", fixedSource, target, e); + Console.WriteLine ("Debugging info:"); + Console.WriteLine ("\tSource is {0}", src); + Console.WriteLine ("\tFixed source is {0}", fixedSource); + Console.WriteLine ("\tPath mangler type is {0}", mangler.GetType().Name); + } catch (PathTooLongException e) { + Console.WriteLine ("The file {0} could not be copied to {1} because the file path is too long: {2}", fixedSource, target, e); + return 1; + } + } // else + } // foreach + + return 0; } -} \ No newline at end of file +} diff --git a/tools/install-source/XamarinSourcesPathMangler.cs b/tools/install-source/XamarinSourcesPathMangler.cs new file mode 100644 index 0000000000..81122696bd --- /dev/null +++ b/tools/install-source/XamarinSourcesPathMangler.cs @@ -0,0 +1,231 @@ +using System; +using System.IO; + +namespace InstallSources +{ + /// + /// Path manipulator that can deal with the Xamarin sources. + /// + public class XamarinSourcesPathMangler : IPathMangler + { + static string GeneratedExtension = ".g.cs"; + static string NativeTypeSubpath = "NativeTypes"; + static string CommonSourceSubpath = "/build/common/"; + static string RuntimeSubpath = "generated.cs"; + + /// + /// Gets and sets the path to the xamarin source. + /// + /// The xamarin source path. + public string XamarinSourcePath { get; set; } + + /// + /// Gets and sets the path used as the dir name for the framework. + /// + /// The framework path. + public string FrameworkPath { get; set; } + + /// + /// Gets or sets the install dir. + /// + /// The install dir. + public string InstallDir { get; set; } + + /// + /// Gets or sets the frame work dir. + /// + /// The frame work dir. + public string DestinationDir { get; set; } + + /// + /// Returns if the provided path was compiler generated or not. + /// + /// true, if generated path was generated, false otherwise. + /// The source path to mangle. + static bool IsGeneratedPath (string path) + { + return path.EndsWith (GeneratedExtension, StringComparison.InvariantCulture); + } + + /// + /// Returns if the source file is part of the common source generated by the generator. + /// + /// true, if common source was ised, false otherwise. + /// Path. + public static bool IsManualSource (string path) + { + return path.EndsWith (".cs", StringComparison.CurrentCulture) && !path.Contains (CommonSourceSubpath) && !path.Contains (NativeTypeSubpath); + } + + /// + /// Returns if the provided path is a NativeType. + /// + /// true, if native type was ised, false otherwise. + /// Path. + static bool IsNativeType (string path) + { + return path.Contains (NativeTypeSubpath); + } + + /// + /// Returns if the pat is from the runtime generated code. + /// + /// true, if runrime was ised, false otherwise. + /// Path. + static bool IsRunrime (string path) + { + return path.Contains (RuntimeSubpath); + } + + /// + /// Returns the source path for a generated file. + /// + /// The source path for native type. + /// Path. + string GetSourcePathForGeneratedPath (string path) + { + var frameworkPrefix = FrameworkPath.Remove (FrameworkPath.IndexOf (".framework", StringComparison.Ordinal)); + var installPath = Path.Combine (InstallDir, "src", frameworkPrefix); + // we might be looking at a mdb that was already gone thorugh mdb rebase, if that is the case, do find the path for the final target + if (path.StartsWith (InstallDir, StringComparison.InvariantCulture)) { + var src = path.Substring (installPath.Length + 1); + if (src.StartsWith ("/", StringComparison.Ordinal)) + src = src.Remove (0, 1); + src = Path.Combine (XamarinSourcePath, (InstallDir.Contains ("Xamarin.iOS.framework")) ? "build/ios/native/" : "build/mac/full/", src); + return src; + } else { + var pos = path.IndexOf ($"/{frameworkPrefix}/", StringComparison.InvariantCulture); + var src = path.Remove (0, pos + $"/{frameworkPrefix}/".Length); // 3 for src and 1 for / + src = Path.Combine (XamarinSourcePath, src); + return src; + } + } + + /// + /// Returns the source path for the native common types. + /// + /// The source path for native type. + /// Path. + string GetSourcePathForNativeType (string path) + { + string src = ""; + var pos = path.IndexOf (CommonSourceSubpath, StringComparison.InvariantCulture); + if (pos >= 0) { + src = path.Remove (0, pos + CommonSourceSubpath.Length); + src = Path.Combine (XamarinSourcePath, "build", "common", src); + } else { + pos = path.IndexOf (NativeTypeSubpath, StringComparison.InvariantCulture); + if (pos >= 0) { + src = path.Remove (0, pos); + src = Path.Combine (XamarinSourcePath, src); + } else { + Console.WriteLine ($"Ignoring path {path}"); + return ""; + } + } + return src; + } + + /// + /// Returns the source path for the bindings that were manually done. + /// + /// The source path for manual source. + /// Path. + string GetSourcePathForManualSource (string path) + { + var removalPath = $"/{FrameworkPath}/"; + var srcFolder = Path.Combine ("src", FrameworkPath.Remove (FrameworkPath.IndexOf (".framework", StringComparison.InvariantCulture))) + Path.DirectorySeparatorChar; + var pos = path.IndexOf (removalPath, StringComparison.InvariantCulture); + var src = path.Remove (0, pos + FrameworkPath.Length + 2); + pos = src.IndexOf (srcFolder, StringComparison.InvariantCulture); + if (pos >= 0) + src = src.Remove (0, src.IndexOf (srcFolder, StringComparison.InvariantCulture) + srcFolder.Length); + else // we are dealing with a correct path (this does happen on the mac side) + src = src.Remove (0, src.IndexOf ("/src/", StringComparison.InvariantCulture) + "/src/".Length); + src = Path.Combine (XamarinSourcePath, src); + return src; + } + + string GetSourcePathForRuntimeSource (string path) + { + Console.WriteLine ($"Path is {path}"); + if (path.StartsWith (InstallDir, StringComparison.Ordinal)) { + var removalPath = Path.Combine (InstallDir, FrameworkPath.Replace(".framework", ""), "src"); + Console.WriteLine ($"Removal path s {removalPath}"); + var src = path.Remove (0, removalPath.Length); + Console.WriteLine ($"Src is {src}"); + if (src.StartsWith ("/", StringComparison.Ordinal)) + src = src.Remove (0, 1); + return Path.Combine (XamarinSourcePath.Replace ("src", "runtime"), src); + } return path; + } + + public string GetSourcePath(string path) + { + if (IsRunrime (path)) { + return GetSourcePathForRuntimeSource (path); + } + // decide what type of path we are dealing with and return the correct source. + if (IsGeneratedPath (path)) { + return GetSourcePathForGeneratedPath (path); + } + if (IsManualSource (path)) + return GetSourcePathForManualSource (path); + return GetSourcePathForNativeType (path); + } + + string GetTargetPathForGeneratedPath (string path) + { + var subpath = (InstallDir.Contains ("Xamarin.iOS.framework")) ? "native" : "full"; + var pos = path.IndexOf (subpath, StringComparison.InvariantCulture); + if (pos >= 0) { + var relativePath = path.Remove (0, pos + subpath.Length + 1); + return Path.Combine (DestinationDir, "src", FrameworkPath.Remove (FrameworkPath.IndexOf (".framework", StringComparison.InvariantCulture)), relativePath); + } + return null; + } + + string GetTargetPathForManualSource (string path) + { + var pos = path.IndexOf (XamarinSourcePath, StringComparison.InvariantCulture); + if (pos >= 0) { + var relativePath = path.Remove (0, pos + XamarinSourcePath.Length); + return Path.Combine (DestinationDir, "src", FrameworkPath.Remove (FrameworkPath.IndexOf (".framework", StringComparison.InvariantCulture)), relativePath); + } + return null; + } + + string GetTargetPathForNativeType (string path) + { + var pos = path.IndexOf (NativeTypeSubpath, StringComparison.InvariantCulture); + if (pos >= 0) { + var relativePath = path.Remove (0, pos); + return Path.Combine (DestinationDir, "src", FrameworkPath.Remove (FrameworkPath.IndexOf (".framework", StringComparison.InvariantCulture)), relativePath); + } + return null; + } + + string GetTargetPathForRuntimeSource (string path) + { + var pos = path.IndexOf (RuntimeSubpath, StringComparison.InvariantCulture); + if (pos >= 0) { + var relativePath = path.Remove (0, pos + 1); // +1 is used to remove the leading / from RuntimeSubpath + var result = Path.Combine (DestinationDir, "src", FrameworkPath.Remove (FrameworkPath.IndexOf (".framework", StringComparison.InvariantCulture)), relativePath); + return result; + } + return null; + } + + public string GetTargetPath (string path) + { + if (IsRunrime(path)) + return GetTargetPathForRuntimeSource(path); + if (IsGeneratedPath(path)) + return GetTargetPathForGeneratedPath(path); + if (IsManualSource(path)) + return GetTargetPathForManualSource(path); + return GetTargetPathForNativeType (path); + } + + } +} diff --git a/tools/install-source/install-source.csproj b/tools/install-source/install-source.csproj index 6d17fd5a62..824efbc193 100644 --- a/tools/install-source/install-source.csproj +++ b/tools/install-source/install-source.csproj @@ -1,7 +1,8 @@ - Debug + Release + . AnyCPU 8.0.30703 2.0 @@ -10,26 +11,27 @@ installsource install-source - - true - full - false - . - DEBUG; - prompt - 4 - true - + + Mono.Cecil.dll + + + Mono.Cecil.Pdb.dll + Options.cs + + + + + \ No newline at end of file diff --git a/tools/install-source/install-source.sln b/tools/install-source/install-source.sln new file mode 100644 index 0000000000..a1cf8124c3 --- /dev/null +++ b/tools/install-source/install-source.sln @@ -0,0 +1,23 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "install-source", "install-source.csproj", "{B24B2169-6243-4F98-B38C-69F03655CF1B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "InstallSourcesTests", "InstallSourcesTests\InstallSourcesTests.csproj", "{795E0F7E-5C48-4C90-8F66-518359874022}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {B24B2169-6243-4F98-B38C-69F03655CF1B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B24B2169-6243-4F98-B38C-69F03655CF1B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B24B2169-6243-4F98-B38C-69F03655CF1B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B24B2169-6243-4F98-B38C-69F03655CF1B}.Release|Any CPU.Build.0 = Release|Any CPU + {795E0F7E-5C48-4C90-8F66-518359874022}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {795E0F7E-5C48-4C90-8F66-518359874022}.Debug|Any CPU.Build.0 = Debug|Any CPU + {795E0F7E-5C48-4C90-8F66-518359874022}.Release|Any CPU.ActiveCfg = Release|Any CPU + {795E0F7E-5C48-4C90-8F66-518359874022}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal