Beispiel #1
0
        private void FillRenderedItemsForSnippets(RenderedItem rendered, RenderedJsonRendering element)
        {
            if (rendered == null || !rendered.Placeholders.First().Elements.Any())
            {
                return;
            }

            if (!rendered.Placeholders.First().Elements.Any())
            {
                return;
            }

            element.Placeholders.FirstOrDefault()?.Elements?.Clear();

            var renderedPlaceholderElements = rendered.Placeholders.FirstOrDefault()?.Elements;

            if (renderedPlaceholderElements == null)
            {
                return;
            }

            foreach (var renderedPlaceholderElement in renderedPlaceholderElements)
            {
                element.Placeholders.FirstOrDefault()?.Elements
                .Add(renderedPlaceholderElement);
            }
        }
Beispiel #2
0
        /// <summary>
        /// Performs the Transform.
        /// </summary>
        public override void Transform(Engine engine, Package package)
        {
            Logger.Debug("Transform");

            Initialize(engine, package);

            int expandLinkDepth;

            package.TryGetParameter("expandLinkDepth", out expandLinkDepth, Logger);

            string[] modelBuilderTypeNames = GetModelBuilderTypeNames();

            RenderedItem renderedItem = Engine.PublishingContext.RenderedItem;
            Page         page         = GetPage();

            try
            {
                DataModelBuilderSettings settings = new DataModelBuilderSettings
                {
                    ExpandLinkDepth     = expandLinkDepth,
                    GenerateXpmMetadata = IsXpmEnabled || IsPreview,
                    Locale = GetLocale()
                };

                DataModelBuilderPipeline modelBuilderPipeline = new DataModelBuilderPipeline(renderedItem, settings, modelBuilderTypeNames);
                PageModelData            pageModel            = modelBuilderPipeline.CreatePageModel(page);
                OutputJson = JsonSerialize(pageModel, IsPreview, DataModelBinder.SerializerSettings);
            }
            catch (Exception ex)
            {
                throw new DxaException($"An error occurred while rendering {page.FormatIdentifier()}", ex);
            }
        }
 public override dynamic Transform(RenderedItem rendered)
 {
     rendered.Context.Add("placeholders", GetPlaceholders());
     rendered.Context.Add("templates", GetTemplates());
     rendered.Context.Add("renderings", GetRenderings());
     return(base.Transform(rendered));
 }
        private EntityModelData GetEntityModelData(ComponentPresentation cp)
        {
            ComponentTemplate ct = cp.ComponentTemplate;

            // Create a Child Rendered Item for the CP in order to make Component linking work.
            RenderedItem childRenderedItem = new RenderedItem(new ResolvedItem(cp.Component, ct),
                                                              Pipeline.RenderedItem.RenderInstruction);

            Pipeline.RenderedItem.AddRenderedItem(childRenderedItem);

            EntityModelData entityModel;

            if (ct.IsRepositoryPublishable)
            {
                Logger.Debug($"Not expanding DCP ({cp.Component}, {ct})");
                entityModel = new EntityModelData
                {
                    Id = $"{GetDxaIdentifier(cp.Component)}-{GetDxaIdentifier(ct)}"
                };
            }
            else
            {
                entityModel = Pipeline.CreateEntityModel(cp);
            }
            return(entityModel);
        }
        protected string RunTemplate(Type templateType, IdentifiableObject inputItem, Template template = null)
        {
            RenderedItem testRenderedItem = CreateTestRenderedItem(inputItem, template);
            TestEngine   testEngine       = new TestEngine(testRenderedItem);
            Package      testPackage      = new Package(testEngine);

            Type        inputItemType        = inputItem.GetType();
            string      inputItemName        = inputItemType.Name;
            ContentType inputItemContentType = new ContentType($"tridion/{inputItemType.Name.ToLower()}");

            testPackage.PushItem(inputItemName, testPackage.CreateTridionItem(inputItemContentType, inputItem));

            ITemplate testTemplate = Activator.CreateInstance(templateType) as ITemplate;

            Assert.IsNotNull(testTemplate, "testTemplate");

            testTemplate.Transform(testEngine, testPackage);

            Item outputItem = testPackage.GetByName(Package.OutputName);

            Assert.IsNotNull(outputItem, "outputItem");

            string result = outputItem.GetAsString();

            Assert.IsNotNull(result, "result");

            Console.WriteLine("Output Item:");
            Console.WriteLine(result);

            return(result);
        }
        internal TestEngine(RenderedItem renderedItem)
        {
            _session = renderedItem.ResolvedItem.Session;

            // Using reflection to set the private field TemplatingRenderer._renderedItem too (otherwise you get an error that the Engine is not initialized):
            FieldInfo renderedItemField = GetType().BaseType.GetField("_renderedItem", BindingFlags.Instance | BindingFlags.NonPublic);

            renderedItemField?.SetValue(this, renderedItem);
        }
Beispiel #7
0
        public RenderingResult(RenderedItem item, string rootDirectory)
        {
            string path     = Path.Combine(rootDirectory, item.Name);
            string fullPath = Path.GetFullPath(path);

            FilePath        = fullPath;
            Content         = item.Content;
            IsFilePathValid = !PathHasInvalidChars(FilePath);
        }
        private void AddComponentPresentationRegions(IDictionary <string, RegionModelData> regionModels, Page page)
        {
            foreach (ComponentPresentation cp in page.ComponentPresentations)
            {
                ComponentTemplate ct = cp.ComponentTemplate;

                // Create a Child Rendered Item for the CP in order to make Component linking work.
                RenderedItem childRenderedItem = new RenderedItem(new ResolvedItem(cp.Component, ct), Pipeline.RenderedItem.RenderInstruction);
                Pipeline.RenderedItem.AddRenderedItem(childRenderedItem);

                EntityModelData entityModel;
                if (ct.IsRepositoryPublishable)
                {
                    Logger.Debug($"Not expanding DCP ({cp.Component}, {ct})");
                    entityModel = new EntityModelData
                    {
                        Id = $"{GetDxaIdentifier(cp.Component)}-{GetDxaIdentifier(ct)}"
                    };
                }
                else
                {
                    entityModel = Pipeline.CreateEntityModel(cp);
                }

                string  regionName;
                MvcData regionMvcData = GetRegionMvcData(cp.ComponentTemplate, out regionName);

                RegionModelData regionModel;
                if (regionModels.TryGetValue(regionName, out regionModel))
                {
                    if (!regionMvcData.Equals(regionModel.MvcData))
                    {
                        throw new DxaException($"Conflicting Region MVC data detected: [{regionMvcData}] versus [{regionModel.MvcData}]");
                    }
                }
                else
                {
                    regionModel = new RegionModelData
                    {
                        Name     = regionName,
                        MvcData  = regionMvcData,
                        Entities = new List <EntityModelData>()
                    };
                    regionModels.Add(regionName, regionModel);
                }
                regionModel.Entities.Add(entityModel);
            }
        }
        public MultimediaItem(Component component, RenderedItem renderedItem, bool forceDownloadExternal = false)
        {
            Guard.ArgumentIsNotNull(component, "component");
            Guard.ArgumentIsNotNull(renderedItem, "renderedItem");
            Guard.Ensures(component.ComponentType == ComponentType.Multimedia,
                          "Specified component ({0}) is not a multimedia component", component.Id);

            this.Component             = component;
            this.renderedItem          = renderedItem;
            this.forceDownloadExternal = forceDownloadExternal;

            // Statement below is there to bypass a TOM.NET bug.
            // This statement makes sure that the Component is fully loaded.

            var bypassTomNetBug = this.Component.Creator;
        }
        public void DataPresentationTemplate_Success()
        {
            Page dummyPage = (Page)TestSession.GetObject(TestFixture.AutoTestParentHomePageWebDavUrl);

            RenderedItem renderedItem = CreateTestRenderedItem(dummyPage, dummyPage.PageTemplate);

            DataModelBuilderPipeline testModelBuilderPipeline = new DataModelBuilderPipeline(
                renderedItem,
                _defaultModelBuilderSettings,
                _defaultModelBuilderTypeNames,
                new ConsoleLogger()
                );

            ComponentTemplate dataPresentationTemplate = testModelBuilderPipeline.DataPresentationTemplate;

            Assert.IsNotNull(dataPresentationTemplate, "dataPresentationTemplate");
        }
        public void DataPresentationTemplate_FoundAndCached_Success()
        {
            using (Session testSessionWithCache = new Session())
            {
                SimpleCache testCache = new SimpleCache();
                testSessionWithCache.Cache = testCache;

                Page dummyPage = (Page)testSessionWithCache.GetObject(TestFixture.AutoTestParentHomePageWebDavUrl);

                RenderedItem renderedItem = CreateTestRenderedItem(dummyPage, dummyPage.PageTemplate);
                TestLogger   testLogger   = new TestLogger();

                DataModelBuilderPipeline testModelBuilderPipeline = new DataModelBuilderPipeline(
                    renderedItem,
                    _defaultModelBuilderSettings,
                    _defaultModelBuilderTypeNames,
                    testLogger
                    );

                ComponentTemplate dataPresentationTemplate = testModelBuilderPipeline.DataPresentationTemplate;
                Assert.IsNotNull(dataPresentationTemplate, "dataPresentationTemplate");

                SimpleCacheRegion dxaCacheRegion;
                Assert.IsTrue(testCache.Regions.TryGetValue("DXA", out dxaCacheRegion), "DXA Cache Region not found.");
                ComponentTemplate cachedComponentTemplate = dxaCacheRegion.Get("DataPresentationTemplate") as ComponentTemplate;
                Assert.AreEqual(dataPresentationTemplate, cachedComponentTemplate, "cachedComponentTemplate");

                // Create new DataModelBuilderPipeline for same Session; DataPresentationTemplate should be obtained from cache.
                testModelBuilderPipeline = new DataModelBuilderPipeline(
                    renderedItem,
                    _defaultModelBuilderSettings,
                    _defaultModelBuilderTypeNames,
                    testLogger
                    );

                ComponentTemplate dataPresentationTemplate2 = testModelBuilderPipeline.DataPresentationTemplate;
                Assert.AreEqual(dataPresentationTemplate, dataPresentationTemplate2, "dataPresentationTemplate2");

                Assert.IsTrue(
                    testLogger.LoggedMessages.Contains(new LogMessage(LogLevel.Debug, "Obtained Data Presentation Template from cache.")),
                    "Expected Log message not found."
                    );
            }
        }
        internal TestEngine(RenderedItem renderedItem)
        {
            _session = renderedItem.ResolvedItem.Session;

            // Ensuring TestEngine has mocked PublishingContext
            var ctor = typeof(PublishingContext).GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, CallingConventions.Any,
                                                                new Type[] { typeof(ResolvedItem), typeof(PublishInstruction), typeof(PublicationTarget), typeof(RenderedItem), typeof(RenderContext) }, null);
            var publishingContextInstance = (PublishingContext)ctor.Invoke(new object[] { null, null, null, renderedItem, null });

            var setPublishingContext = typeof(Engine).GetMethod("SetPublishingContext", BindingFlags.Instance | BindingFlags.NonPublic, null, CallingConventions.Any,
                                                                new Type[] { typeof(PublishingContext) }, null);

            setPublishingContext.Invoke(this, new[] { publishingContextInstance });

            // Using reflection to set the private field TemplatingRenderer._renderedItem too (otherwise you get an error that the Engine is not initialized):
            FieldInfo renderedItemField = GetType().BaseType.GetField("_renderedItem", BindingFlags.Instance | BindingFlags.NonPublic);

            renderedItemField?.SetValue(this, renderedItem);
        }
Beispiel #13
0
        /// <summary>
        /// Performs the Transform.
        /// </summary>
        public override void Transform(Engine engine, Package package)
        {
            Logger.Debug("Transform");

            Initialize(engine, package);

            bool includeComponentTemplateData;

            if (!package.TryGetParameter("includeComponentTemplateData", out includeComponentTemplateData, Logger))
            {
                includeComponentTemplateData = true; // Default
            }

            int expandLinkDepth;

            package.TryGetParameter("expandLinkDepth", out expandLinkDepth, Logger);

            string[] modelBuilderTypeNames = GetModelBuilderTypeNames();

            RenderedItem      renderedItem = Engine.PublishingContext.RenderedItem;
            Component         component    = GetComponent();
            ComponentTemplate ct           = GetComponentTemplate();

            try
            {
                DataModelBuilderSettings settings = new DataModelBuilderSettings
                {
                    ExpandLinkDepth     = expandLinkDepth,
                    GenerateXpmMetadata = IsXpmEnabled || IsPreview
                };

                DataModelBuilderPipeline modelBuilderPipeline = new DataModelBuilderPipeline(renderedItem, settings, modelBuilderTypeNames);
                EntityModelData          entityModel          = modelBuilderPipeline.CreateEntityModel(component, includeComponentTemplateData ? ct : null);

                string entityModelJson = JsonSerialize(entityModel, IsPreview, DataModelBinder.SerializerSettings);
                Item   outputItem      = Package.CreateStringItem(ContentType.Text, entityModelJson);
                Package.PushItem(Package.OutputName, outputItem);
            }
            catch (Exception ex)
            {
                throw new DxaException($"An error occurred while rendering {component.FormatIdentifier()} with {ct.FormatIdentifier()}", ex);
            }
        }
