Skip to content

Commit

Permalink
Integration with the SwiftLogging API (#18)
Browse files Browse the repository at this point in the history
- logs provided via the logger object through the entire project
- proper info / debug / trace logs instead of prints
- introduces the `--log-level` option to the commands
- moved the filemanager extension to the proper place
  • Loading branch information
tib authored Oct 7, 2024
1 parent 231ac51 commit ada0fba
Show file tree
Hide file tree
Showing 13 changed files with 220 additions and 111 deletions.
1 change: 1 addition & 0 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ let package = Package(
name: "toucan-cli",
dependencies: [
.product(name: "ArgumentParser", package: "swift-argument-parser"),
.product(name: "Logging", package: "swift-log"),
.product(name: "Hummingbird", package: "hummingbird"),
.target(name: "ToucanSDK"),
] + tdeps
Expand Down
26 changes: 26 additions & 0 deletions Sources/ToucanSDK/Extensions/FileManager+Extensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,32 @@ import Foundation

extension FileManager {

func copyRecursively(
from inputURL: URL,
to outputURL: URL
) throws {
guard directoryExists(at: inputURL) else {
return
}
if !directoryExists(at: outputURL) {
try createDirectory(at: outputURL)
}

for item in listDirectory(at: inputURL) {
let itemSourceUrl = inputURL.appendingPathComponent(item)
let itemDestinationUrl = outputURL.appendingPathComponent(item)
if fileExists(at: itemSourceUrl) {
if fileExists(at: itemDestinationUrl) {
try delete(at: itemDestinationUrl)
}
try copy(from: itemSourceUrl, to: itemDestinationUrl)
}
else {
try copyRecursively(from: itemSourceUrl, to: itemDestinationUrl)
}
}
}

func createParentFolderIfNeeded(for url: URL) throws {
let folderPath =
"/"
Expand Down
36 changes: 18 additions & 18 deletions Sources/ToucanSDK/Site/SiteRenderer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -72,12 +72,14 @@ struct SiteRenderer {
source: Source,
templatesUrl: URL,
overridesUrl: URL,
destinationUrl: URL
destinationUrl: URL,
logger: Logger
) throws {
self.source = source
self.templatesUrl = templatesUrl
self.overridesUrl = overridesUrl
self.destinationUrl = destinationUrl
self.logger = logger

let calendar = Calendar(identifier: .gregorian)
self.currentYear = calendar.component(.year, from: .init())
Expand All @@ -87,12 +89,6 @@ struct SiteRenderer {
self.rssDateFormatter = DateFormatters.rss
self.sitemapDateFormatter = DateFormatters.sitemap

self.logger = {
var logger = Logger(label: "SiteRenderer")
logger.logLevel = .debug
return logger
}()

self.templateRenderer = try MustacheToHTMLRenderer(
templatesUrl: templatesUrl,
overridesUrl: overridesUrl
Expand Down Expand Up @@ -341,11 +337,11 @@ struct SiteRenderer {
// print(cmd)
let log = try shell.run(cmd)
if !log.isEmpty {
print(log)
logger.debug("\(log)")
}
}
catch {
print("\(error)")
logger.error("\(error.localizedDescription)")
}
}
contents = try! String(contentsOf: fileURL, encoding: .utf8)
Expand Down Expand Up @@ -379,10 +375,10 @@ struct SiteRenderer {

}
catch Exception.Error(_, let message) {
print(message)
logger.error("\(message)")
}
catch {
print("error")
logger.error("\(error.localizedDescription)")
}
}

Expand All @@ -406,8 +402,12 @@ struct SiteRenderer {
return res
}

logger.trace("slug: \(pageBundle.context.slug)")
logger.trace("type: \(pageBundle.type)")
let metadata: Logger.Metadata = [
"type": "\(pageBundle.type)",
"slug": "\(pageBundle.context.slug)",
]

logger.trace("Generating context", metadata: metadata)

let contentType = source.contentType(for: pageBundle)

Expand All @@ -419,20 +419,20 @@ struct SiteRenderer {

let relations = relations(for: pageBundle)

logger.trace("relations:")
logger.trace("relations:", metadata: metadata)
for (key, values) in relations {
logger.trace("\t\(key):")
for item in values {
logger.trace("\t - \(item.context.slug)")
logger.trace("\t - \(item.context.slug)", metadata: metadata)
}
}

let localContext = localContext(for: pageBundle)
logger.trace("local context:")
logger.trace("local context:", metadata: metadata)
for (key, values) in localContext {
logger.trace("\t\(key):")
logger.trace("\t\(key):", metadata: metadata)
for item in values {
logger.trace("\t - \(item.context.slug)")
logger.trace("\t - \(item.context.slug)", metadata: metadata)
}
}

Expand Down
14 changes: 10 additions & 4 deletions Sources/ToucanSDK/Source/ConfigLoader.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import Foundation
import FileManagerKit
import Yams
import Logging

private extension Config {

Expand Down Expand Up @@ -87,11 +88,11 @@ private extension Config.Content {
}
}

struct ConfigLoader {
public struct ConfigLoader {

/// An enumeration representing possible errors that can occur while loading the configuration.
enum Error: Swift.Error {
case missing
public enum Error: Swift.Error {
case missing(URL)
/// Indicates an error related to file operations.
case file(Swift.Error)
/// Indicates an error related to parsing YAML.
Expand All @@ -104,6 +105,8 @@ struct ConfigLoader {
let fileManager: FileManager
/// The base URL to use for the configuration.
let baseUrl: String?
/// The logger instance
let logger: Logger

/// Loads the configuration.
///
Expand All @@ -121,6 +124,9 @@ struct ConfigLoader {
continue
}
do {
logger.debug(
"Loading config file: `\(yamlConfigUrl.absoluteString)`."
)
let rawYaml = try String(
contentsOf: yamlConfigUrl,
encoding: .utf8
Expand All @@ -136,7 +142,7 @@ struct ConfigLoader {
throw Error.file(error)
}
}
throw Error.missing
throw Error.missing(sourceUrl)
}

func dictToConfig(
Expand Down
1 change: 1 addition & 0 deletions Sources/ToucanSDK/Source/PageBundle.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import Foundation

/// A page bundle representing a subpage for a website.
struct PageBundle {

struct Redirect {
Expand Down
84 changes: 52 additions & 32 deletions Sources/ToucanSDK/Source/PageBundleLoader.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,34 @@

import Foundation
import FileManagerKit
import Logging
import Yams

extension String {

func finalAssetUrl(
in path: String,
slug: String
) -> String {
let prefix = "./\(path)/"
guard hasPrefix(prefix) else {
return self
}
let path = String(dropFirst(prefix.count))
// TODO: not sure if this is the correct way of handling index assets
if slug.isEmpty {
return "/" + path
}
return "/assets/" + slug + "/" + path
}
}

struct PageBundleLocation {
let slug: String
let path: String
}

struct PageBundleLoader {
public struct PageBundleLoader {

public enum Keys: String, CaseIterable {
case draft
Expand All @@ -41,8 +61,8 @@ struct PageBundleLoader {
}

/// An enumeration representing possible errors that can occur while loading the content.
enum Error: Swift.Error {
case indexFileNotExists
public enum Error: Swift.Error {
// case indexFileNotExists
/// Indicates an error related to a content.
case pageBundle(Swift.Error)
}
Expand All @@ -58,6 +78,8 @@ struct PageBundleLoader {
/// The front matter parser used for parsing markdown files.
let frontMatterParser: FrontMatterParser

let logger: Logger

/// The current date.
let now: Date = .init()

Expand All @@ -76,12 +98,10 @@ struct PageBundleLoader {
}

/// Loads all the page bundles.
public func load() throws -> [PageBundle] {
func load() throws -> [PageBundle] {
try loadBundleLocations()
.sorted { $0.path < $1.path }
.compactMap {
return try? loadPageBundle(at: $0)
}
.compactMap { try loadPageBundle(at: $0) }
.sorted { $0.context.slug < $1.context.slug }
}

Expand Down Expand Up @@ -322,7 +342,20 @@ struct PageBundleLoader {
) throws -> PageBundle? {
let dirUrl = contentUrl.appendingPathComponent(location.path)

let metadata: Logger.Metadata = [
"slug": "\(location.slug)"
]

logger.debug(
"Loading page bundle at: `\(location.path)`",
metadata: metadata
)

guard fileManager.directoryExists(at: dirUrl) else {
logger.debug(
"Page bundle directory does not exists.",
metadata: metadata
)
return nil
}
do {
Expand All @@ -343,17 +376,26 @@ struct PageBundleLoader {

/// filter out drafts
if draft(frontMatter: frontMatter) {
logger.debug("Page bundle is a draft.", metadata: metadata)
return nil
}
/// filter out unpublished
let publication = publication(frontMatter: frontMatter)

if publication > now {
logger.debug(
"Page bundle is not published yet.",
metadata: metadata
)
return nil
}
/// filter out expired
let expiration = expiration(frontMatter: frontMatter)
if let expiration, expiration < now {
logger.debug(
"Page bundle is already expired.",
metadata: metadata
)
return nil
}

Expand All @@ -379,8 +421,7 @@ struct PageBundleLoader {

let contentType = contentTypes.first { $0.id == type }
guard let contentType else {
// TODO: fatal or log invalid content type
print("invalid content type")
logger.error("Invalid content type.", metadata: metadata)
return nil
}

Expand All @@ -403,10 +444,6 @@ struct PageBundleLoader {
let hreflang = hreflang(frontMatter: frontMatter)
let redirects = redirects(frontMatter: frontMatter)

// print("-------------------")
// print(assetsUrl.path())
// print(assets.joined(separator: "\n"))

/// resolve imageUrl for the page bundle
let assetsPrefix = "./\(assetsPath)/"
var imageUrl: String? = nil
Expand Down Expand Up @@ -458,6 +495,8 @@ struct PageBundleLoader {
js: js
)

logger.debug("Page bundle is loaded.", metadata: metadata)

return .init(
id: location.path,
url: dirUrl,
Expand All @@ -481,22 +520,3 @@ struct PageBundleLoader {
}
}
}

extension String {

func finalAssetUrl(
in path: String,
slug: String
) -> String {
let prefix = "./\(path)/"
guard hasPrefix(prefix) else {
return self
}
let path = String(dropFirst(prefix.count))
// TODO: not sure if this is the correct way of handling index assets
if slug.isEmpty {
return "/" + path
}
return "/assets/" + slug + "/" + path
}
}
Loading

0 comments on commit ada0fba

Please sign in to comment.