diff --git a/Clojure/Clojure.Compile/Clojure.Compile.csproj b/Clojure/Clojure.Compile/Clojure.Compile.csproj index a2b3c2ffd..af5a61da7 100644 --- a/Clojure/Clojure.Compile/Clojure.Compile.csproj +++ b/Clojure/Clojure.Compile/Clojure.Compile.csproj @@ -73,8 +73,11 @@ AllRules.ruleset v4.0 + + OnBuildSuccess + - + ..\..\lib\DLR\2.0\Microsoft.Scripting.Core.dll diff --git a/Clojure/Clojure/CljCompiler/Compiler.cs b/Clojure/Clojure/CljCompiler/Compiler.cs index c644e064a..0f765b035 100644 --- a/Clojure/Clojure/CljCompiler/Compiler.cs +++ b/Clojure/Clojure/CljCompiler/Compiler.cs @@ -1394,11 +1394,21 @@ public static void PushNS() Symbol.intern("*ns*")).setDynamic(), null)); } - - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")] internal static bool LoadAssembly(FileInfo assyInfo) { Assembly assy = Assembly.LoadFrom(assyInfo.FullName); + return InitAssembly(assy); + } + + internal static bool LoadAssembly(byte[] assyData) + { + Assembly assy = Assembly.Load(assyData); + return InitAssembly(assy); + } + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")] + private static bool InitAssembly(Assembly assy) + { Type initType = assy.GetType("__Init__"); if (initType == null) { @@ -1412,7 +1422,7 @@ internal static bool LoadAssembly(FileInfo assyInfo) } catch (Exception e) { - Console.WriteLine("Error initializing {0}: {1}", assyInfo.FullName, e.Message); + Console.WriteLine("Error initializing {0}: {1}", assy.FullName, e.Message); return false; } } diff --git a/Clojure/Clojure/Clojure.csproj b/Clojure/Clojure/Clojure.csproj index 0d5524ea9..7eb695b3f 100644 --- a/Clojure/Clojure/Clojure.csproj +++ b/Clojure/Clojure/Clojure.csproj @@ -114,6 +114,9 @@ + + ResourceHelper.cs + diff --git a/Clojure/Clojure/Lib/RT.cs b/Clojure/Clojure/Lib/RT.cs index 8db7db14e..9b604c6c4 100644 --- a/Clojure/Clojure/Lib/RT.cs +++ b/Clojure/Clojure/Lib/RT.cs @@ -23,6 +23,7 @@ using System.Text; using System.Text.RegularExpressions; using System.Threading; +using ResPack; using RTProperties = clojure.runtime.Properties; using Microsoft.Scripting.Hosting; using clojure.lang.Runtime; @@ -280,6 +281,10 @@ public static class RT // for folks using Cygwin and its ilk. public const string ClojureLoadPathString = "CLOJURE_LOAD_PATH"; + public const string ResourceFileName = "Clojure.resources"; + + private static readonly string ResourceFilePath; + #endregion #region It's true (or not) @@ -512,10 +517,30 @@ public override object invoke(object arg1) #endregion #region Initialization + + static string GetAssemblyParentDirectory() + { + Uri uri = new Uri(Assembly.GetExecutingAssembly().CodeBase); + return Path.GetDirectoryName(Uri.UnescapeDataString(uri.AbsolutePath)); + } + + static Assembly ResolveAssembly(object sender, ResolveEventArgs args) + { + string weakName = args.Name.Split(',').FirstOrDefault(); + if (String.IsNullOrEmpty(weakName) || weakName.EndsWith(".resources")) return null; + + byte[] data; + return ResourceHelper.TryGetResourceData(weakName + ".dll", ResourceFilePath, out data) + ? Assembly.Load(data) + : null; + } [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1810:InitializeReferenceTypeStaticFieldsInline")] static RT() { + ResourceFilePath = Path.Combine(GetAssemblyParentDirectory(), ResourceFileName); + AppDomain.CurrentDomain.AssemblyResolve += ResolveAssembly; + // TODO: Check for existence of ClojureContext.Default before doing this? ScriptRuntimeSetup setup = new ScriptRuntimeSetup(); @@ -3081,10 +3106,27 @@ public static void load(String relativePath, Boolean failIfNotFound) else LoadScript(cljInfo, cljname); ; } - else if (!loaded && failIfNotFound) - throw new FileNotFoundException(String.Format("Could not locate {0} or {1} on load path.", assemblyname, cljname)); - + else if (!loaded) + { + byte[] data; + if (ResourceHelper.TryGetResourceData(assemblyname, ResourceFilePath, out data)) + { + try + { + Var.pushThreadBindings(RT.map(CurrentNSVar, CurrentNSVar.deref(), + WarnOnReflectionVar, WarnOnReflectionVar.deref(), + RT.UncheckedMathVar, RT.UncheckedMathVar.deref())); + loaded = Compiler.LoadAssembly(data); + } + finally + { + Var.popThreadBindings(); + } + } + if (!loaded && failIfNotFound) + throw new FileNotFoundException(String.Format("Could not locate {0} or {1} on load path.", assemblyname, cljname)); + } } private static void MaybeLoadCljScript(string cljname) diff --git a/Clojure/ClojureCLR.sln b/Clojure/ClojureCLR.sln index 6e8ed0ca6..9a9553613 100644 --- a/Clojure/ClojureCLR.sln +++ b/Clojure/ClojureCLR.sln @@ -40,6 +40,11 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DlrConsole", "DlrConsole\DlrConsole.csproj", "{4F303159-0D0D-44D2-885D-B84F406BAF0C}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ResPack", "ResPack\ResPack.csproj", "{58194622-8C69-494C-817C-A39EEB9C58DC}" + ProjectSection(ProjectDependencies) = postProject + {3DBF3359-43B5-47C9-9E4D-CF50D7587F20} = {3DBF3359-43B5-47C9-9E4D-CF50D7587F20} + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug 3.5|Any CPU = Debug 3.5|Any CPU @@ -272,6 +277,36 @@ Global {4F303159-0D0D-44D2-885D-B84F406BAF0C}.Release|Mixed Platforms.Build.0 = Release|x86 {4F303159-0D0D-44D2-885D-B84F406BAF0C}.Release|x86.ActiveCfg = Release|x86 {4F303159-0D0D-44D2-885D-B84F406BAF0C}.Release|x86.Build.0 = Release|x86 + {58194622-8C69-494C-817C-A39EEB9C58DC}.Debug 3.5|Any CPU.ActiveCfg = Debug|x86 + {58194622-8C69-494C-817C-A39EEB9C58DC}.Debug 3.5|Mixed Platforms.ActiveCfg = Debug|x86 + {58194622-8C69-494C-817C-A39EEB9C58DC}.Debug 3.5|Mixed Platforms.Build.0 = Debug|x86 + {58194622-8C69-494C-817C-A39EEB9C58DC}.Debug 3.5|x86.ActiveCfg = Debug|x86 + {58194622-8C69-494C-817C-A39EEB9C58DC}.Debug 3.5|x86.Build.0 = Debug|x86 + {58194622-8C69-494C-817C-A39EEB9C58DC}.Debug 4.0|Any CPU.ActiveCfg = Debug|x86 + {58194622-8C69-494C-817C-A39EEB9C58DC}.Debug 4.0|Mixed Platforms.ActiveCfg = Debug|x86 + {58194622-8C69-494C-817C-A39EEB9C58DC}.Debug 4.0|Mixed Platforms.Build.0 = Debug|x86 + {58194622-8C69-494C-817C-A39EEB9C58DC}.Debug 4.0|x86.ActiveCfg = Debug|x86 + {58194622-8C69-494C-817C-A39EEB9C58DC}.Debug 4.0|x86.Build.0 = Debug|x86 + {58194622-8C69-494C-817C-A39EEB9C58DC}.Debug|Any CPU.ActiveCfg = Debug|x86 + {58194622-8C69-494C-817C-A39EEB9C58DC}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {58194622-8C69-494C-817C-A39EEB9C58DC}.Debug|Mixed Platforms.Build.0 = Debug|x86 + {58194622-8C69-494C-817C-A39EEB9C58DC}.Debug|x86.ActiveCfg = Debug|x86 + {58194622-8C69-494C-817C-A39EEB9C58DC}.Debug|x86.Build.0 = Debug|x86 + {58194622-8C69-494C-817C-A39EEB9C58DC}.Release 3.5|Any CPU.ActiveCfg = Release|x86 + {58194622-8C69-494C-817C-A39EEB9C58DC}.Release 3.5|Mixed Platforms.ActiveCfg = Release|x86 + {58194622-8C69-494C-817C-A39EEB9C58DC}.Release 3.5|Mixed Platforms.Build.0 = Release|x86 + {58194622-8C69-494C-817C-A39EEB9C58DC}.Release 3.5|x86.ActiveCfg = Release|x86 + {58194622-8C69-494C-817C-A39EEB9C58DC}.Release 3.5|x86.Build.0 = Release|x86 + {58194622-8C69-494C-817C-A39EEB9C58DC}.Release 4.0|Any CPU.ActiveCfg = Release|x86 + {58194622-8C69-494C-817C-A39EEB9C58DC}.Release 4.0|Mixed Platforms.ActiveCfg = Release|x86 + {58194622-8C69-494C-817C-A39EEB9C58DC}.Release 4.0|Mixed Platforms.Build.0 = Release|x86 + {58194622-8C69-494C-817C-A39EEB9C58DC}.Release 4.0|x86.ActiveCfg = Release|x86 + {58194622-8C69-494C-817C-A39EEB9C58DC}.Release 4.0|x86.Build.0 = Release|x86 + {58194622-8C69-494C-817C-A39EEB9C58DC}.Release|Any CPU.ActiveCfg = Release|x86 + {58194622-8C69-494C-817C-A39EEB9C58DC}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {58194622-8C69-494C-817C-A39EEB9C58DC}.Release|Mixed Platforms.Build.0 = Release|x86 + {58194622-8C69-494C-817C-A39EEB9C58DC}.Release|x86.ActiveCfg = Release|x86 + {58194622-8C69-494C-817C-A39EEB9C58DC}.Release|x86.Build.0 = Release|x86 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Clojure/ResPack/Program.cs b/Clojure/ResPack/Program.cs new file mode 100644 index 000000000..72b258c18 --- /dev/null +++ b/Clojure/ResPack/Program.cs @@ -0,0 +1,60 @@ +using System; +using System.Linq; +using System.Collections.Generic; +using System.IO; + +namespace ResPack +{ + internal static class Program + { + const string PATH_PROP = "CLOJURE_COMPILE_PATH"; + + static Program() + { + AppDomain.CurrentDomain.UnhandledException += + (sender, args) => LogErrorAndExit(args.ExceptionObject as Exception); + } + + private static void LogErrorAndExit(Exception ex) + { + Console.Error.WriteLine(ex.Message); + Environment.Exit(ExitCode.Error); + } + + private static void Main(string[] args) + { + switch (args.Length) + { + case 0: + throw new Exception("missing resource file name"); + + case 1: + throw new Exception("missing content file name"); + } + + var dir = Environment.GetEnvironmentVariable(PATH_PROP) ?? Environment.CurrentDirectory; + args.Skip(1).PackResources(dir, args[0]); + } + + private static void PackResources(this IEnumerable resources, string directory, string fileName) + { + var entries = new Dictionary(); + + foreach (var res in resources.Where(r => !String.IsNullOrWhiteSpace(r))) + { + var contentFile = Path.Combine(directory, res.Trim()); + var data = File.ReadAllBytes(contentFile); + entries.Add(res, data); + } + + var resFile = Path.Combine(directory, fileName); + entries.WriteResourceFile(resFile); + } + } + + internal static class ExitCode + { + public const int Error = -1; + public const int Success = 0; + } +} \ No newline at end of file diff --git a/Clojure/ResPack/Properties/AssemblyInfo.cs b/Clojure/ResPack/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..5ba21454f --- /dev/null +++ b/Clojure/ResPack/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("ResPack")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("ResPack")] +[assembly: AssemblyCopyright("Copyright © 2012")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("5b8c2878-3154-43c1-939d-e365e6a943ea")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Clojure/ResPack/ResPack.csproj b/Clojure/ResPack/ResPack.csproj new file mode 100644 index 000000000..d7aa97832 --- /dev/null +++ b/Clojure/ResPack/ResPack.csproj @@ -0,0 +1,61 @@ + + + + Debug + x86 + 8.0.30703 + 2.0 + {58194622-8C69-494C-817C-A39EEB9C58DC} + Exe + Properties + ResPack + ResPack + v4.0 + Client + 512 + + + x86 + true + full + false + ..\..\bin\4.0\Debug\ + DEBUG;TRACE + prompt + 4 + + + x86 + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + "$(TargetPath)" Clojure.resources clojure.clr.io.clj.dll clojure.clr.shell.clj.dll clojure.core.clj.dll clojure.core.protocols.clj.dll clojure.core_clr.clj.dll clojure.core_deftype.clj.dll clojure.core_print.clj.dll clojure.core_proxy.clj.dll clojure.data.clj.dll clojure.genclass.clj.dll clojure.gvec.clj.dll clojure.instant.clj.dll clojure.main.clj.dll clojure.pprint.cl_format.clj.dll clojure.pprint.clj.dll clojure.pprint.column_writer.clj.dll clojure.pprint.dispatch.clj.dll clojure.pprint.pprint_base.clj.dll clojure.pprint.pretty_writer.clj.dll clojure.pprint.print_table.clj.dll clojure.pprint.utilities.clj.dll clojure.reflect.clj.dll clojure.reflect.clr.clj.dll clojure.repl.clj.dll clojure.set.clj.dll clojure.stacktrace.clj.dll clojure.string.clj.dll clojure.template.clj.dll clojure.test.clj.dll clojure.test.junit.clj.dll clojure.test.tap.clj.dll clojure.uuid.clj.dll clojure.walk.clj.dll clojure.zip.clj.dll + + + \ No newline at end of file diff --git a/Clojure/ResPack/ResourceHelper.cs b/Clojure/ResPack/ResourceHelper.cs new file mode 100644 index 000000000..ceff6c83a --- /dev/null +++ b/Clojure/ResPack/ResourceHelper.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Resources; + +namespace ResPack +{ + public static class ResourceHelper + { + public static void WriteResourceFile(this IEnumerable> pairs, string fileName) + { + using (var writer = new ResourceWriter(fileName)) + { + foreach (var p in pairs) + { + writer.AddResourceData(p.Key, String.Empty, p.Value); + } + } + } + + public static bool TryGetResourceData(string key, string fileName, out byte[] data) + { + try + { + data = GetResourceData(key, fileName); + return (data != null); + } + catch + { + data = null; + return false; + } + } + + public static byte[] GetResourceData(string key, string fileName) + { + return ReadResourceFile(new[] {key}, fileName).First().Value; + } + + public static IEnumerable> ReadResourceFile(this IEnumerable keys, + string fileName) + { + using (var reader = new ResourceReader(fileName)) + { + string _; + byte[] data; + var pairs = new Dictionary(); + + foreach (var k in keys) + { + reader.GetResourceData(k, out _, out data); + pairs.Add(k, data); + } + + return pairs; + } + } + } +} \ No newline at end of file