summaryrefslogtreecommitdiff
path: root/Xamarin.Forms.Build.Tasks/XamlTask.cs
blob: 9bfc87cff524239775e2c6530c4e59cabcba5ebb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Xml;

using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;

using Mono.Cecil;

using Xamarin.Forms.Xaml;
using Mono.Cecil.Cil;
using Mono.Cecil.Pdb;
using Mono.Cecil.Mdb;

namespace Xamarin.Forms.Build.Tasks
{
	public abstract class XamlTask : AppDomainIsolatedTask
	{
		[Required]
		public string Assembly { get; set; }
		public string DependencyPaths { get; set; }
		public string ReferencePath { get; set; }
		public int Verbosity { get; set; }
		public bool DebugSymbols { get; set; }

		internal XamlTask()
		{
		}

		protected Logger Logger { get; set; }

		public override bool Execute()
		{
			Logger = new Logger(Log, Verbosity);
			IList<Exception> _;
			return Execute(out _);
		}

		public abstract bool Execute(out IList<Exception> thrownExceptions);

		internal static ILRootNode ParseXaml(Stream stream, TypeReference typeReference)
		{
			ILRootNode rootnode = null;
			using (var reader = XmlReader.Create(stream)) {
				while (reader.Read()) {
					//Skip until element
					if (reader.NodeType == XmlNodeType.Whitespace)
						continue;
					if (reader.NodeType != XmlNodeType.Element) {
						Debug.WriteLine("Unhandled node {0} {1} {2}", reader.NodeType, reader.Name, reader.Value);
						continue;
					}

					XamlParser.ParseXaml(
						rootnode = new ILRootNode(new XmlType(reader.NamespaceURI, reader.Name, null), typeReference, reader as IXmlNamespaceResolver), reader);
					break;
				}
			}
			return rootnode;
		}

		protected static ISymbolReaderProvider GetSymbolReaderProvider(string moduleFileName, bool debugSymbols)
		{
			if (!debugSymbols)
				return null;

			var pdb_name = GetPdbFileName(moduleFileName);
			if (File.Exists(pdb_name)) {
				// TODO: check mvid match
				return new PdbReaderProvider();
			}

			var mdb_name = GetMdbFileName(moduleFileName);
			if (File.Exists(mdb_name)) {
				// TODO: check mvid match
				return new MdbReaderProvider();
			}

			return null;
		}

		protected static ISymbolWriterProvider GetSymbolWriterProvider(string moduleFileName, bool debugSymbols)
		{
			if (!debugSymbols)
				return null;

			var pdb_name = GetPdbFileName(moduleFileName);
			if (File.Exists(pdb_name)) {
				// TODO: check mvid match
				return new PdbWriterProvider();
			}

			var mdb_name = GetMdbFileName(moduleFileName);
			if (File.Exists(mdb_name)) {
				// TODO: check mvid match
				return new MdbWriterProvider();
			}

			return null;
		}

		static string GetPdbFileName(string assemblyFileName)
		{
			return Path.ChangeExtension(assemblyFileName, ".pdb");
		}

		static string GetMdbFileName(string assemblyFileName)
		{
			return assemblyFileName + ".mdb";
		}
	}

	static class CecilExtensions
	{
		public static bool IsXaml(this EmbeddedResource resource, out string classname)
		{
			classname = null;
			if (!resource.Name.EndsWith(".xaml", StringComparison.InvariantCulture))
				return false;

			using (var resourceStream = resource.GetResourceStream()) {
				var xmlDoc = new XmlDocument();
				xmlDoc.Load(resourceStream);

				var nsmgr = new XmlNamespaceManager(xmlDoc.NameTable);

				var root = xmlDoc.SelectSingleNode("/*", nsmgr);
				if (root == null)
					return false;

				var rootClass = root.Attributes ["Class", "http://schemas.microsoft.com/winfx/2006/xaml"] ??
								root.Attributes ["Class", "http://schemas.microsoft.com/winfx/2009/xaml"];
				if (rootClass == null)
					return false;
				classname = rootClass.Value;
				return true;
			}
		}
	}
}