From d4308a740d119d5c2b646ed3150db31fe7d07672 Mon Sep 17 00:00:00 2001 From: "Frank A. Krueger" Date: Tue, 13 Mar 2018 00:59:33 -0700 Subject: [PATCH] Implement the wasm build task --- .gitignore | 1 + Ooui.Wasm.Build.Tasks/BuildDistTask.cs | 211 +++++++++++++++++++++++-- Ooui.sln | 26 ++- 3 files changed, 218 insertions(+), 20 deletions(-) diff --git a/.gitignore b/.gitignore index eaa0c2e..0be966e 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,7 @@ /Ooui.Wasm/sample* /Ooui.Wasm/lib* /Ooui.Wasm/*.w* +/Ooui.Wasm.Test # Social media files /Media diff --git a/Ooui.Wasm.Build.Tasks/BuildDistTask.cs b/Ooui.Wasm.Build.Tasks/BuildDistTask.cs index 815b26c..2164d26 100644 --- a/Ooui.Wasm.Build.Tasks/BuildDistTask.cs +++ b/Ooui.Wasm.Build.Tasks/BuildDistTask.cs @@ -1,30 +1,213 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.IO; -using System.Xml; +using System.IO.Compression; +using System.Linq; +using System.Net; using Microsoft.Build.Framework; using Microsoft.Build.Utilities; +using System.Text; +using Mono.Cecil; namespace Ooui.Wasm.Build.Tasks { - public class BuildDistTask : MarshalByRefObject, ITask + public class BuildDistTask : Task { - [Required] - public string Assembly { get; set; } - public string ReferencePath { get; set; } + const string SdkUrl = "https://jenkins.mono-project.com/job/test-mono-mainline-webassembly/62/label=highsierra/Azure/processDownloadRequest/62/highsierra/sdks/wasm/mono-wasm-ddf4e7be31b.zip"; - public bool Execute () - { - var fullAsmPath = Path.GetFullPath (Assembly); - Console.WriteLine ("YO " + fullAsmPath); - return true; + [Required] + public string Assembly { get; set; } + public string ReferencePath { get; set; } + + public override bool Execute () + { + try { + InstallSdk (); + GetBcl (); + CreateDist (); + CopyRuntime (); + LinkAssemblies (); + ExtractClientJs (); + GenerateHtml (); + GenerateServer (); + return true; + } + catch (Exception ex) { + Log.LogErrorFromException (ex); + return false; + } } - public IBuildEngine BuildEngine { get; set; } - public ITaskHost HostObject { get; set; } + string sdkPath; + void InstallSdk () + { + var sdkName = Path.GetFileNameWithoutExtension (new Uri (SdkUrl).AbsolutePath.Replace ('/', Path.DirectorySeparatorChar)); + Log.LogMessage ("SDK: " + sdkName); + sdkPath = Path.Combine (Path.GetTempPath (), sdkName); + Log.LogMessage ("SDK Path: " + sdkPath); + if (Directory.Exists (sdkPath)) + return; + + var client = new WebClient (); + var zipPath = sdkPath + ".zip"; + Log.LogMessage ($"Downloading {sdkName} to {zipPath}"); + client.DownloadFile (SdkUrl, zipPath); + + ZipFile.ExtractToDirectory (zipPath, sdkPath); + Log.LogMessage ($"Extracted {sdkName} to {sdkPath}"); + } + + string bclPath; + Dictionary bclAssemblies; + + void GetBcl () + { + bclPath = Path.Combine (sdkPath, "bcl"); + var reals = Directory.GetFiles (bclPath, "*.dll"); + var facades = Directory.GetFiles (Path.Combine (bclPath, "Facades"), "*.dll"); + var allFiles = reals.Concat (facades); + bclAssemblies = allFiles.ToDictionary (x => Path.GetFileName (x)); + } + + string distPath; + string managedPath; + + void CreateDist () + { + var fullAsmPath = Path.GetFullPath (Assembly); + var outputPath = Path.GetDirectoryName (fullAsmPath); + distPath = Path.Combine (outputPath, "dist"); + managedPath = Path.Combine (distPath, "managed"); + Directory.CreateDirectory (managedPath); + //foreach (var dll in Directory.GetFiles (managedPath, "*.dll")) { + // File.Delete (dll); + //} + } + + void CopyRuntime () + { + var rtPath = Path.Combine (sdkPath, "release"); + var files = new[] { "mono.wasm", "mono.js" }; + foreach (var f in files) { + var src = Path.Combine (rtPath, f); + var dest = Path.Combine (distPath, f); + Log.LogMessage ($"Runtime {src} -> {dest}"); + File.Copy (src, dest, true); + } + } + + List linkedAsmNames; + List linkedAsmPaths; + + void LinkAssemblies () + { + var references = ReferencePath.Split (';').Select (x => x.Trim ()).Where (x => x.Length > 0).ToList (); + references.Add (Path.GetFullPath (Assembly)); + + linkedAsmPaths = new List (); + foreach (var r in references) { + var name = Path.GetFileName (r); + if (bclAssemblies.ContainsKey (name)) { + linkedAsmPaths.Add (bclAssemblies[name]); + } + else { + linkedAsmPaths.Add (r); + } + } + + linkedAsmNames = new List (); + foreach (var l in linkedAsmPaths) { + var name = Path.GetFileName (l); + linkedAsmNames.Add (name); + var dest = Path.Combine (managedPath, name); + if (bclAssemblies.ContainsKey (name) && File.Exists (dest)) + continue; + File.Copy (l, dest, true); + Log.LogMessage ($"Managed {l} -> {dest}"); + } + } + + void ExtractClientJs () + { + var oouiPath = linkedAsmPaths.FirstOrDefault (x => Path.GetFileName (x).Equals ("Ooui.dll", StringComparison.InvariantCultureIgnoreCase)); + if (oouiPath == null) { + Log.LogError ("Ooui.dll not included in the project"); + return; + } + var oouiAsm = AssemblyDefinition.ReadAssembly (oouiPath); + var clientJs = oouiAsm.MainModule.Resources.FirstOrDefault (x => x.Name.EndsWith ("Client.js", StringComparison.InvariantCultureIgnoreCase)) as EmbeddedResource; + if (clientJs == null) { + Log.LogError ("Ooui.dll missing client javascript"); + return; + } + var dest = Path.Combine (distPath, "ooui.js"); + using (var srcs = clientJs.GetResourceStream ()) { + using (var dests = new FileStream (dest, FileMode.Create, FileAccess.Write)) { + srcs.CopyTo (dests); + } + } + Log.LogMessage ($"Client JS {dest}"); + } + + void GenerateHtml () + { + var htmlPath = Path.Combine (distPath, "index.html"); + using (var w = new StreamWriter (htmlPath, false, new UTF8Encoding (false))) { + w.Write (@" + + + Ooui Wasm + + + + + +
+

Loading...

+
+ + + + + +"); + } + Log.LogMessage ($"HTML {htmlPath}"); + } + + void GenerateServer () + { + var server = @"import SimpleHTTPServer +import SocketServer +PORT = 8000 +class Handler(SimpleHTTPServer.SimpleHTTPRequestHandler): + pass +Handler.extensions_map["".wasm""] = ""application/wasm"" +httpd = SocketServer.TCPServer(("""", PORT), Handler) +print ""serving at port"", PORT +httpd.serve_forever()"; + var serverPath = Path.Combine (distPath, "server.py"); + using (var w = new StreamWriter (serverPath, false, new UTF8Encoding (false))) { + w.WriteLine (server); + } + Log.LogMessage ($"Server {serverPath}"); + } } - } diff --git a/Ooui.sln b/Ooui.sln index 429aab2..26cd07d 100644 --- a/Ooui.sln +++ b/Ooui.sln @@ -2,22 +2,24 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 VisualStudioVersion = 15.0.27130.2010 MinimumVisualStudioVersion = 15.0.26124.0 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ooui", "Ooui\Ooui.csproj", "{DFDFD036-BF48-4D3A-BF99-88CA1EA8E4B9}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ooui", "Ooui\Ooui.csproj", "{DFDFD036-BF48-4D3A-BF99-88CA1EA8E4B9}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Samples", "Samples\Samples.csproj", "{CDF8BB01-40BB-402F-8446-47AA6F1628F3}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Samples", "Samples\Samples.csproj", "{CDF8BB01-40BB-402F-8446-47AA6F1628F3}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tests", "Tests\Tests.csproj", "{78F6E9E7-4322-4F87-8CE9-1EEF1B16D268}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests", "Tests\Tests.csproj", "{78F6E9E7-4322-4F87-8CE9-1EEF1B16D268}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ooui.Forms", "Ooui.Forms\Ooui.Forms.csproj", "{DB819A2F-91E1-40FB-8D48-6544169966B8}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ooui.Forms", "Ooui.Forms\Ooui.Forms.csproj", "{DB819A2F-91E1-40FB-8D48-6544169966B8}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ooui.AspNetCore", "Ooui.AspNetCore\Ooui.AspNetCore.csproj", "{2EDF0328-698B-458A-B10C-AB1B4786A6CA}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ooui.AspNetCore", "Ooui.AspNetCore\Ooui.AspNetCore.csproj", "{2EDF0328-698B-458A-B10C-AB1B4786A6CA}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "PlatformSamples", "PlatformSamples", "{12ADF328-BBA8-48FC-9AF1-F11B7921D9EA}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AspNetCoreMvc", "PlatformSamples\AspNetCoreMvc\AspNetCoreMvc.csproj", "{7C6D477C-3378-4A86-9C31-AAD51204120B}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AspNetCoreMvc", "PlatformSamples\AspNetCoreMvc\AspNetCoreMvc.csproj", "{7C6D477C-3378-4A86-9C31-AAD51204120B}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OouiTemplates", "Templates\OouiTemplates\OouiTemplates.csproj", "{1DA10AAB-EB41-49CF-9441-B4D28D0A7F96}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ooui.Wasm.Build.Tasks", "Ooui.Wasm.Build.Tasks\Ooui.Wasm.Build.Tasks.csproj", "{6E9C9582-0DA8-4496-BAE0-23EFAF4A10C2}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -112,6 +114,18 @@ Global {1DA10AAB-EB41-49CF-9441-B4D28D0A7F96}.Release|x64.Build.0 = Release|Any CPU {1DA10AAB-EB41-49CF-9441-B4D28D0A7F96}.Release|x86.ActiveCfg = Release|Any CPU {1DA10AAB-EB41-49CF-9441-B4D28D0A7F96}.Release|x86.Build.0 = Release|Any CPU + {6E9C9582-0DA8-4496-BAE0-23EFAF4A10C2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6E9C9582-0DA8-4496-BAE0-23EFAF4A10C2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6E9C9582-0DA8-4496-BAE0-23EFAF4A10C2}.Debug|x64.ActiveCfg = Debug|Any CPU + {6E9C9582-0DA8-4496-BAE0-23EFAF4A10C2}.Debug|x64.Build.0 = Debug|Any CPU + {6E9C9582-0DA8-4496-BAE0-23EFAF4A10C2}.Debug|x86.ActiveCfg = Debug|Any CPU + {6E9C9582-0DA8-4496-BAE0-23EFAF4A10C2}.Debug|x86.Build.0 = Debug|Any CPU + {6E9C9582-0DA8-4496-BAE0-23EFAF4A10C2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6E9C9582-0DA8-4496-BAE0-23EFAF4A10C2}.Release|Any CPU.Build.0 = Release|Any CPU + {6E9C9582-0DA8-4496-BAE0-23EFAF4A10C2}.Release|x64.ActiveCfg = Release|Any CPU + {6E9C9582-0DA8-4496-BAE0-23EFAF4A10C2}.Release|x64.Build.0 = Release|Any CPU + {6E9C9582-0DA8-4496-BAE0-23EFAF4A10C2}.Release|x86.ActiveCfg = Release|Any CPU + {6E9C9582-0DA8-4496-BAE0-23EFAF4A10C2}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE