mirror of
https://github.com/samsonjs/samhuri.net.git
synced 2026-04-27 14:57:40 +00:00
Make the site generator render index.html with a layout
This commit is contained in:
parent
57bdf5d14a
commit
ea2b53d625
21 changed files with 247 additions and 18 deletions
6
Makefile
6
Makefile
|
|
@ -12,4 +12,8 @@ publish_beta: compile
|
||||||
@echo
|
@echo
|
||||||
./bin/publish --beta --delete
|
./bin/publish --beta --delete
|
||||||
|
|
||||||
.PHONY: compile publish publish_beta
|
test:
|
||||||
|
@echo
|
||||||
|
./bin/test
|
||||||
|
|
||||||
|
.PHONY: compile publish publish_beta test
|
||||||
|
|
|
||||||
|
|
@ -19,9 +19,9 @@ Execution, trying TDD for the first time:
|
||||||
|
|
||||||
- [x] Write a test harness that renders a site and then checks the output with `diff -r`
|
- [x] Write a test harness that renders a site and then checks the output with `diff -r`
|
||||||
|
|
||||||
- [ ] Port _layout.ejs to Swift code
|
- [x] Write a site generator that renders www/index.html from site.json
|
||||||
|
|
||||||
- [ ] Write a site generator that renders www/index.html from site.json
|
- [ ] Port _layout.ejs to Swift code
|
||||||
|
|
||||||
- [ ] Add support for CSS files
|
- [ ] Add support for CSS files
|
||||||
|
|
||||||
|
|
|
||||||
5
SiteGenerator/.gitignore
vendored
Normal file
5
SiteGenerator/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
.DS_Store
|
||||||
|
/.build
|
||||||
|
/Packages
|
||||||
|
/*.xcodeproj
|
||||||
|
/.swiftpm
|
||||||
34
SiteGenerator/Package.resolved
Normal file
34
SiteGenerator/Package.resolved
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
{
|
||||||
|
"object": {
|
||||||
|
"pins": [
|
||||||
|
{
|
||||||
|
"package": "PathKit",
|
||||||
|
"repositoryURL": "https://github.com/kylef/PathKit.git",
|
||||||
|
"state": {
|
||||||
|
"branch": null,
|
||||||
|
"revision": "e2f5be30e4c8f531c9c1e8765aa7b71c0a45d7a0",
|
||||||
|
"version": "0.9.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"package": "Spectre",
|
||||||
|
"repositoryURL": "https://github.com/kylef/Spectre.git",
|
||||||
|
"state": {
|
||||||
|
"branch": null,
|
||||||
|
"revision": "f14ff47f45642aa5703900980b014c2e9394b6e5",
|
||||||
|
"version": "0.9.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"package": "Stencil",
|
||||||
|
"repositoryURL": "https://github.com/stencilproject/Stencil.git",
|
||||||
|
"state": {
|
||||||
|
"branch": null,
|
||||||
|
"revision": "0e9a78d6584e3812cd9c09494d5c7b483e8f533c",
|
||||||
|
"version": "0.13.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"version": 1
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
// swift-tools-version:5.0
|
||||||
|
// The swift-tools-version declares the minimum version of Swift required to build this package.
|
||||||
|
|
||||||
|
import PackageDescription
|
||||||
|
|
||||||
|
let package = Package(
|
||||||
|
name: "SiteGenerator",
|
||||||
|
dependencies: [
|
||||||
|
.package(url: "https://github.com/stencilproject/Stencil.git", from: "0.13.0")
|
||||||
|
],
|
||||||
|
targets: [
|
||||||
|
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
|
||||||
|
// Targets can depend on other targets in this package, and on products in packages which this package depends on.
|
||||||
|
.target(
|
||||||
|
name: "SiteGenerator",
|
||||||
|
dependencies: ["Stencil"]),
|
||||||
|
.testTarget(
|
||||||
|
name: "SiteGeneratorTests",
|
||||||
|
dependencies: ["SiteGenerator"]),
|
||||||
|
]
|
||||||
|
)
|
||||||
5
SiteGenerator/Readme.md
Normal file
5
SiteGenerator/Readme.md
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
# SiteGenerator
|
||||||
|
|
||||||
|
A static site generator for [samhuri.net](https://samhuri.net).
|
||||||
|
|
||||||
|
See https://github.com/samsonjs/samhuri.net for details.
|
||||||
34
SiteGenerator/Sources/SiteGenerator/Generator.swift
Normal file
34
SiteGenerator/Sources/SiteGenerator/Generator.swift
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
//
|
||||||
|
// Generator.swift
|
||||||
|
// SiteGenerator
|
||||||
|
//
|
||||||
|
// Created by Sami Samhuri on 2019-12-01.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import PathKit
|
||||||
|
import Stencil
|
||||||
|
|
||||||
|
public final class Generator {
|
||||||
|
private let fileManager: FileManager = .default
|
||||||
|
|
||||||
|
public let site: Site
|
||||||
|
public let sourceURL: URL
|
||||||
|
|
||||||
|
private let renderer: Environment
|
||||||
|
|
||||||
|
public init(sourceURL: URL) throws {
|
||||||
|
let publicURL = sourceURL.appendingPathComponent("public")
|
||||||
|
self.renderer = Environment(loader: FileSystemLoader(paths: [Path(publicURL.path)]))
|
||||||
|
let siteURL = sourceURL.appendingPathComponent("site.json")
|
||||||
|
self.site = try Site.decode(from: siteURL)
|
||||||
|
self.sourceURL = sourceURL
|
||||||
|
}
|
||||||
|
|
||||||
|
public func generate(targetURL: URL) throws {
|
||||||
|
try fileManager.createDirectory(at: targetURL, withIntermediateDirectories: true, attributes: nil)
|
||||||
|
let indexHTML = try renderer.renderTemplate(name: "index.html", context: ["site": site])
|
||||||
|
let indexURL = targetURL.appendingPathComponent("index.html")
|
||||||
|
try indexHTML.write(to: indexURL, atomically: true, encoding: .utf8)
|
||||||
|
}
|
||||||
|
}
|
||||||
22
SiteGenerator/Sources/SiteGenerator/Site.swift
Normal file
22
SiteGenerator/Sources/SiteGenerator/Site.swift
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
//
|
||||||
|
// Site.swift
|
||||||
|
// SiteGenerator
|
||||||
|
//
|
||||||
|
// Created by Sami Samhuri on 2019-12-01.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
public struct Site: Codable {
|
||||||
|
public let author: String
|
||||||
|
public let email: String
|
||||||
|
public let title: String
|
||||||
|
public let url: String
|
||||||
|
}
|
||||||
|
|
||||||
|
public extension Site {
|
||||||
|
static func decode(from url: URL) throws -> Site {
|
||||||
|
let json = try Data(contentsOf: url)
|
||||||
|
return try JSONDecoder().decode(Site.self, from: json)
|
||||||
|
}
|
||||||
|
}
|
||||||
22
SiteGenerator/Sources/SiteGenerator/main.swift
Normal file
22
SiteGenerator/Sources/SiteGenerator/main.swift
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
//
|
||||||
|
// main.swift
|
||||||
|
// SiteGenerator
|
||||||
|
//
|
||||||
|
// Created by Sami Samhuri on 2019-12-01.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
func main(sourcePath: String, targetPath: String) throws {
|
||||||
|
let sourceURL = URL(fileURLWithPath: sourcePath)
|
||||||
|
let targetURL = URL(fileURLWithPath: targetPath)
|
||||||
|
let generator = try Generator(sourceURL: sourceURL)
|
||||||
|
try generator.generate(targetURL: targetURL)
|
||||||
|
}
|
||||||
|
|
||||||
|
let sourcePath = CommandLine.arguments[1]
|
||||||
|
let targetPath = CommandLine.arguments[2]
|
||||||
|
|
||||||
|
// TODO: validate args
|
||||||
|
|
||||||
|
try! main(sourcePath: sourcePath, targetPath: targetPath)
|
||||||
7
SiteGenerator/Tests/LinuxMain.swift
Normal file
7
SiteGenerator/Tests/LinuxMain.swift
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
import XCTest
|
||||||
|
|
||||||
|
import SiteGeneratorTests
|
||||||
|
|
||||||
|
var tests = [XCTestCaseEntry]()
|
||||||
|
tests += SiteGeneratorTests.allTests()
|
||||||
|
XCTMain(tests)
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
import XCTest
|
||||||
|
import class Foundation.Bundle
|
||||||
|
|
||||||
|
final class SiteGeneratorTests: XCTestCase {
|
||||||
|
func testExample() throws {
|
||||||
|
// This is an example of a functional test case.
|
||||||
|
// Use XCTAssert and related functions to verify your tests produce the correct
|
||||||
|
// results.
|
||||||
|
|
||||||
|
// Some of the APIs that we use below are available in macOS 10.13 and above.
|
||||||
|
guard #available(macOS 10.13, *) else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let fooBinary = productsDirectory.appendingPathComponent("SiteGenerator")
|
||||||
|
|
||||||
|
let process = Process()
|
||||||
|
process.executableURL = fooBinary
|
||||||
|
|
||||||
|
let pipe = Pipe()
|
||||||
|
process.standardOutput = pipe
|
||||||
|
|
||||||
|
try process.run()
|
||||||
|
process.waitUntilExit()
|
||||||
|
|
||||||
|
let data = pipe.fileHandleForReading.readDataToEndOfFile()
|
||||||
|
let output = String(data: data, encoding: .utf8)
|
||||||
|
|
||||||
|
XCTAssertEqual(output, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns path to the built products directory.
|
||||||
|
var productsDirectory: URL {
|
||||||
|
#if os(macOS)
|
||||||
|
for bundle in Bundle.allBundles where bundle.bundlePath.hasSuffix(".xctest") {
|
||||||
|
return bundle.bundleURL.deletingLastPathComponent()
|
||||||
|
}
|
||||||
|
fatalError("couldn't find the products directory")
|
||||||
|
#else
|
||||||
|
return Bundle.main.bundleURL
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static var allTests = [
|
||||||
|
("testExample", testExample),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
import XCTest
|
||||||
|
|
||||||
|
#if !canImport(ObjectiveC)
|
||||||
|
public func allTests() -> [XCTestCaseEntry] {
|
||||||
|
return [
|
||||||
|
testCase(SiteGeneratorTests.allTests),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
@ -8,9 +8,8 @@ SOURCE_DIR="$1"
|
||||||
TARGET_DIR="$2"
|
TARGET_DIR="$2"
|
||||||
|
|
||||||
function main() {
|
function main() {
|
||||||
echo "* copy files from $SOURCE_DIR to $TARGET_DIR"
|
echo "* generate site from $SOURCE_DIR into $TARGET_DIR"
|
||||||
mkdir -p "$TARGET_DIR"
|
"$THIS_DIR/sitegen" "$SOURCE_DIR" "$TARGET_DIR"
|
||||||
cp -rp "$SOURCE_DIR"/* "$TARGET_DIR"
|
|
||||||
|
|
||||||
# echo "* compile rss feed"
|
# echo "* compile rss feed"
|
||||||
# compile_feeds
|
# compile_feeds
|
||||||
|
|
|
||||||
BIN
bin/sitegen
Executable file
BIN
bin/sitegen
Executable file
Binary file not shown.
9
bin/test
9
bin/test
|
|
@ -2,8 +2,13 @@
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
|
pushd "SiteGenerator" >/dev/null
|
||||||
|
swift build
|
||||||
|
cp .build/x86_64-apple-macosx/debug/SiteGenerator ../bin/sitegen
|
||||||
|
popd >/dev/null
|
||||||
|
|
||||||
for site in Tests/test-*; do
|
for site in Tests/test-*; do
|
||||||
bin/compile "$site/in" "$site/actual" >/dev/null
|
bin/compile "$site/in" "$site/actual" # >/dev/null
|
||||||
diff -r "$site/expected" "$site/actual"
|
diff -ru "$site/expected" "$site/actual"
|
||||||
rm -r "$site/actual"
|
rm -r "$site/actual"
|
||||||
done
|
done
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,12 @@
|
||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html>
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Valar Morghulis</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1><a href="http://example.net">Valar Morghulis</a></h1>
|
||||||
|
|
||||||
|
<p>hello world</p>
|
||||||
|
|
||||||
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
{
|
|
||||||
"title": "Valar Morghulis",
|
|
||||||
"author": "A man has no name",
|
|
||||||
"email": "jaqen@hotmail.com",
|
|
||||||
"url": "http://example.net"
|
|
||||||
}
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
<!doctype html>
|
|
||||||
<html>
|
|
||||||
</html>
|
|
||||||
4
tests/test-index/in/public/index.html
Normal file
4
tests/test-index/in/public/index.html
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
{% extends "layout.html" %}
|
||||||
|
{% block content %}
|
||||||
|
<p>hello world</p>
|
||||||
|
{% endblock %}
|
||||||
11
tests/test-index/in/public/layout.html
Normal file
11
tests/test-index/in/public/layout.html
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>{{ site.title }}</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1><a href="{{ site.url }}">{{ site.title }}</a></h1>
|
||||||
|
{% block content %}
|
||||||
|
{% endblock %}
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"title": "Valar Morghulis",
|
|
||||||
"author": "A man has no name",
|
"author": "A man has no name",
|
||||||
"email": "jaqen@hotmail.com",
|
"email": "jaqen@hotmail.com",
|
||||||
|
"title": "Valar Morghulis",
|
||||||
"url": "http://example.net"
|
"url": "http://example.net"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue