Copy required files for pages

This commit is contained in:
Christoph Hagen 2022-08-16 12:26:45 +02:00
parent 14b935249f
commit 02a3dd4007
13 changed files with 85 additions and 46 deletions

View File

@ -23,7 +23,7 @@
E22E878C289E4A8900E51191 /* Ink in Frameworks */ = {isa = PBXBuildFile; productRef = E22E878B289E4A8900E51191 /* Ink */; };
E22E8793289E7EC700E51191 /* Page+LocalizedMetadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = E22E8792289E7EC700E51191 /* Page+LocalizedMetadata.swift */; };
E22E8795289E81D700E51191 /* FileSystem.swift in Sources */ = {isa = PBXBuildFile; fileRef = E22E8794289E81D700E51191 /* FileSystem.swift */; };
E22E8798289EA42C00E51191 /* ImageProcessor.swift in Sources */ = {isa = PBXBuildFile; fileRef = E22E8797289EA42C00E51191 /* ImageProcessor.swift */; };
E22E8798289EA42C00E51191 /* FileProcessor.swift in Sources */ = {isa = PBXBuildFile; fileRef = E22E8797289EA42C00E51191 /* FileProcessor.swift */; };
E22E879B289EE02F00E51191 /* Optional+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E22E879A289EE02F00E51191 /* Optional+Extensions.swift */; };
E22E879E289EFDFC00E51191 /* OverviewPageGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = E22E879D289EFDFC00E51191 /* OverviewPageGenerator.swift */; };
E22E87A0289F008200E51191 /* ThumbnailListGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = E22E879F289F008200E51191 /* ThumbnailListGenerator.swift */; };
@ -82,7 +82,7 @@
E22E8788289DDF5700E51191 /* Page+Metadata.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Page+Metadata.swift"; sourceTree = "<group>"; };
E22E8792289E7EC700E51191 /* Page+LocalizedMetadata.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Page+LocalizedMetadata.swift"; sourceTree = "<group>"; };
E22E8794289E81D700E51191 /* FileSystem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileSystem.swift; sourceTree = "<group>"; };
E22E8797289EA42C00E51191 /* ImageProcessor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageProcessor.swift; sourceTree = "<group>"; };
E22E8797289EA42C00E51191 /* FileProcessor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileProcessor.swift; sourceTree = "<group>"; };
E22E879A289EE02F00E51191 /* Optional+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Optional+Extensions.swift"; sourceTree = "<group>"; };
E22E879D289EFDFC00E51191 /* OverviewPageGenerator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OverviewPageGenerator.swift; sourceTree = "<group>"; };
E22E879F289F008200E51191 /* ThumbnailListGenerator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThumbnailListGenerator.swift; sourceTree = "<group>"; };
@ -149,7 +149,7 @@
E2C5A5D328A0222B00102A25 /* Templates */,
E22E8799289EE02300E51191 /* Extensions */,
E22E876B289D855D00E51191 /* ThumbnailStyle.swift */,
E22E8797289EA42C00E51191 /* ImageProcessor.swift */,
E22E8797289EA42C00E51191 /* FileProcessor.swift */,
E22E8777289DA0E100E51191 /* GenerationError.swift */,
E22E8794289E81D700E51191 /* FileSystem.swift */,
);
@ -315,7 +315,7 @@
E22E876E289D868100E51191 /* Site+LocalizedMetadata.swift in Sources */,
E2C5A5D528A0223C00102A25 /* OverviewPageTemplate.swift in Sources */,
E22E876C289D855D00E51191 /* ThumbnailStyle.swift in Sources */,
E22E8798289EA42C00E51191 /* ImageProcessor.swift in Sources */,
E22E8798289EA42C00E51191 /* FileProcessor.swift in Sources */,
E26555E428A2C4FA00BAF496 /* LinkPreviewMetadataProvider.swift in Sources */,
E22E87AA289F1AEE00E51191 /* PageHeadGenerator.swift in Sources */,
E2D55EDB28A2511D00B9453E /* OverviewSectionCleanTemplate.swift in Sources */,

View File

@ -3,7 +3,7 @@ import Foundation
import AppKit
#endif
final class ImageProcessor {
final class FileProcessor {
struct ImageOutput: Hashable {
@ -32,12 +32,44 @@ final class ImageProcessor {
let outputFolder: URL
/**
The files required by the site.
The content are the links to the files relative to the source root folder.
The files will be placed at the same path relative to the output folder
*/
private var requiredFiles: Set<String> = []
private var tasks: [String : ImageOutput] = [:]
init(inputFolder: URL, outputFolder: URL) {
self.inputFolder = inputFolder
self.outputFolder = outputFolder
}
private var tasks: [String : ImageOutput] = [:]
// MARK: Files
/**
Add a file as required, so that it will be copied to the output directory.
*/
func require(file: String) {
requiredFiles.insert(file)
}
func copyRequiredFiles() throws {
var missingFiles = [String]()
for file in requiredFiles {
let sourceUrl = inputFolder.appendingPathComponent(file)
guard sourceUrl.exists else {
missingFiles.append(file)
continue
}
let destinationUrl = outputFolder.appendingPathComponent(file)
try FileSystem.copy(sourceUrl, to: destinationUrl)
}
}
// MARK: Images
@discardableResult
func requireImage(source: String, destination: String, width: Int, desiredHeight: Int? = nil, createDoubleVersion: Bool = false) throws -> NSSize {

View File

@ -9,6 +9,9 @@ enum FileSystem {
.filter { $0.isDirectory }
}
/**
Copy a file to the destination, creating the containing folder if needed
*/
static func copy(_ source: URL, to destination: URL) throws {
try destination.ensureParentFolderExistence()
try source.copy(to: destination)

View File

@ -20,7 +20,7 @@ struct IndexPageGenerator {
private let factory: LocalizedSiteTemplate
init(factory: LocalizedSiteTemplate, imageProcessor: ImageProcessor) {
init(factory: LocalizedSiteTemplate) {
self.factory = factory
}

View File

@ -3,10 +3,10 @@ import Ink
struct PageContentGenerator {
private let imageProcessor: ImageProcessor
private let files: FileProcessor
init(imageProcessor: ImageProcessor) {
self.imageProcessor = imageProcessor
init(files: FileProcessor) {
self.files = files
}
func generate(page: Page, language: String, at url: URL) throws -> String {
@ -71,7 +71,7 @@ struct PageContentGenerator {
let size: NSSize
let imagePath = page.pathRelativeToRootForContainedInputFile(file)
do {
size = try imageProcessor.requireImage(
size = try files.requireImage(
source: imagePath,
destination: imagePath,
width: pageImageWidth,

View File

@ -6,9 +6,9 @@ struct OverviewPageGenerator {
let outputFolder: URL
init(factory: LocalizedSiteTemplate, imageProcessor: ImageProcessor) {
init(factory: LocalizedSiteTemplate, files: FileProcessor) {
self.factory = factory
self.outputFolder = imageProcessor.outputFolder
self.outputFolder = files.outputFolder
}
func generate(

View File

@ -6,15 +6,15 @@ struct OverviewSectionGenerator {
private let singleSectionsTemplate: OverviewSectionCleanTemplate
let imageProcessor: ImageProcessor
let files: FileProcessor
private let generator: ThumbnailListGenerator
init(factory: TemplateFactory, imageProcessor: ImageProcessor) {
init(factory: TemplateFactory, files: FileProcessor) {
self.multipleSectionsTemplate = factory.overviewSection
self.singleSectionsTemplate = factory.overviewSectionClean
self.imageProcessor = imageProcessor
self.generator = ThumbnailListGenerator(factory: factory, imageProcessor: imageProcessor)
self.files = files
self.generator = ThumbnailListGenerator(factory: factory, files: files)
}
func generate(sections: [Section], in parent: SiteElement, language: String, sectionItemCount: Int) throws -> String {

View File

@ -12,11 +12,11 @@ struct PageGenerator {
private let factory: LocalizedSiteTemplate
private let imageProcessor: ImageProcessor
private let files: FileProcessor
init(factory: LocalizedSiteTemplate, imageProcessor: ImageProcessor) {
init(factory: LocalizedSiteTemplate, files: FileProcessor) {
self.factory = factory
self.imageProcessor = imageProcessor
self.files = files
}
func generate(page: Page, language: String, backText: String, nextPage: NavigationLink?, previousPage: NavigationLink?) throws {
@ -45,8 +45,8 @@ struct PageGenerator {
content[.nextPageUrl] = nextPage?.link
content[.footer] = try page.customFooterContent()
let url = imageProcessor.outputFolder.appendingPathComponent(path)
try factory.contentPage.generate(content, to: url)
let url = files.outputFolder.appendingPathComponent(path)
}
private func makeContent(page: Page, language: String, url: URL) throws -> String {
@ -55,7 +55,7 @@ struct PageGenerator {
return factory.placeholder
}
print("Generated page \(page.path)")
return try PageContentGenerator(imageProcessor: imageProcessor).generate(page: page, language: language, at: url)
return try PageContentGenerator(files: files).generate(page: page, language: language, at: url)
}
private func makeHead(page: Page, language: String) throws -> String {

View File

@ -30,11 +30,11 @@ struct PageHeadGenerator {
let template: PageHeadTemplate
let imageProcessor: ImageProcessor
let files: FileProcessor
init(factory: TemplateFactory, imageProcessor: ImageProcessor) {
init(factory: TemplateFactory, files: FileProcessor) {
self.template = factory.pageHead
self.imageProcessor = imageProcessor
self.files = files
}
func generate(page: PageHeadInfoProvider) throws -> String {
@ -47,7 +47,7 @@ struct PageHeadGenerator {
// since we don't want a single large image for thumbnails.
// Warning: Link preview source path must be relative to root
let linkPreviewImagePath = image.insert("-link", beforeLast: ".")
try imageProcessor.requireImage(
try files.requireImage(
source: image,
destination: linkPreviewImagePath,
width: Site.linkPreviewDesiredImageWidth)

View File

@ -6,17 +6,17 @@ struct SiteGenerator {
let templates: TemplateFactory
private let imageProcessor: ImageProcessor
private let files: FileProcessor
private var outputFolder: URL {
imageProcessor.outputFolder
files.outputFolder
}
init(site: Site, imageProcessor: ImageProcessor) throws {
init(site: Site, files: FileProcessor) throws {
self.site = site
let templatesFolder = site.inputFolder.appendingPathComponent("templates")
self.templates = try TemplateFactory(templateFolder: templatesFolder)
self.imageProcessor = imageProcessor
self.files = files
}
func generate() throws {
@ -26,12 +26,12 @@ struct SiteGenerator {
factory: templates,
language: language,
site: site,
imageProcessor: imageProcessor)
files: files)
// Generate sections
let overviewGenerator = OverviewPageGenerator(factory: template, imageProcessor: imageProcessor)
let pageGenerator = PageGenerator(factory: template, imageProcessor: imageProcessor)
let overviewGenerator = OverviewPageGenerator(factory: template, files: files)
let pageGenerator = PageGenerator(factory: template, files: files)
let backLinkText = try site.backLinkText(for: language)
var elementsToProcess: [(element: SiteElement, backText: String?)] = site.elements.map { ($0, backLinkText) }
while let (element, backText) = elementsToProcess.popLast() {
@ -52,12 +52,14 @@ struct SiteGenerator {
backText: backText ?? metadata.defaultBackLinkText,
nextPage: nil,
previousPage: nil)
for file in page.metadata.requiredFiles {
let relativePath = page.path + "/" + file
files.require(file: relativePath)
}
}
}
let generator = IndexPageGenerator(
factory: template,
imageProcessor: imageProcessor)
let generator = IndexPageGenerator(factory: template)
// Generate front page
let relativeUrl = site.localizedPath(for: language)

View File

@ -4,11 +4,11 @@ struct ThumbnailListGenerator {
private let factory: TemplateFactory
let imageProcessor: ImageProcessor
let files: FileProcessor
init(factory: TemplateFactory, imageProcessor: ImageProcessor) {
init(factory: TemplateFactory, files: FileProcessor) {
self.factory = factory
self.imageProcessor = imageProcessor
self.files = files
}
func generateContent(items: [ThumbnailInfo], style: ThumbnailStyle) throws -> String {
@ -26,7 +26,7 @@ struct ThumbnailListGenerator {
factory.largeThumbnail.makeCorner(text: $0)
}
try imageProcessor.requireImage(
try files.requireImage(
source: thumbnail.imageFilePath,
destination: thumbnail.imageFilePath,
width: style.width,

View File

@ -54,7 +54,7 @@ struct LocalizedSiteTemplate {
factory.contentPage
}
init(factory: TemplateFactory, language: String, site: Site, imageProcessor: ImageProcessor) throws {
init(factory: TemplateFactory, language: String, site: Site, files: FileProcessor) throws {
self.author = site.metadata.author
self.factory = factory
@ -92,10 +92,10 @@ struct LocalizedSiteTemplate {
topBarWebsiteTitle: title)
self.pageHead = PageHeadGenerator(
factory: factory,
imageProcessor: imageProcessor)
files: files)
self.overviewSection = OverviewSectionGenerator(
factory: factory,
imageProcessor: imageProcessor)
files: files)
self.placeholder = factory.placeholder.generate([
.title: metadata.placeholderTitle,

View File

@ -2,7 +2,7 @@ import Foundation
let contentDirectory = URL(fileURLWithPath: "/Users/ch/Projects/MakerSpace")
let outputDirectory = URL(fileURLWithPath: "/Users/ch/Projects/MakerSpace/Site")
let imageProcessor = ImageProcessor(
let files = FileProcessor(
inputFolder: contentDirectory, outputFolder: outputDirectory)
// 1: Load all site content
@ -10,11 +10,13 @@ guard let site = try Site(folder: contentDirectory) else {
exit(0)
}
// site.printContents()
let siteGenerator = try SiteGenerator(site: site, imageProcessor: imageProcessor)
let siteGenerator = try SiteGenerator(site: site, files: files)
try siteGenerator.generate()
print("Pages generated")
try imageProcessor.createImages()
try files.createImages()
print("Images generated")
try files.copyRequiredFiles()
print("Required files copied")
#warning("Check that all metadata for each language is present")