public override void Transform(Engine engine, Package package) { Initialize(engine, package); mergeFileLines.Add("src\\system\\assets\\less\\_custom.less", new List<string>()); mergeFileLines.Add("src\\system\\assets\\less\\_modules.less", new List<string>()); mergeFileLines.Add("src\\templates\\partials\\module-scripts-header.hbs", new List<string>()); mergeFileLines.Add("src\\templates\\partials\\module-scripts-footer.hbs", new List<string>()); StringBuilder publishedFiles = new StringBuilder(); string cleanup = package.GetValue("cleanup") ?? String.Empty; // not using System.IO.Path.GetTempPath() because the paths in our zip are already quite long, // so we need a very short temp path for the extract of our zipfile to succeed // using drive from tridion cm homedir for temp folder tempFolder = ConfigurationSettings.GetTcmHomeDirectory().Substring(0, 3) + "t" + DateTime.Now.ToString("yyyyMMddHHmmssfff") + "\\"; try { // read values from Component var config = GetComponent(); var fields = new ItemFields(config.Content, config.Schema); var favicon = fields.GetMultimediaLink("favicon"); var version = fields.GetTextValue("version"); var nodeJs = fields.GetTextValue("nodeJs"); // set defaults if required if (String.IsNullOrEmpty(nodeJs)) { nodeJs = NodejsDefault; } PublishJson(String.Format("{{\"version\":{0}}}", JsonEncode(version)), config, GetPublication().RootStructureGroup, "version", "version"); // create temp folder Directory.CreateDirectory(tempFolder); Log.Debug("Created " + tempFolder); ProcessModules(); // build html design ProcessStartInfo info = new ProcessStartInfo { FileName = "cmd.exe", Arguments = String.Format("/c \"{0}\" start --color=false", nodeJs), WorkingDirectory = tempFolder, CreateNoWindow = true, ErrorDialog = false, UseShellExecute = false, RedirectStandardOutput = true, RedirectStandardError = true, StandardErrorEncoding = Encoding.UTF8, StandardOutputEncoding = Encoding.UTF8 }; using (Process cmd = new Process {StartInfo = info}) { cmd.Start(); using (StreamReader reader = cmd.StandardOutput) { string output = reader.ReadToEnd(); if (!String.IsNullOrEmpty(output)) { Log.Info(output); // TODO: check for errors in standard output and throw exception } } using (StreamReader reader = cmd.StandardError) { string error = reader.ReadToEnd(); if (!String.IsNullOrEmpty(error)) { string user = System.Security.Principal.WindowsIdentity.GetCurrent().Name; Exception ex = new Exception(error); ex.Data.Add("Filename", info.FileName); ex.Data.Add("Arguments", info.Arguments); ex.Data.Add("User", user); if (error.ToLower().Contains("the system cannot find the path specified")) { throw new Exception(String.Format("Node.js not installed or missing from path for user {0}.", user), ex); } else if (error.ToLower().Contains("mkdir") && error.ToLower().Contains("appdata\\roaming\\npm")) { throw new Exception(String.Format("Node.js cannot access %APPDATA% for user {0}.", user), ex); } throw ex; } } cmd.WaitForExit(); } // publish all binaries from dist folder string dist = tempFolder + "dist\\"; if (Directory.Exists(dist)) { // save favicon to disk (if available) if (favicon != null) { File.WriteAllBytes(dist + "favicon.ico", favicon.BinaryContent.GetByteArray()); Log.Debug("Saved " + dist + "favicon.ico"); } string[] files = Directory.GetFiles(dist, "*.*", SearchOption.AllDirectories); foreach (var file in files) { string filename = file.Substring(file.LastIndexOf('\\') + 1); string extension = filename.Substring(filename.LastIndexOf('.') + 1); Log.Debug("Found " + file); // determine correct structure group (create if not exists) Publication pub = (Publication)config.ContextRepository; string relativeFolderPath = file.Substring(dist.Length - 1, file.LastIndexOf('\\') + 1 - dist.Length); relativeFolderPath = relativeFolderPath.Replace("system", SystemSgName).Replace('\\', '/'); string pubSgWebDavUrl = pub.RootStructureGroup.WebDavUrl; string publishSgWebDavUrl = pubSgWebDavUrl + relativeFolderPath; StructureGroup sg = engine.GetObject(publishSgWebDavUrl) as StructureGroup; if (sg == null) { throw new Exception("Missing Structure Group " + publishSgWebDavUrl); } // add binary to package and publish using (FileStream fs = File.OpenRead(file)) { Item binaryItem = Package.CreateStreamItem(GetContentType(extension), fs); var binary = engine.PublishingContext.RenderedItem.AddBinary(binaryItem.GetAsStream(), filename, sg, "dist-" + filename, config, GetMimeType(extension)); binaryItem.Properties[Item.ItemPropertyPublishedPath] = binary.Url; package.PushItem(filename, binaryItem); if (publishedFiles.Length > 0) { publishedFiles.Append(","); } publishedFiles.AppendFormat("\"{0}\"", binary.Url); Log.Info("Published " + binary.Url); } } } else { throw new Exception("Grunt build failed, dist folder is missing."); } } finally { if (String.IsNullOrEmpty(cleanup) || !cleanup.ToLower().Equals("false")) { // cleanup workfolder Directory.Delete(tempFolder, true); Log.Debug("Removed " + tempFolder); } else { Log.Debug("Did not cleanup " + tempFolder); } } // output json result package.PushItem(Package.OutputName, package.CreateStringItem(ContentType.Text, String.Format(JsonOutputFormat, publishedFiles))); }
public override void Transform(Engine engine, Package package) { Initialize(engine, package); bool cleanup; // cleanup should be true by default (if not filled in) if (!package.TryGetParameter("cleanup", out cleanup, Logger)) { cleanup = true; } string drive; package.TryGetParameter("drive", out drive, Logger); List <Binary> binaries = new List <Binary>(); // Read values from HTML Design Configuration Component (which should be the Component used for this Component Presentation) Component inputComponent = GetComponent(); if (inputComponent.Schema.NamespaceUri != HtmlDesignConfigNamespace || inputComponent.Schema.RootElementName != HtmlDesignConfigRootElementName) { throw new DxaException( string.Format("Unexpected input Component {0} ('{1}'). Expecting HTML Design Configuration Component.", inputComponent.Id, inputComponent.Title) ); } ItemFields htmlDesignConfigFields = new ItemFields(inputComponent.Content, inputComponent.Schema); Component favIconComponent = htmlDesignConfigFields.GetMultimediaLink("favicon"); string htmlDesignVersion = htmlDesignConfigFields.GetTextValue("version"); // Publish version.json file IDictionary <string, string> versionData = new Dictionary <string, string> { { "version", htmlDesignVersion } }; Binary versionJsonBinary = AddJsonBinary(versionData, inputComponent, Publication.RootStructureGroup, "version", variantId: "version"); binaries.Add(versionJsonBinary); string tempFolder = GetTempFolder(drive); Directory.CreateDirectory(tempFolder); Logger.Debug("Created temp folder: " + tempFolder); try { // Unzip and merge files ProcessModules(tempFolder); string distFolder = BuildHtmlDesign(tempFolder); // Save favicon to disk (if available) if (favIconComponent != null) { string favIconFilePath = Path.Combine(distFolder, "favicon.ico"); File.WriteAllBytes(favIconFilePath, favIconComponent.BinaryContent.GetByteArray()); Logger.Debug("Saved " + favIconFilePath); } // Publish all files from dist folder Publication pub = (Publication)inputComponent.ContextRepository; string rootStructureGroupWebDavUrl = pub.RootStructureGroup.WebDavUrl; RenderedItem renderedItem = engine.PublishingContext.RenderedItem; string[] distFiles = Directory.GetFiles(distFolder, "*.*", SearchOption.AllDirectories); foreach (string file in distFiles) { Logger.Debug("Found " + file); // Map the file path to a Structure Group string relativeFolderPath = file.Substring(distFolder.Length, file.LastIndexOf('\\') - distFolder.Length); Logger.Debug(string.Format("Relative folder path: '{0}'", relativeFolderPath)); string sgWebDavUrl = rootStructureGroupWebDavUrl + relativeFolderPath.Replace("system", SystemSgName).Replace('\\', '/'); StructureGroup structureGroup = engine.GetObject(sgWebDavUrl) as StructureGroup; if (structureGroup == null) { throw new DxaException(string.Format("Cannot publish '{0}' because Structure Group '{1}' does not exist.", file, sgWebDavUrl)); } // Add binary to package and publish using (FileStream fs = File.OpenRead(file)) { string filename = Path.GetFileName(file); string extension = Path.GetExtension(file); string variantId = string.Format("dist-{0}-{1}", structureGroup.Id.ItemId, filename); Item binaryItem = Package.CreateStreamItem(GetContentType(extension), fs); Binary binary = renderedItem.AddBinary( binaryItem.GetAsStream(), filename, structureGroup, variantId, inputComponent, GetMimeType(extension) ); binaryItem.Properties[Item.ItemPropertyPublishedPath] = binary.Url; package.PushItem(filename, binaryItem); binaries.Add(binary); Logger.Info(string.Format("Added Binary '{0}' related to Component '{1}' ({2}) with variant ID '{3}'", binary.Url, inputComponent.Title, inputComponent.Id, variantId)); } } } finally { if (cleanup) { Directory.Delete(tempFolder, true); Logger.Debug("Removed temp folder " + tempFolder); } else { Logger.Debug("Did not cleanup temp folder " + tempFolder); } } OutputSummary("Publish HTML Design", binaries.Select(b => b.Url)); }
public override void Transform(Engine engine, Package package) { Initialize(engine, package); bool cleanup; package.TryGetParameter("cleanup", out cleanup, Logger); string drive; package.TryGetParameter("drive", out drive, Logger); List<Binary> binaries = new List<Binary>(); // Read values from HTML Design Configuration Component (which should be the Component used for this Component Presentation) Component inputComponent = GetComponent(); if (inputComponent.Schema.NamespaceUri != HtmlDesignConfigNamespace || inputComponent.Schema.RootElementName != HtmlDesignConfigRootElementName) { throw new DxaException( string.Format("Unexpected input Component {0} ('{1}'). Expecting HTML Design Configuration Component.", inputComponent.Id, inputComponent.Title) ); } ItemFields htmlDesignConfigFields = new ItemFields(inputComponent.Content, inputComponent.Schema); Component favIconComponent = htmlDesignConfigFields.GetMultimediaLink("favicon"); string htmlDesignVersion = htmlDesignConfigFields.GetTextValue("version"); // Publish version.json file IDictionary<string, string> versionData = new Dictionary<string, string> { { "version", htmlDesignVersion } }; Binary versionJsonBinary = AddJsonBinary(versionData, inputComponent, Publication.RootStructureGroup, "version", variantId: "version"); binaries.Add(versionJsonBinary); string tempFolder = GetTempFolder(drive); Directory.CreateDirectory(tempFolder); Logger.Debug("Created temp folder: " + tempFolder); try { // Unzip and merge files ProcessModules(tempFolder); string distFolder = BuildHtmlDesign(tempFolder); // Save favicon to disk (if available) if (favIconComponent != null) { string favIconFilePath = Path.Combine(distFolder, "favicon.ico"); File.WriteAllBytes(favIconFilePath, favIconComponent.BinaryContent.GetByteArray()); Logger.Debug("Saved " + favIconFilePath); } // Publish all files from dist folder Publication pub = (Publication) inputComponent.ContextRepository; string rootStructureGroupWebDavUrl = pub.RootStructureGroup.WebDavUrl; RenderedItem renderedItem = engine.PublishingContext.RenderedItem; string[] distFiles = Directory.GetFiles(distFolder, "*.*", SearchOption.AllDirectories); foreach (string file in distFiles) { Logger.Debug("Found " + file); // Map the file path to a Structure Group string relativeFolderPath = file.Substring(distFolder.Length, file.LastIndexOf('\\') - distFolder.Length); Logger.Debug(string.Format("Relative folder path: '{0}'",relativeFolderPath)); string sgWebDavUrl = rootStructureGroupWebDavUrl + relativeFolderPath.Replace("system", SystemSgName).Replace('\\', '/'); StructureGroup structureGroup = engine.GetObject(sgWebDavUrl) as StructureGroup; if (structureGroup == null) { throw new DxaException(string.Format("Cannot publish '{0}' because Structure Group '{1}' does not exist.", file, sgWebDavUrl)); } // Add binary to package and publish using (FileStream fs = File.OpenRead(file)) { string filename = Path.GetFileName(file); string extension = Path.GetExtension(file); string variantId = string.Format("dist-{0}-{1}", structureGroup.Id.ItemId, filename); Item binaryItem = Package.CreateStreamItem(GetContentType(extension), fs); Binary binary = renderedItem.AddBinary( binaryItem.GetAsStream(), filename, structureGroup, variantId, inputComponent, GetMimeType(extension) ); binaryItem.Properties[Item.ItemPropertyPublishedPath] = binary.Url; package.PushItem(filename, binaryItem); binaries.Add(binary); Logger.Info(string.Format("Added Binary '{0}' related to Component '{1}' ({2}) with variant ID '{3}'", binary.Url, inputComponent.Title, inputComponent.Id, variantId)); } } } finally { if (cleanup) { Directory.Delete(tempFolder, true); Logger.Debug("Removed temp folder " + tempFolder); } else { Logger.Debug("Did not cleanup temp folder " + tempFolder); } } OutputSummary("Publish HTML Design", binaries.Select(b => b.Url)); }
public override void Transform(Engine engine, Package package) { Initialize(engine, package); _mergeFileLines.Add("src\\system\\assets\\less\\_custom.less", new List<string>()); _mergeFileLines.Add("src\\system\\assets\\less\\_modules.less", new List<string>()); _mergeFileLines.Add("src\\templates\\partials\\module-scripts-header.hbs", new List<string>()); _mergeFileLines.Add("src\\templates\\partials\\module-scripts-footer.hbs", new List<string>()); StringBuilder publishedFiles = new StringBuilder(); string drive = package.GetValue("drive") ?? String.Empty; string cleanup = package.GetValue("cleanup") ?? String.Empty; // not using System.IO.Path.GetTempPath() because the paths in our zip are already quite long, // so we need a very short temp path for the extract of our zipfile to succeed // using current time and convert to hex (the date won't matter as this folder is cleaned up so time is unique enough) int timestamp = Convert.ToInt32(DateTime.Now.ToString("HHmmssfff")); if (!String.IsNullOrEmpty(drive) && Char.IsLetter(drive.First())) { _tempFolder = drive.First() + @":\_" + timestamp.ToString("x"); } else { // using drive from tridion cm homedir for temp folder _tempFolder = ConfigurationSettings.GetTcmHomeDirectory().Substring(0, 3) + "_" + timestamp.ToString("x"); } try { // read values from Component Component config = GetComponent(); ItemFields fields = new ItemFields(config.Content, config.Schema); Component favicon = fields.GetMultimediaLink("favicon"); string version = fields.GetTextValue("version"); string url = PublishJson(String.Format("{{\"version\":{0}}}", JsonEncode(version)), config, GetPublication().RootStructureGroup, "version", "version"); publishedFiles.AppendCommaSeparated(url); Logger.Info("Published " + url); // create temp folder Directory.CreateDirectory(_tempFolder); Logger.Debug("Created " + _tempFolder); // unzip and merge files ProcessModules(); // build html design string user = System.Security.Principal.WindowsIdentity.GetCurrent().Name; ProcessStartInfo info = new ProcessStartInfo { FileName = "cmd.exe", Arguments = "/c npm start --color=false", WorkingDirectory = _tempFolder, CreateNoWindow = true, ErrorDialog = false, UseShellExecute = false, RedirectStandardOutput = true, RedirectStandardError = true, StandardErrorEncoding = Encoding.UTF8, StandardOutputEncoding = Encoding.UTF8 }; using (Process cmd = new Process { StartInfo = info }) { cmd.Start(); using (StreamReader reader = cmd.StandardOutput) { string output = reader.ReadToEnd(); if (!String.IsNullOrEmpty(output)) { Logger.Info(output); // TODO: check for errors in standard output and throw exception } } using (StreamReader reader = cmd.StandardError) { string error = reader.ReadToEnd(); if (!String.IsNullOrEmpty(error)) { Exception ex = new Exception(error); ex.Data.Add("Filename", info.FileName); ex.Data.Add("Arguments", info.Arguments); ex.Data.Add("User", user); // TODO: check for known errors and throw exception with a user friendly message //if (error.ToLower().Contains("something")) //{ // throw new Exception(String.Format("Something went wrong for user {0}.", user), ex); //} throw ex; } } cmd.WaitForExit(); } // publish all binaries from dist folder string dist = Path.Combine(_tempFolder, "dist"); if (Directory.Exists(dist)) { // save favicon to disk (if available) if (favicon != null) { string ico = Path.Combine(dist, "favicon.ico"); File.WriteAllBytes(ico, favicon.BinaryContent.GetByteArray()); Logger.Debug("Saved " + ico); } string[] files = Directory.GetFiles(dist, "*.*", SearchOption.AllDirectories); foreach (string file in files) { string filename = Path.GetFileName(file); string extension = Path.GetExtension(file); Logger.Debug("Found " + file); // determine correct structure group Publication pub = (Publication)config.ContextRepository; string relativeFolderPath = file.Substring(dist.Length, file.LastIndexOf('\\') - dist.Length); Logger.Debug("Relative path: " + relativeFolderPath); relativeFolderPath = relativeFolderPath.Replace("system", SystemSgName).Replace('\\', '/'); string pubSgWebDavUrl = pub.RootStructureGroup.WebDavUrl; string publishSgWebDavUrl = pubSgWebDavUrl + relativeFolderPath; Logger.Debug("Structure Group WebDAV URL: " + publishSgWebDavUrl); StructureGroup sg = engine.GetObject(publishSgWebDavUrl) as StructureGroup; if (sg == null) { throw new Exception("Missing Structure Group " + publishSgWebDavUrl); } // add binary to package and publish using (FileStream fs = File.OpenRead(file)) { Item binaryItem = Package.CreateStreamItem(GetContentType(extension), fs); Binary binary = engine.PublishingContext.RenderedItem.AddBinary(binaryItem.GetAsStream(), filename, sg, "dist-" + filename, config, GetMimeType(extension)); binaryItem.Properties[Item.ItemPropertyPublishedPath] = binary.Url; package.PushItem(filename, binaryItem); publishedFiles.AppendCommaSeparated("\"{0}\"", binary.Url); Logger.Info("Published " + binary.Url); } } } else { throw new Exception("Grunt build failed, dist folder is missing."); } } finally { if (String.IsNullOrEmpty(cleanup) || !cleanup.ToLower().Equals("false")) { // cleanup workfolder Directory.Delete(_tempFolder, true); Logger.Debug("Removed " + _tempFolder); } else { Logger.Debug("Did not cleanup " + _tempFolder); } } // output json result package.PushItem(Package.OutputName, package.CreateStringItem(ContentType.Text, String.Format(JsonOutputFormat, publishedFiles))); }
public override void Transform(Engine engine, Package package) { Initialize(engine, package); _mergeFileLines.Add("src\\system\\assets\\less\\_custom.less", new List <string>()); _mergeFileLines.Add("src\\system\\assets\\less\\_modules.less", new List <string>()); _mergeFileLines.Add("src\\templates\\partials\\module-scripts-header.hbs", new List <string>()); _mergeFileLines.Add("src\\templates\\partials\\module-scripts-footer.hbs", new List <string>()); _mergeFileLines.Add("src\\templates\\partials\\module-scripts-xpm.hbs", new List <string>()); StringBuilder publishedFiles = new StringBuilder(); string drive = package.GetValue("drive") ?? String.Empty; string cleanup = package.GetValue("cleanup") ?? String.Empty; // not using System.IO.Path.GetTempPath() because the paths in our zip are already quite long, // so we need a very short temp path for the extract of our zipfile to succeed // using current time and convert to hex (the date won't matter as this folder is cleaned up so time is unique enough) int timestamp = Convert.ToInt32(DateTime.Now.ToString("HHmmssfff")); if (!String.IsNullOrEmpty(drive) && Char.IsLetter(drive.First())) { _tempFolder = drive.First() + @":\_" + timestamp.ToString("x"); } else { // using drive from tridion cm homedir for temp folder _tempFolder = ConfigurationSettings.GetTcmHomeDirectory().Substring(0, 3) + "_" + timestamp.ToString("x"); } try { // read values from Component Component config = GetComponent(); ItemFields fields = new ItemFields(config.Content, config.Schema); Component favicon = fields.GetMultimediaLink("favicon"); string version = fields.GetTextValue("version"); string url = PublishJson(String.Format("{{\"version\":{0}}}", JsonEncode(version)), config, GetPublication().RootStructureGroup, "version", "version"); publishedFiles.AppendCommaSeparated(url); Logger.Info("Published " + url); // create temp folder Directory.CreateDirectory(_tempFolder); Logger.Debug("Created " + _tempFolder); // unzip and merge files ProcessModules(); // build html design string user = System.Security.Principal.WindowsIdentity.GetCurrent().Name; ProcessStartInfo info = new ProcessStartInfo { FileName = "cmd.exe", Arguments = "/c npm start --color=false", WorkingDirectory = _tempFolder, CreateNoWindow = true, ErrorDialog = false, UseShellExecute = false, RedirectStandardOutput = true, RedirectStandardError = true, StandardErrorEncoding = Encoding.UTF8, StandardOutputEncoding = Encoding.UTF8 }; using (Process cmd = new Process { StartInfo = info }) { cmd.Start(); using (StreamReader reader = cmd.StandardOutput) { string output = reader.ReadToEnd(); if (!String.IsNullOrEmpty(output)) { Logger.Info(output); // TODO: check for errors in standard output and throw exception } } using (StreamReader reader = cmd.StandardError) { string error = reader.ReadToEnd(); if (!String.IsNullOrEmpty(error)) { Exception ex = new Exception(error); ex.Data.Add("Filename", info.FileName); ex.Data.Add("Arguments", info.Arguments); ex.Data.Add("User", user); // TODO: check for known errors and throw exception with a user friendly message //if (error.ToLower().Contains("something")) //{ // throw new Exception(String.Format("Something went wrong for user {0}.", user), ex); //} throw ex; } } cmd.WaitForExit(); } // publish all binaries from dist folder string dist = Path.Combine(_tempFolder, "dist"); if (Directory.Exists(dist)) { // save favicon to disk (if available) if (favicon != null) { string ico = Path.Combine(dist, "favicon.ico"); File.WriteAllBytes(ico, favicon.BinaryContent.GetByteArray()); Logger.Debug("Saved " + ico); } string[] files = Directory.GetFiles(dist, "*.*", SearchOption.AllDirectories); foreach (string file in files) { string filename = Path.GetFileName(file); string extension = Path.GetExtension(file); Logger.Debug("Found " + file); // determine correct structure group Publication pub = (Publication)config.ContextRepository; string relativeFolderPath = file.Substring(dist.Length, file.LastIndexOf('\\') - dist.Length); Logger.Debug("Relative path: " + relativeFolderPath); relativeFolderPath = relativeFolderPath.Replace("system", SystemSgName).Replace('\\', '/'); string pubSgWebDavUrl = pub.RootStructureGroup.WebDavUrl; string publishSgWebDavUrl = pubSgWebDavUrl + relativeFolderPath; Logger.Debug("Structure Group WebDAV URL: " + publishSgWebDavUrl); StructureGroup sg = engine.GetObject(publishSgWebDavUrl) as StructureGroup; if (sg == null) { throw new Exception("Missing Structure Group " + publishSgWebDavUrl); } // add binary to package and publish using (FileStream fs = File.OpenRead(file)) { Item binaryItem = Package.CreateStreamItem(GetContentType(extension), fs); Binary binary = engine.PublishingContext.RenderedItem.AddBinary(binaryItem.GetAsStream(), filename, sg, "dist-" + filename, config, GetMimeType(extension)); binaryItem.Properties[Item.ItemPropertyPublishedPath] = binary.Url; package.PushItem(filename, binaryItem); publishedFiles.AppendCommaSeparated("\"{0}\"", binary.Url); Logger.Info("Published " + binary.Url); } } } else { throw new Exception("Grunt build failed, dist folder is missing."); } } finally { if (String.IsNullOrEmpty(cleanup) || !cleanup.ToLower().Equals("false")) { // cleanup workfolder Directory.Delete(_tempFolder, true); Logger.Debug("Removed " + _tempFolder); } else { Logger.Debug("Did not cleanup " + _tempFolder); } } // output json result package.PushItem(Package.OutputName, package.CreateStringItem(ContentType.Text, String.Format(JsonOutputFormat, publishedFiles))); }