[wasm] WasmAppBuilder write the json as json (#39660)
authorLarry Ewing <lewing@microsoft.com>
Wed, 22 Jul 2020 14:15:42 +0000 (09:15 -0500)
committerGitHub <noreply@github.com>
Wed, 22 Jul 2020 14:15:42 +0000 (09:15 -0500)
* Write the json as json

Co-authored-by: Alexander Köplinger <alex.koeplinger@outlook.com>
tools-local/tasks/mobile.tasks/WasmAppBuilder/WasmAppBuilder.cs

index c16e13d..94ad3a5 100644 (file)
@@ -9,6 +9,8 @@ using System.Diagnostics;
 using System.IO;
 using System.Linq;
 using System.Text;
+using System.Text.Json;
+using System.Text.Json.Serialization;
 using System.Reflection;
 using Microsoft.Build.Framework;
 using Microsoft.Build.Utilities;
@@ -34,6 +36,47 @@ public class WasmAppBuilder : Task
     SortedDictionary<string, Assembly>? _assemblies;
     Resolver? _resolver;
 
+    private class WasmAppConfig
+    {
+        [JsonPropertyName("assembly_root")]
+        public string AssemblyRoot { get; set; } = "managed";
+        [JsonPropertyName("enable_debugging")]
+        public int EnableDebugging { get; set; } = 0;
+        [JsonPropertyName("assets")]
+        public List<object> Assets { get; } = new List<object>();
+        [JsonPropertyName("remote_sources")]
+        public List<string> RemoteSources { get; set; } = new List<string>();
+    }
+
+    private class AssetEntry {
+        protected AssetEntry (string name, string behavior)
+        {
+            Name = name;
+            Behavior = behavior;
+        }
+        [JsonPropertyName("behavior")]
+        public string Behavior { get; init; }
+        [JsonPropertyName("name")]
+        public string Name { get; init; }
+    }
+
+    private class AssemblyEntry : AssetEntry
+    {
+        public AssemblyEntry(string name) : base(name, "assembly") {}
+    }
+
+    private class VfsEntry : AssetEntry {
+        public VfsEntry(string name) : base(name, "vfs") {}
+        [JsonPropertyName("virtual_path")]
+        public string? VirtualPath { get; set; }
+    }
+
+    private class IcuData : AssetEntry {
+        public IcuData(string name = "icudt.dat") : base(name, "icu") {}
+        [JsonPropertyName("load_remote")]
+        public bool LoadRemote { get; set; }
+    }
+
     public override bool Execute ()
     {
         if (!File.Exists(MainAssembly))
@@ -55,7 +98,7 @@ public class WasmAppBuilder : Task
         _resolver = new Resolver(paths);
         var mlc = new MetadataLoadContext(_resolver, "System.Private.CoreLib");
 
-        var mainAssembly = mlc.LoadFromAssemblyPath (MainAssembly);
+        var mainAssembly = mlc.LoadFromAssemblyPath(MainAssembly);
         Add(mlc, mainAssembly);
 
         if (ExtraAssemblies != null)
@@ -67,71 +110,61 @@ public class WasmAppBuilder : Task
             }
         }
 
+        var config = new WasmAppConfig ();
+
         // Create app
         Directory.CreateDirectory(AppDir!);
-        Directory.CreateDirectory(Path.Join(AppDir, "managed"));
+        Directory.CreateDirectory(Path.Join(AppDir, config.AssemblyRoot));
         foreach (var assembly in _assemblies!.Values)
-            File.Copy(assembly.Location, Path.Join(AppDir, "managed", Path.GetFileName(assembly.Location)), true);
+            File.Copy(assembly.Location, Path.Join(AppDir, config.AssemblyRoot, Path.GetFileName(assembly.Location)), true);
         foreach (var f in new string[] { "dotnet.wasm", "dotnet.js", "dotnet.timezones.blat", "icudt.dat" })
             File.Copy(Path.Join (MicrosoftNetCoreAppRuntimePackDir, "native", f), Path.Join(AppDir, f), true);
         File.Copy(MainJS!, Path.Join(AppDir, "runtime.js"),  true);
 
