Source/Tx.LinqPad/TypeCache.cs (142 lines of code) (raw):
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using LINQPad.Extensibility.DataContext;
using Microsoft.SqlServer.XEvent;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Windows;
using System.Xml;
using Tx.SqlServer;
using Tx.Windows;
namespace Tx.LinqPad
{
internal class TypeCache
{
public void Init(string targetDir)
{
if (!Directory.Exists(GetCacheDir(targetDir)))
Directory.CreateDirectory(GetCacheDir(targetDir));
}
public void BuildCache(string targetDir, string[] traces, string metadataDir)
{
string[] metadaFiles = Directory.GetFiles(metadataDir, "*.man");
BuildCache(targetDir, traces, metadaFiles);
}
public void BuildCache(string targetDir, string[] traces, string[] metadaFiles)
{
List<string> extraAssembies = new List<string>();
foreach (string f in metadaFiles.Concat(traces))
{
string output = Path.Combine(GetCacheDir(targetDir),
Path.ChangeExtension(
Path.GetFileName(f),
".dll"));
DateTime metadataTimestamp = File.GetLastWriteTimeUtc(f);
DateTime outputTimestamp = File.GetLastWriteTimeUtc(output);
if (outputTimestamp == metadataTimestamp)
continue;
var sources = new Dictionary<string, string>();
switch (Path.GetExtension(f).ToLower())
{
case ".man":
case ".manifest":
{
string manifest = File.ReadAllText(f);
Dictionary<string, string> s = ManifestParser.Parse(manifest);
foreach (string type in s.Keys)
{
if (!sources.ContainsKey(type))
{
sources.Add(type, s[type]);
}
}
break;
}
case ".etl":
{
string[] manifests = ManifestParser.ExtractFromTrace(f);
if (manifests.Length == 0)
continue;
foreach (string manifest in manifests)
{
Dictionary<string, string> s;
try
{
s = ManifestParser.Parse(manifest);
}
catch (XmlException)
{
// if one manifest is bad, we should still see the other events
string err = String.Format(
"Malformed manifest found in the file {0}\nThe corresponding events will not be shown in the tree-control. \nHere are the first 1000 characters: \n\n{1}", f, manifest.Substring(0,1000));
MessageBox.Show(err, "Tx LINQPad Driver");
continue;
}
foreach (string type in s.Keys)
{
if (!sources.ContainsKey(type))
{
sources.Add(type, s[type]);
}
}
}
}
break;
case ".blg":
case ".csv":
case ".tsv":
{
Dictionary<string, string> s = PerfCounterParser.Parse(f);
foreach (string type in s.Keys)
{
if (!sources.ContainsKey(type))
{
sources.Add(type, s[type]);
}
}
}
break;
case ".evtx":
break;
case ".xel":
{
extraAssembies.Add(typeof(XEventAttribute).Assembly.Location);
extraAssembies.Add(typeof(CallStack).Assembly.Location);
Dictionary<string, string> s = XeTypeGenerator.Parse(f);
foreach (string type in s.Keys)
{
if (!sources.ContainsKey(type))
{
sources.Add(type, s[type]);
}
}
}
break;
default:
throw new Exception("Unknown metadata format " + f);
}
AssemblyBuilder.OutputAssembly(sources, extraAssembies, output);
File.SetLastWriteTimeUtc(output, metadataTimestamp);
}
}
public string[] GetAssemblies(string targetDir, string[] traces, string[] metadaFiles)
{
return Directory.GetFiles(GetCacheDir(targetDir), "*.dll");
}
public Type[] GetAvailableTypes(string targetDir, string[] traces, string[] metadaFiles)
{
Assembly[] assemblies = (from file in GetAssemblies(targetDir, traces, metadaFiles)
select DataContextDriver.LoadAssemblySafely(file)).ToArray();
var types = (from a in assemblies
from t in a.GetTypes()
where t.IsPublic
select t).ToArray();
return types;
}
private string GetCacheDir(string targetDir)
{
return Path.Combine(Path.GetTempPath(), "TxTypeCache", targetDir);
}
}
}