public void TestLayoutBundleReferences() { var coll = new AppletCollection(); coll.Add(AppletManifest.Load(typeof(TestRenderApplets).Assembly.GetManifestResourceStream("SanteDB.Core.Applets.Test.LayoutAngularTest.xml"))); var asset = coll.ResolveAsset("app://org.santedb.applet.test.layout/index.html"); var render = coll.RenderAssetContent(asset); string html = Encoding.UTF8.GetString(render); Assert.IsTrue(html.Contains("index-controller"), "Missing index-controller"); Assert.IsTrue(html.Contains("layout-controller"), "Missing layout-controller"); Assert.IsTrue(html.Contains("index-style"), "Missing index-style"); Assert.IsTrue(html.Contains("layout-controller"), "Missing layout-style"); }
/// <summary> /// Compile /// </summary> static int Compile(ConsoleParameters parameters) { int retVal = 0; // First is there a Manifest.xml? if (!Path.IsPathRooted(parameters.Source)) { parameters.Source = Path.Combine(Environment.CurrentDirectory, parameters.Source); } // Applet collection AppletCollection ac = new AppletCollection(); XmlSerializer xsz = new XmlSerializer(typeof(AppletManifest)); XmlSerializer xpz = new XmlSerializer(typeof(AppletPackage)); if (parameters.References != null) { foreach (var itm in parameters.References) { if (File.Exists(itm)) { using (var fs = File.OpenRead(itm)) { if (Path.GetExtension(itm) == ".pak") { using (var gzs = new GZipStream(fs, CompressionMode.Decompress)) { var pack = xpz.Deserialize(gzs) as AppletPackage; var mfst = pack.Unpack(); mfst.Initialize(); ac.Add(mfst); Console.WriteLine("Added reference to {0}; v={1}", mfst.Info.Id, mfst.Info.Version); } } else { var mfst = xsz.Deserialize(fs) as AppletManifest; mfst.Initialize(); ac.Add(mfst); Console.WriteLine("Added reference to {0}; v={1}", mfst.Info.Id, mfst.Info.Version); } } } } } Console.WriteLine("Processing {0}...", parameters.Source); String manifestFile = Path.Combine(parameters.Source, "manifest.xml"); if (!File.Exists(manifestFile)) { Console.WriteLine("Directory must have manifest.xml"); } else { Console.WriteLine("\t Reading Manifest...", parameters.Source); using (var fs = File.OpenRead(manifestFile)) { AppletManifest mfst = xsz.Deserialize(fs) as AppletManifest; mfst.Assets.AddRange(ProcessDirectory(parameters.Source, parameters.Source, parameters)); foreach (var i in mfst.Assets) { i.Name = i.Name.Substring(1); } if (mfst.Info.Version.Contains("*")) { mfst.Info.Version = mfst.Info.Version.Replace("*", (((DateTime.Now.Subtract(new DateTime(DateTime.Now.Year, 1, 1)).Ticks >> 24) % 10000)).ToString("0000")); } if (!Directory.Exists(Path.GetDirectoryName(parameters.Output)) && !String.IsNullOrEmpty(Path.GetDirectoryName(parameters.Output))) { Directory.CreateDirectory(Path.GetDirectoryName(parameters.Output)); } AppletPackage pkg = null; // Is there a signature? if (!String.IsNullOrEmpty(parameters.SignKey)) { pkg = CreateSignedPackage(mfst, parameters); if (pkg == null) { return(-102); } } else { Console.WriteLine("WARNING:>>> THIS PACKAGE IS NOT SIGNED - MOST OPEN IZ TOOLS WILL NOT LOAD IT"); mfst.Info.PublicKeyToken = null; pkg = mfst.CreatePackage(parameters.Compression); //pkg.Meta.PublicKeyToken = null; } pkg.Meta.Hash = SHA256.Create().ComputeHash(pkg.Manifest); using (var ofs = File.Create(Path.ChangeExtension(parameters.Output ?? "out.pak", ".pak"))) { pkg.Save(ofs); } // Render the build directory if (!String.IsNullOrEmpty(parameters.Deploy)) { var bindir = Path.Combine(Path.GetDirectoryName(parameters.Output), "bin"); if (String.IsNullOrEmpty(parameters.Deploy)) { if (Directory.Exists(bindir) && parameters.Clean) { Directory.Delete(bindir, true); } bindir = Path.Combine(bindir, mfst.Info.Id); Directory.CreateDirectory(bindir); } else { bindir = parameters.Deploy; } mfst.Initialize(); ac.Add(mfst); foreach (var lang in mfst.Strings) { string wd = Path.Combine(bindir, lang.Language); if (String.IsNullOrEmpty(parameters.Lang)) { Directory.CreateDirectory(wd); } else if (parameters.Lang == lang.Language) { wd = bindir; } else { continue; } foreach (var m in ac) { foreach (var itm in m.Assets) { try { String fn = Path.Combine(wd, m.Info.Id, itm.Name.Replace("/", "\\")); Console.WriteLine("\tRendering {0}...", fn); if (!Directory.Exists(Path.GetDirectoryName(fn))) { Directory.CreateDirectory(Path.GetDirectoryName(fn)); } File.WriteAllBytes(fn, ac.RenderAssetContent(itm, lang.Language)); } catch (Exception e) { Console.WriteLine("E: {0}: {1} {2}", itm, e.GetType().Name, e); retVal = -1000; } } } } } } } return(retVal); }
/// <summary> /// Package an APK to the output directory /// </summary> private void PackageApk() { Emit.Message("INFO", "Will package {0}.apk ...", this.m_package.Meta.Id); var workingDir = Path.Combine(Path.GetTempPath(), "dcg-apk", this.m_package.Meta.Id); if (!String.IsNullOrEmpty(this.m_parameters.DcdrAssetOutput)) { workingDir = Path.Combine(this.m_parameters.DcdrAssetOutput, "dcg-apk"); } if (!Directory.Exists(workingDir)) { Directory.CreateDirectory(workingDir); } this.CloneTarget("https://github.com/santedb/santedb-dc-android", workingDir, this.m_parameters.SourceBranch); var appletCollection = new AppletCollection(); // Next slip in the applets from our output Emit.Message("INFO", "Slipstreaming Applets"); if (this.m_package is AppletSolution solution) { foreach (var f in Directory.GetFiles(Path.Combine(workingDir, "SanteDB.DisconnectedClient.Android", "Assets", "Applets"), "*.pak")) { Emit.Message("WARN", "Removing stale applet {0}", f); File.Delete(f); } foreach (var pkg in solution.Include) { Emit.Message("INFO", "Injecting applet {0}", pkg.Meta.Id); this.SerializeApplet(pkg, Path.Combine(workingDir, "SanteDB.DisconnectedClient.Android", "Assets", "Applets"), Path.Combine(workingDir, "SanteDB.DisconnectedClient.Android", "SanteDB.DisconnectedClient.Android.csproj")); appletCollection.Add(pkg.Unpack()); } } else { this.SerializeApplet(this.m_package, Path.Combine(workingDir, "SanteDB.DisconnectedClient.Android", "Assets", "Applets"), Path.Combine(workingDir, "SanteDB.DisconnectedClient.Android", "SanteDB.DisconnectedClient.Android.csproj")); appletCollection.Add(this.m_package.Unpack()); } // Next setup the android manifest var manifest = new XmlDocument(); var versionCode = new Version(this.m_package.Meta.Version); manifest.Load(Path.Combine(workingDir, "SanteDB.DisconnectedClient.Android", "Properties", "AndroidManifest.xml")); manifest.DocumentElement.SetAttribute("versionCode", "http://schemas.android.com/apk/res/android", $"{versionCode.Major:00}{versionCode.Minor:00}{versionCode.Build:000}"); manifest.DocumentElement.SetAttribute("versionName", "http://schemas.android.com/apk/res/android", this.m_package.Meta.Version); manifest.DocumentElement.SetAttribute("package", this.m_package.Meta.Id); var providerNode = manifest.SelectSingleNode("/manifest/application/provider") as XmlElement; providerNode.SetAttribute("authorities", "http://schemas.android.com/apk/res/android", $"{this.m_package.Meta.Id}.fileprovider"); manifest.Save(Path.Combine(workingDir, "SanteDB.DisconnectedClient.Android", "Properties", "AndroidManifest.xml")); // Generate the stub for the app info using (var tw = File.CreateText(Path.Combine(workingDir, "SanteDB.DisconnectedClient.Android.Core", "AndroidApplicationInfo.cs"))) { tw.WriteLine("namespace SanteDB.DisconnectedClient.Android.Core \r\n{\r\n\tstatic class AndroidApplicationInfo\r\n\t{"); tw.WriteLine("\t\tinternal const string ApplicationId = \"{0}\";", this.m_package.Meta.Id); tw.WriteLine("\t\tinternal const string ApplicationKey = \"{0}\";", this.m_package.Meta.Uuid); tw.WriteLine("\t\tinternal const string DefaultSecret = \"{0}\";", this.m_package.Meta.PublicKeyToken ?? "$$DEFAULT_PWD$$"); tw.WriteLine("\t}\r\n}"); } // Get the icon var iconAsset = appletCollection.ResolveAsset(this.m_package.Meta.Icon); if (iconAsset?.MimeType == "image/png") { var imageData = appletCollection.RenderAssetContent(iconAsset); Emit.Message("INFO", "Slipstream Icons..."); File.WriteAllBytes(Path.Combine(workingDir, "SanteDB.DisconnectedClient.Android", "Resources", "drawable", "icon.png"), imageData); File.WriteAllBytes(Path.Combine(workingDir, "SanteDB.DisconnectedClient.Android", "Resources", "drawable", "logo.png"), imageData); File.WriteAllBytes(Path.Combine(workingDir, "SanteDB.DisconnectedClient.Android", "Resources", "drawable", "logo_lg.png"), imageData); foreach (var dir in Directory.GetDirectories(Path.Combine(workingDir, "SanteDB.DisconnectedClient.Android", "Resources"), "mipmap-*")) { File.WriteAllBytes(Path.Combine(dir, "Icon.png"), imageData); } } // Swap out the translation var strings = new XmlDocument(); strings.Load(Path.Combine(workingDir, "SanteDB.DisconnectedClient.Android", "Resources", "values", "Strings.xml")); strings.SelectSingleNode("//*[local-name() = 'string'][@name = 'app_name']").InnerText = this.m_package.Meta.GetName("en", true); strings.Save(Path.Combine(workingDir, "SanteDB.DisconnectedClient.Android", "Resources", "values", "Strings.xml")); // Locate MSBUILD Path if (String.IsNullOrEmpty(this.m_parameters.MsBuild)) { var vsDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), "Microsoft Visual Studio"); if (Directory.Exists(vsDir)) { this.m_parameters.MsBuild = Directory.GetFiles(vsDir, "msbuild.exe", SearchOption.AllDirectories).LastOrDefault(); } } if (!File.Exists(this.m_parameters.MsBuild)) { Emit.Message("ERROR", "Cannot find Visual Studio MSBUILD Tooling"); throw new InvalidOperationException("Missing Visual Studio Build Tooling"); } var arguments = new String[] { $"/p:Configuration=Pakman /m:1 /t:restore \"{Path.Combine(workingDir, "santedb-dc-android.sln")}\"", $"/p:Configuration=Pakman /m:1 /t:SignAndroidPackage \"{Path.Combine(workingDir, "santedb-dc-android.sln")}\"" }; foreach (var args in arguments) { var processInfo = new ProcessStartInfo(this.m_parameters.MsBuild); processInfo.Arguments = args; processInfo.WindowStyle = ProcessWindowStyle.Hidden; processInfo.RedirectStandardOutput = true; processInfo.RedirectStandardError = true; processInfo.UseShellExecute = false; Emit.Message("INFO", "Running {0} {1}", processInfo.FileName, processInfo.Arguments); using (var process = new Process()) { process.StartInfo = processInfo; process.EnableRaisingEvents = true; var mre = new ManualResetEventSlim(false); process.ErrorDataReceived += (o, e) => Console.WriteLine(e.Data); process.OutputDataReceived += (o, e) => Console.WriteLine(e.Data); process.Start(); process.BeginErrorReadLine(); process.BeginOutputReadLine(); process.WaitForExit(); process.Close(); } } // Copy the output of the APK foreach (var apk in Directory.GetFiles(Path.Combine(workingDir, "SanteDB.DisconnectedClient.Android", "bin", "Pakman"), "*.apk")) { var dest = Path.Combine(Path.GetDirectoryName(this.m_parameters.Output), Path.GetFileName(apk)); Emit.Message("INFO", "Copying {0} to {1}...", apk, dest); File.Copy(apk, dest, true); } }