-        using (var sw = File.CreateText(Path.Join(AppDir, "mono-config.js")))
-        {
-            sw.WriteLine("config = {");
-            sw.WriteLine("\tassembly_root: \"managed\",");
-            sw.WriteLine("\tenable_debugging: 0,");
-            sw.WriteLine("\tassets: [");
+        foreach (var assembly in _assemblies.Values)
+            config.Assets.Add(new AssemblyEntry (Path.GetFileName(assembly.Location)));
 
-            foreach (var assembly in _assemblies.Values)
-                sw.WriteLine($"\t\t{{ behavior: \"assembly\", name: \"{Path.GetFileName(assembly.Location)}\" }},");
+        if (FilesToIncludeInFileSystem != null)
+        {
+            string supportFilesDir = Path.Join(AppDir, "supportFiles");
+            Directory.CreateDirectory(supportFilesDir);
 
-            if (FilesToIncludeInFileSystem != null)
+            var i = 0;
+            foreach (var item in FilesToIncludeInFileSystem)
             {
-                string supportFilesDir = Path.Join(AppDir, "supportFiles");
-                Directory.CreateDirectory(supportFilesDir);
-
-                var i = 0;
-                foreach (var item in FilesToIncludeInFileSystem)
+                string? targetPath = item.GetMetadata("TargetPath");
+                if (string.IsNullOrEmpty(targetPath))
                 {
-                    string? targetPath = item.GetMetadata("TargetPath");
-                    if (string.IsNullOrEmpty(targetPath))
-                    {
-                        targetPath = Path.GetFileName(item.ItemSpec);
-                    }
-
-                    // We normalize paths from `\` to `/` as MSBuild items could use `\`.
-                    targetPath = targetPath.Replace('\\', '/');
+                    targetPath = Path.GetFileName(item.ItemSpec);
+                }
 
-                    var generatedFileName = $"{i++}_{Path.GetFileName(item.ItemSpec)}";
+                // We normalize paths from `\` to `/` as MSBuild items could use `\`.
+                targetPath = targetPath.Replace('\\', '/');
 
-                    File.Copy(item.ItemSpec, Path.Join(supportFilesDir, generatedFileName), true);
+                var generatedFileName = $"{i++}_{Path.GetFileName(item.ItemSpec)}";
 
-                    var actualItemName = "supportFiles/" + generatedFileName;
+                File.Copy(item.ItemSpec, Path.Join(supportFilesDir, generatedFileName), true);
 
-                    sw.WriteLine("\t\t{");
-                    sw.WriteLine("\t\t\tbehavior: \"vfs\",");
-                    sw.WriteLine($"\t\t\tname: \"{actualItemName}\",");
-                    sw.WriteLine($"\t\t\tvirtual_path: \"{targetPath}\",");
-                    sw.WriteLine("\t\t},");
-                }
+                var asset = new VfsEntry ($"supportFiles/{generatedFileName}") {
+                    VirtualPath = targetPath
+                };
+                config.Assets.Add(asset);
             }
+        }
 
-            var enableRemote = (RemoteSources != null) && (RemoteSources!.Length > 0);
-            var sEnableRemote = enableRemote ? "true" : "false";
-
-            sw.WriteLine($"\t\t{{ behavior: \"icu\", name: \"icudt.dat\", load_remote: {sEnableRemote} }},");
-            sw.WriteLine($"\t\t{{ behavior: \"vfs\", name: \"dotnet.timezones.blat\", virtual_path: \"/usr/share/zoneinfo/\" }}");
-            sw.WriteLine ("\t],");
+        config.Assets.Add(new IcuData { LoadRemote = RemoteSources?.Length > 0 });
+        config.Assets.Add(new VfsEntry ("dotnet.timezones.blat") { VirtualPath = "/usr/share/zoneinfo/"});
 
-            if (enableRemote) {
-                sw.WriteLine("\tremote_sources: [");
-                foreach (var source in RemoteSources!)
-                    sw.WriteLine("\t\t\"" + source.ItemSpec + "\", ");
-                sw.WriteLine ("\t],");
-            }
+        if (RemoteSources?.Length > 0) {
+            foreach (var source in RemoteSources)
+                if (source != null && source.ItemSpec != null)
+                    config.RemoteSources.Add(source.ItemSpec);
+        }
 
-            sw.WriteLine ("};");
+        using (var sw = File.CreateText(Path.Join(AppDir, "mono-config.js")))
+        {
+            var json = JsonSerializer.Serialize (config, new JsonSerializerOptions { WriteIndented = true });
+            sw.Write($"config = {json};");
         }
 
         using (var sw = File.CreateText(Path.Join(AppDir, "run-v8.sh")))