Beispiel #14
0
        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="renderedItem">A context <see cref="RenderedItem"/> instance which is used to add Binaries and child Rendered Items.</param>
        /// <param name="settings">The Model Builder Settings to use.</param>
        /// <param name="modelBuilderTypeNames">The (qualified) type names of Model Builders to use.</param>
        /// <param name="logger">Optional logger to use. If not specified or <c>null</c>, the Data Model Builder Pipeline creates its own logger.</param>
        public DataModelBuilderPipeline(
            RenderedItem renderedItem,
            DataModelBuilderSettings settings,
            IEnumerable <string> modelBuilderTypeNames,
            ILogger logger = null
            )
        {
            Session      = renderedItem.ResolvedItem.Item.Session;
            RenderedItem = renderedItem;
            Settings     = settings;
            Logger       = logger ?? new TemplatingLoggerAdapter(TemplatingLogger.GetLogger(GetType()));

            foreach (string modelBuilderTypeName in modelBuilderTypeNames)
            {
                string qualifiedTypeName = modelBuilderTypeName.Contains(".") ? modelBuilderTypeName : $"Sdl.Web.Tridion.Data.{modelBuilderTypeName}";
                Type   modelBuilderType  = Type.GetType(qualifiedTypeName, throwOnError: true);
                object modelBuilder      = Activator.CreateInstance(modelBuilderType, new object[] { this });
                IPageModelDataBuilder    pageModelBuilder    = modelBuilder as IPageModelDataBuilder;
                IEntityModelDataBuilder  entityModelBuilder  = modelBuilder as IEntityModelDataBuilder;
                IKeywordModelDataBuilder keywordModelBuilder = modelBuilder as IKeywordModelDataBuilder;
                if ((pageModelBuilder == null) && (entityModelBuilder == null) && (keywordModelBuilder == null))
                {
                    Logger.Warning($"Configured Model Builder type '{modelBuilderType.FullName}' does not implement IPageModelDataBuilder, IEntityModelDataBuilder nor IKeywordModelDataBuilder; skipping.");
                    continue;
                }
                if (pageModelBuilder != null)
                {
                    Logger.Debug($"Using Page Model Builder type '{modelBuilderType.FullName}'.");
                    _pageModelBuilders.Add(pageModelBuilder);
                }
                if (entityModelBuilder != null)
                {
                    Logger.Debug($"Using Entity Model Builder type '{modelBuilderType.FullName}'.");
                    _entityModelBuilders.Add(entityModelBuilder);
                }
                if (keywordModelBuilder != null)
                {
                    Logger.Debug($"Using Keyword Model Builder type '{modelBuilderType.FullName}'.");
                    _keywordModelBuilders.Add(keywordModelBuilder);
                }
            }
        }
        public void DataPresentationTemplate_NotFound_Success()
        {
            Page dummyPage = (Page)TestSession.GetObject(TestFixture.AutoTestChildHomePageWebDavUrl);

            RenderedItem renderedItem = CreateTestRenderedItem(dummyPage, dummyPage.PageTemplate);
            TestLogger   testLogger   = new TestLogger();

            DataModelBuilderPipeline testModelBuilderPipeline = new DataModelBuilderPipeline(
                renderedItem,
                _defaultModelBuilderSettings,
                _defaultModelBuilderTypeNames,
                testLogger
                );

            ComponentTemplate dataPresentationTemplate = testModelBuilderPipeline.DataPresentationTemplate;

            Assert.IsNull(dataPresentationTemplate, "dataPresentationTemplate");
            Assert.IsTrue(
                testLogger.LoggedMessages.Contains(new LogMessage(LogLevel.Warning, "Component Template 'Generate Data Presentation' not found.")),
                "Expected Log message not found."
                );
        }
        private PageModelData CreatePageModel(Page page, out RenderedItem renderedItem, IEnumerable <string> modelBuilderTypeNames = null)
        {
            renderedItem = CreateTestRenderedItem(page, page.PageTemplate);

            if (modelBuilderTypeNames == null)
            {
                modelBuilderTypeNames = _defaultModelBuilderTypeNames;
            }

            DataModelBuilderPipeline testModelBuilderPipeline = new DataModelBuilderPipeline(
                renderedItem,
                _defaultModelBuilderSettings,
                modelBuilderTypeNames,
                new TestLogger()
                );

            PageModelData result = testModelBuilderPipeline.CreatePageModel(page);

            Assert.IsNotNull(result);
            OutputJson(result, DataModelBinder.SerializerSettings);

            return(result);
        }
 /// <summary>
 /// Sets the rendered item as the internal _renderedItem variable of the Engine
 /// </summary>
 /// <param name="renderedItem">The RenderedItem to configure the engine with</param>
 private void SetRenderedItem(RenderedItem renderedItem)
 {
     typeof(TemplatingRenderer).GetField("_renderedItem", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(this, renderedItem);
 }
Beispiel #18
0
        protected Package RunTemplate(Type templateType, IdentifiableObject inputItem, out RenderedItem renderedItem, Template template = null)
        {
            renderedItem = CreateTestRenderedItem(inputItem, template);
            TestEngine testEngine  = new TestEngine(renderedItem);
            Package    testPackage = new Package(testEngine);

            Type        inputItemType        = inputItem.GetType();
            string      inputItemName        = inputItemType.Name;
            ContentType inputItemContentType = new ContentType($"tridion/{inputItemType.Name.ToLower()}");

            testPackage.PushItem(inputItemName, testPackage.CreateTridionItem(inputItemContentType, inputItem));

            ITemplate testTemplate = Activator.CreateInstance(templateType) as ITemplate;

            Assert.IsNotNull(testTemplate, "testTemplate");

            testTemplate.Transform(testEngine, testPackage);

            return(testPackage);
        }
Beispiel #19
0
        /// <summary>
        /// Execute the template transformation with the given parameters
        /// </summary>
        /// <param name="itemUri">Tridion item URI.</param>
        /// <param name="templateUri">Tridion template URI.</param>
        /// <param name="publicationTargetUri">Tridion publication target URI.</param>
        /// <returns>Package "Output" item as <see cref="T:System.String" /></returns>
        /// <exception cref="System.ArgumentNullException">
        /// itemUri cannot be null or empty.
        /// or
        /// templateUri cannot be null or empty for itemtype
        /// </exception>
        /// <exception cref="System.ArgumentException">
        /// itemUri is not a valid Tridion URI.
        /// or
        /// templateUri is not a valid Tridion URI.
        /// </exception>
        public override String Execute(String itemUri, String templateUri = null, String publicationTargetUri = null)
        {
            Session session = null;

            try
            {
                session = DebuggerConfig.Instance.Templating.EnableImpersonation && !String.IsNullOrEmpty(DebuggerConfig.Instance.Templating.ImpersonationIdentity) ?
                          new Session(DebuggerConfig.Instance.Templating.ImpersonationIdentity) : new Session();

                IdentifiableObject item = session.GetObject(itemUri);

                Template template = null;

                if (String.IsNullOrEmpty(templateUri))
                {
                    Page page = item as Page;

                    if (page != null)
                    {
                        template = page.PageTemplate;
                    }
                }
                else
                {
                    template = session.GetObject(templateUri) as Template;
                }

                if (template != null)
                {
                    ResolvedItem resolvedItem = new ResolvedItem(item, template);

                    PublishInstruction instruction = new PublishInstruction(session)
                    {
                        RenderInstruction = new RenderInstruction(session)
                        {
                            RenderMode = RenderMode.PreviewDynamic
                        },
                        ResolveInstruction = new ResolveInstruction(session)
                        {
                            IncludeChildPublications = false,
                            IncludeComponentLinks    = true,
                            IncludeWorkflow          = false,
                            OnlyPublishedItems       = false,
                            Purpose = ResolvePurpose.Publish,
                            StructureResolveOption = StructureResolveOption.ItemsAndStructure
                        }
                    };

                    DebuggerHook();

                    RenderedItem renderedItem = global::Tridion.ContentManager.Publishing.Rendering.RenderEngine.Render(resolvedItem,
                                                                                                                        instruction,
                                                                                                                        !String.IsNullOrEmpty(publicationTargetUri) ? new PublicationTarget(new TcmUri(publicationTargetUri), session) : null);

                    using (StreamReader sr = new StreamReader(renderedItem.Content))
                    {
                        renderedItem.Content.Seek(0, SeekOrigin.Begin);
                        return(sr.ReadToEnd());
                    }
                }
            }
            catch (Exception ex)
            {
                Logger.Log(TraceEventType.Error, "Exception while executing TemplateEngine for item {0}, template {1}: {2}", itemUri, templateUri, ex.Message);
            }
            finally
            {
                if (session != null)
                {
                    session.Dispose();
                }
            }

            return(String.Empty);
        }
        private EntityModelData CreateEntityModel(Component component, ComponentTemplate ct, out RenderedItem renderedItem, IEnumerable <string> modelBuilderTypeNames = null)
        {
            renderedItem = CreateTestRenderedItem(component, ct);

            if (modelBuilderTypeNames == null)
            {
                modelBuilderTypeNames = _defaultModelBuilderTypeNames;
            }

            DataModelBuilderPipeline testModelBuilderPipeline = new DataModelBuilderPipeline(
                renderedItem,
                _defaultModelBuilderSettings,
                modelBuilderTypeNames,
                new TestLogger()
                );

            EntityModelData result = testModelBuilderPipeline.CreateEntityModel(component, ct);

            Assert.IsNotNull(result);
            OutputJson(result, DataModelBinder.SerializerSettings);

            return(result);
        }
Beispiel #21
0
 public void AddRenderedItem(RenderedItem file)
 {
     renderedItems.Add(file);
 }
Beispiel #22
0
 public ComponentImage(Component component, RenderedItem renderedItem, bool forceDownloadExternal = false)
     : base(component, renderedItem, forceDownloadExternal)
 {
     this.InitializeImage();
 }
        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));
        }